• 04 . Vue组件注册,组件间数据交互,调试工具及组件插槽介绍及使用


    vue组件

    组件(Component)是 Vue.js 最强大的功能之一。

    组件可以扩展 HTML 元素,封装可重用的代码。

    组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树:

    目标

    /*
    		知道组件化开发思想
    		知道组件的注册方式
    		说出组件间的数据交互方式
    		说出组件插槽的用法
    		说出Vue调试工具的用法
    		基于组件的方式实现业务功能
    */
    
    组件化开发思想
    /*
    		标准
    		分治
    		重用
    		组合
    		
    		组件化规范: Web Components
    				希望尽可能多的重用代码
    				自定义组件的方式不太容易(html,css和js)
    				多次使用组件可能冲突
    				
    		Web Components通过创建封装好功能的定制元素解决上述问题.
    */
    
    全局组件

    语法

    // 定义组件
    Vue.component(组件名称, {
    		data: 组件数据
    		template: 组件模板内容
    })
    
    // 组件用法
    <div id="app">
       <button-counter></button-counter>
    </div>
    

    Example1

    <!DOCTYPE html>
    <html lang="en">
    
    	<head>
    		<meta charset="UTF-8">
    		<title>Document</title>
    	</head>
    
    	<body>
    		<div id="app">
    			<button-counter>点击</button-counter>
    		</div>
    
    		<script type="text/javascript" src="js/vue.js"></script>
    		<script type="text/javascript">
    			/*
    				组件注册
    			*/
    			Vue.component('button-counter', {
    				data: function() {
    					return {
    						count: 0
    					}
    				},
    				template: `
    				<div>
    					<button @click="handle">点击了{{ count }}次</button>
    					<button>测试</div>
    				</div>
    				`,
    				methods: {
    					handle: function() {
    						this.count += 2
    					}
    				}
    			})
    
    			var vm = new Vue({
    				el: '#app',
    				data: {
    
    				},
    				methods: {
    
    				}
    			})
    		</script>
    	</body>
    </html>
    

    所有实例都能使用全局组件

    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="utf-8">
    		<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    		<title>Examples</title>
    		<meta name="description" content="">
    		<meta name="keywords" content="">
    		<link href="" rel="stylesheet">
    		<script type="text/javascript" src="lib/vue.js"></script>
    
    		<style>
    			.navbar{
    				background: red;
    			}
    		</style>
    	</head>
    	<body>
    		<div id="box">
    			<navbar></navbar>
    			<navbar></navbar>
    		</div>
    
    		<script type="text/javascript">
    			// 1. 全局定义组件(作用域隔离)
    			Vue.component("navbar", {
    				template: `
    				<div style="background:yellow">
    					<button @click="handleback()">返回</button>
    					navbar
    					<button>主页</button>
    				</div>`,
    				methods: {
    					handleback() {
    						console.log("back")
    					}
    				}
    			})
    
    			new Vue({
    				el: "#box"
    
    			})
    		</script>
    
    	</body>
    </html>
    
    局部组件

    我们可以在实力选项中注册局部组件,这样组件只能在这个实例中使用

    定义局部组件

    /*
    		var ComponentA = {  ...  }
    		var ComponentB = {  ...  }
    		var ComponentC = {  ...  }
    		
    		new Vue({
    				el: '#app'
    				components {
    						'component-a': ComponentA,
    						'component-b': ComponentB,
    						'component-c': ComponentC,
    				}
    		})
    */
    

    Example1

    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="utf-8">
    		<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    		<title>Examples</title>
    		<meta name="description" content="">
    		<meta name="keywords" content="">
    		<link href="" rel="stylesheet">
    		<script type="text/javascript" src="lib/vue.js"></script>
    
    		<style>
    			.navbar{
    				background: red;
    			}
    		</style>
    	</head>
    	<body>
    		<div id="box">
    			<navbar></navbar>
    			<navbar></navbar>
    			<sidebar></sidebar>
    		</div>
    
    		<script type="text/javascript">
    			// 1. 全局定义组件(作用域隔离)
    			Vue.component("navbar", {
    				template: `
    				<div style="background:yellow">
    					<button @click="handleback()">返回</button>
    					navbar
    					<button>主页</button>
    					<child></child>
    					<navbarchild></navbarchild>
    				</div>`,
    				methods: {
    					handleback() {
    						console.log("back")
    					}
    				},
    
    				// 局部定义组件
    				components: {
    					navbarchild: {
    						template: `
    						<div>
    							navbarchild-只能在navbar组件中使用
    						</div>
    						`
    					}
    				}
    			})
    
    			Vue.component("child", {
    				template: `<div>child组件-全局定义</div>`
    			})
    
    			Vue.component("sidebar", {
    				template: `
    				<div>
    					sider组件
    					<child></child>
    				</div>
    				`
    			})
    
    			new Vue({
    				el: "#box"
    			}) // root component
    		</script>
    
    	</body>
    </html>
    

    Example2

    <!DOCTYPE html>
    <html lang="en">
    	<head>
    		<meta charset="UTF-8">
    		<title>Document</title>
    	</head>
    	<body>
    		<div id="app">
    			<hello-world></hello-world>
    			<hello-tom></hello-tom>
    			<hello-jerry></hello-jerry>
    			<test-com></test-com>
    		</div>
    		<script type="text/javascript" src="js/vue.js"></script>
    		<script type="text/javascript">
    			/*
          局部组件注册
          局部组件只能在注册他的父组件中使用
        */
    			Vue.component('test-com', {
    				template: '<div>Test<hello-world></hello-world></div>'
    			});
    			var HelloWorld = {
    				data: function() {
    					return {
    						msg: 'HelloWorld'
    					}
    				},
    				template: '<div>{{msg}}</div>'
    			};
    			var HelloTom = {
    				data: function() {
    					return {
    						msg: 'HelloTom'
    					}
    				},
    				template: '<div>{{msg}}</div>'
    			};
    			var HelloJerry = {
    				data: function() {
    					return {
    						msg: 'HelloJerry'
    					}
    				},
    				template: '<div>{{msg}}</div>'
    			};
    			var vm = new Vue({
    				el: '#app',
    				data: {
    
    				},
    				components: {
    					'hello-world': HelloWorld,
    					'hello-tom': HelloTom,
    					'hello-jerry': HelloJerry
    				}
    			});
    		</script>
    	</body>
    </html>
    
    组件注意事项
    /*
    		1. data必须是一个函数
    				分析函数与普通对象的对比
    				
    		2. 组件模板内容必须是单个跟元素
    				分析演示实际的效果
    				
    		3. 组件模板内容可以是模板字符串
    				模板字符串需要浏览器提供支持(ES6语法)
    */
    
    组件命名方式
    /*
    		短横线方式
    			Vue.component('my-component',{ ...  })
    
    		驼峰方式
    			Vue.component('MyComponent',( ... ))
    */
    

    Example1

    <!DOCTYPE html>
    <html lang="en">
    
    	<head>
    		<meta charset="UTF-8">
    		<title>Document</title>
    	</head>
    
    	<body>
    		<div id="app">
    			<button-counter>点击</button-counter>
    		</div>
    
    		<script type="text/javascript" src="js/vue.js"></script>
    		<script type="text/javascript">
    			/*
    			  组件注册注意事项
    			  如果使用驼峰式命名组件,那么在使用组件的时候,只能在字符串模板中用驼峰的方式使用组件,但是
    			  在普通的标签模板中,必须使用短横线的方式使用组件
    			*/
    			Vue.component('HelloWorld', {
    				data: function() {
    					return {
    						msg: 'HelloWorld'
    					}
    				},
    				template: '<div>{{msg}}</div>'
    			});
    
    			Vue.component('button-counter', {
    				data: function() {
    					return {
    						count: 0
    					}
    				},
    				template: `
            <div>
              <button @click="handle">点击了{{count}}次</button>
              <button>测试123</button>
              <HelloWorld></HelloWorld>
            </div>
          `,
    				methods: {
    					handle: function() {
    						this.count += 2;
    					}
    				}
    			})
    
    			var vm = new Vue({
    				el: '#app',
    				data: {
    
    				},
    				methods: {
    
    				}
    			})
    		</script>
    	</body>
    </html>
    
    组件编写方式与Vue实例的区别
    /*
    		1. 自定义组件需要有一个root element
    		2. 父子组件的data是无法共享的
    		3. 组件可以有data,methods,computed.., 但是data必须是一个函数
    */
    

    Vue调试(Devtools)工具用法

    地址

    https://github.com/vuejs/vue-devtools

    /*
    
    */
    
    安装

    下载包并打包

    git clone https://github.com/vuejs/vue-devtools.git
    cd vue-devtools
    yarn install && yarn build
    

    谷歌浏览器打开开发者模式,加载打包后的shell-chrome目录

    组件间数据交互

    父组件向子组件传值

    1. 组件内部通过props接受传递过来的值

    Vue.component('menu-item',{
    		props: ['title'],
    template: '<div>{{ title }}</div>div>'
    </div>
    })
    

    2. 父组件通过属性将值传递给子组件

    <menu-item title="来自父组件的数据"></menu-item>
    <menu-item :title="title"></menu-item>
    

    Example1

    <!DOCTYPE html>
    <html lang="en">
    	<head>
    		<meta charset="UTF-8">
    		<title>Document</title>
    	</head>
    	<body>
    		<div id="app">
    			<div>{{pmsg}}</div>
    			<menu-item title='来自父组件的值'></menu-item>
    			<menu-item :title='ptitle' content='hello'></menu-item>
    		</div>
    		<script type="text/javascript" src="js/vue.js"></script>
    		<script type="text/javascript">
    			/*
          父组件向子组件传值-基本使用
        */
    			Vue.component('menu-item', {
    				props: ['title', 'content'],
    				data: function() {
    					return {
    						msg: '子组件本身的数据'
    					}
    				},
    				template: '<div>{{msg + "----" + title + "-----" + content}}</div>'
    			});
    			var vm = new Vue({
    				el: '#app',
    				data: {
    					pmsg: '父组件中内容',
    					ptitle: '动态绑定属性'
    				}
    			});
    		</script>
    	</body>
    </html>
    
    子组件向父组件传值
    /*
    		1. 子组件通过自定义事件向父组件传递信息
    		<button v-on:click='$emit("enlarge-text")'>扩大字体</button>
    		
    		2. 父组件监听子组件的事件
    		<menu-item v-on:enlarge-text='fontSize += 0.1'></menu-item>
    */
    

    Example1

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    <body>
    <div id="app">
        <div :style='{fontSize: fontSize + "px"}'>{{pmsg}}</div>
        <menu-item :parr='parr' @enlarge-text='handle($event)'></menu-item>
    </div>
    <script type="text/javascript" src="js/vue.js"></script>
    <script type="text/javascript">
        /*
          子组件向父组件传值-携带参数
        */
    
        Vue.component('menu-item', {
            props: ['parr'],
            template: `
            <div>
              <ul>
                <li :key='index' v-for='(item,index) in parr'>{{item}}</li>
              </ul>
              <button @click='$emit("enlarge-text", 5)'>扩大父组件中字体大小</button>
              <button @click='$emit("enlarge-text", 10)'>扩大父组件中字体大小</button>
            </div>
          `
        });
        var vm = new Vue({
            el: '#app',
            data: {
                pmsg: '父组件中内容',
                parr: ['apple', 'orange', 'banana'],
                fontSize: 10
            },
            methods: {
                handle: function (val) {
                    // 扩大字体大小
                    this.fontSize += val;
                }
            }
        });
    </script>
    </body>
    </html>
    
    非父子组件间传值
    /*
    		1. 单独的事件中心管理组件间通信
    				var eventHub = new Vue()
    				
    		2. 监听事件与销毁事件
    				eventHub.$on('add-todo',addTodo)
    				eventHub.$off('add-todo')
    				
    		3. 触发时间
    				eventHub.$emit('add-todo',id)
    */
    

    Example1

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    <body>
    <div id="app">
        <div>父组件</div>
        <div>
            <button @click='handle'>销毁事件</button>
        </div>
        <test-tom></test-tom>
        <test-jerry></test-jerry>
    </div>
    <script type="text/javascript" src="js/vue.js"></script>
    <script type="text/javascript">
        /*
          兄弟组件之间数据传递
        */
        // 提供事件中心
        var hub = new Vue();
    
        Vue.component('test-tom', {
            data: function () {
                return {
                    num: 0
                }
            },
            template: `
            <div>
              <div>TOM:{{num}}</div>
              <div>
                <button @click='handle'>点击</button>
              </div>
            </div>
          `,
            methods: {
                handle: function () {
                    hub.$emit('jerry-event', 2);
                }
            },
            mounted: function () {
                // 监听事件
                hub.$on('tom-event', (val) => {
                    this.num += val;
                });
            }
        });
        Vue.component('test-jerry', {
            data: function () {
                return {
                    num: 0
                }
            },
            template: `
            <div>
              <div>JERRY:{{num}}</div>
              <div>
                <button @click='handle'>点击</button>
              </div>
            </div>
          `,
            methods: {
                handle: function () {
                    // 触发兄弟组件的事件
                    hub.$emit('tom-event', 1);
                }
            },
            mounted: function () {
                // 监听事件
                hub.$on('jerry-event', (val) => {
                    this.num += val;
                });
            }
        });
        var vm = new Vue({
            el: '#app',
            data: {},
            methods: {
                handle: function () {
                    hub.$off('tom-event');
                    hub.$off('jerry-event');
                }
            }
        });
    </script>
    </body>
    </html>
    
    props属性名规则
    /*
    		在props中使用驼峰形式,模板中需要使用短横线的形式.
    		字符串形式的模板中没有这个模板
    		
    		Vue.component('menu-item',{
    				// 在JavaScript中是驼峰式的
    				props: ['menuTitle'],
    				template: '<div>{{ menuTitle }}</div>'
    		})
    		
    		<!-- 在html中是短横线方式的 -->
    		<menu-item menu-title="nihao"></menu-item>
    */
    

    Example1

    <!DOCTYPE html>
    <html lang="en">
    	<head>
    		<meta charset="UTF-8">
    		<title>Document</title>
    	</head>
    	<body>
    		<div id="app">
    			<div>{{pmsg}}</div>
    			<menu-item :menu-title='ptitle'></menu-item>
    		</div>
    		<script type="text/javascript" src="js/vue.js"></script>
    		<script type="text/javascript">
    			/*
          父组件向子组件传值-props属性名规则
        */
    			Vue.component('third-com', {
    				props: ['testTile'],
    				template: '<div>{{testTile}}</div>'
    			});
    			Vue.component('menu-item', {
    				props: ['menuTitle'],
    				template: '<div>{{menuTitle}}<third-com testTile="hello"></third-com></div>'
    			});
    			var vm = new Vue({
    				el: '#app',
    				data: {
    					pmsg: '父组件中内容',
    					ptitle: '动态绑定属性'
    				}
    			});
    		</script>
    	</body>
    </html>
    
    props属性值类型
    /*
    		字符串 String
    		数值 Number
    		布尔值  Boolean
    		数组   Array
    		对象   Object
    */
    

    Example1

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    
    <body>
    <div id="app">
        <div>{{pmsg}}</div>
        <menu-item :pstr='pstr' :pnum='12' pboo='true' :parr='parr' :pobj='pobj'></menu-item>
    </div>
    <script type="text/javascript" src="js/vue.js"></script>
    <script type="text/javascript">
        /*
          父组件向子组件传值-props属性值类型
        */
    
        Vue.component('menu-item', {
            props: ['pstr', 'pnum', 'pboo', 'parr', 'pobj'],
            template: `
            <div>
              <div>{{pstr}}</div>
              <div>{{12   pnum}}</div>
              <div>{{typeof pboo}}</div>
              <ul>
                <li :key='index' v-for='(item,index) in parr'>{{item}}</li>
              </ul>
                <span>{{pobj.name}}</span>
                <span>{{pobj.age}}</span>
              </div>
            </div>
          `
        });
        var vm = new Vue({
            el: '#app',
            data: {
                pmsg: '父组件中内容',
                pstr: 'hello',
                parr: ['apple', 'orange', 'banana'],
                pobj: {
                    name: 'lisi',
                    age: 12
                }
            }
        });
    </script>
    </body>
    </html>
    

    插槽

    组件插槽
    /*
    		父组件向子组件传递内容
    */
    

    插槽位置

    Vue.component('alert-box',{
    		template: `
    			<div class="demo-alert-box">
            <strong>Error!</strong>
            <slot></slot>
          </div>
    		`
    })
    

    插槽内容

    <alert-box>Something=happen</alert-box>
    

    Example1

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    
    <body>
    <div id="app">
        <alert-box>有bug发生</alert-box>
        <alert-box>有一个警告</alert-box>
        <alert-box></alert-box>
    </div>
    
    <script type="text/javascript" src="js/vue.js"></script>
    <script type="text/javascript">
        var vm = new Vue({
            el: '#app',
            data: {},
            methods: {}
        })
    </script>
    </body>
    </html>
    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    
    <body>
    <div id="app">
    
    </div>
    
    <script type="text/javascript" src="js/vue.js"></script>
    <script type="text/javascript">
        /*
               组件插槽
         */
        Vue.component('alert-box', {
            template: `
                <div>
                    <strong>ERROR:</strong>
                    <slot>默认内容</slot>
                </div>
            `
        })
        
        var vm = new Vue({
            el: '#app',
            data: {},
            methods: {}
        })
    </script>
    </body>
    </html>
    
    具名插槽

    1. 插槽定义

    <div class="container">
    	<header>
      	<slot name="header"></slot>
      </header>
      
      <main>
      	<slot></slot>
      </main>
      
      <footer>
      	<slot name="footer"></slot>
      </footer>
    </div>
    

    2.插槽内容

    <base-layout>
    	<h1 slot="header">标题内容</h1>
      
      <p>主要内容1</p>
      <p>主要内容2</p>
      
      <p slot="footer">底部内容</p>
    </base-layout>
    

    Example

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    <body>
    <div id="app">
        <base-layout>
            <p slot='header'>标题信息</p>
            <p>主要内容1</p>
            <p>主要内容2</p>
            <p slot='footer'>底部信息信息</p>
        </base-layout>
    
        <base-layout>
            <template slot='header'>
                <p>标题信息1</p>
                <p>标题信息2</p>
            </template>
            <p>主要内容1</p>
            <p>主要内容2</p>
            <template slot='footer'>
                <p>底部信息信息1</p>
                <p>底部信息信息2</p>
            </template>
        </base-layout>
    </div>
    <script type="text/javascript" src="js/vue.js"></script>
    <script type="text/javascript">
        /*
          具名插槽
        */
        Vue.component('base-layout', {
            template: `
            <div>
              <header>
                <slot name='header'></slot>
              </header>
              <main>
                <slot></slot>
              </main>
              <footer>
                <slot name='footer'></slot>
              </footer>
            </div>
          `
        });
        var vm = new Vue({
            el: '#app',
            data: {}
        });
    </script>
    </body>
    </html>
    
    作用域插槽
    /*
    		应用场景: 父组件对子组件的内容进行加工处理
    */
    

    Example

    <ul>
      <li v-for="item in list" v-bind:key="item.id">
      	<slot v-bind:item="item">
          {{ item.name }}
        </slot>
      </li>
    </ul>
    

    Example2

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
        <style type="text/css">
            .current{
                color: orange;
            }
        </style>
    </head>
    
    <body>
    <div id="app">
        <fruit-list :list='list'>
            <template slot-scope="slotProps">
                <strong v-if='slotProps.info.id==3' class="current">{{ slotProps.info.name }}</strong>
                <span v-else>{{ slotProps.info.name }}</span>
            </template>
        </fruit-list>
    </div>
    
    <script type="text/javascript" src="js/vue.js"></script>
    <script type="text/javascript">
        /*
                作用域插槽
         */
    
        Vue.component('fruit-list', {
            props: ['list'],
            template: `
                <div>
                   <li :key='item.id' v-for='item in list'>
                      <slot :info='item'>{{ item.name }}</slot>
                    </li>
                </div>
            `
        })
    
    
        var vm = new Vue({
            el: '#app',
            data: {
                list: [{
                    id: 1,
                    name: 'apple'
                }, {
                    id: 2,
                    name: 'orange'
                }, {
                    id: 3,
                    name: 'banana'
                }
                ]
            },
            methods: {}
        })
    </script>
    </body>
    </html>
    

    购物车案例

    需求分析
    /*
    		根据业务功能进行组件化划分
    				1. 标题组件(展示文本)
    				2. 列表组件(列表展示,商品数量变更,商品删除)
    				3. 结算组件(计算商品总额)
    */
    
    功能实现步骤
    /*
    		实现整体布局和样式效果
    		划分独立的功能组件
    		组合所有的子组件形成整体结构
    		逐个实现各个组件功能
    				标题组件
    				列表组件
    				结算组件
    */
    

    Example

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
        <style type="text/css">
            .container {
            }
    
            .container .cart {
                 300px;
                margin: auto;
            }
    
            .container .title {
                background-color: lightblue;
                height: 40px;
                line-height: 40px;
                text-align: center;
                /*color: #fff;*/
            }
    
            .container .total {
                background-color: #FFCE46;
                height: 50px;
                line-height: 50px;
                text-align: right;
            }
    
            .container .total button {
                margin: 0 10px;
                background-color: #DC4C40;
                height: 35px;
                 80px;
                border: 0;
            }
    
            .container .total span {
                color: red;
                font-weight: bold;
            }
    
            .container .item {
                height: 55px;
                line-height: 55px;
                position: relative;
                border-top: 1px solid #ADD8E6;
            }
    
            .container .item img {
                 45px;
                height: 45px;
                margin: 5px;
            }
    
            .container .item .name {
                position: absolute;
                 90px;
                top: 0;
                left: 55px;
                font-size: 16px;
            }
    
            .container .item .change {
                 100px;
                position: absolute;
                top: 0;
                right: 50px;
            }
    
            .container .item .change a {
                font-size: 20px;
                 30px;
                text-decoration: none;
                background-color: lightgray;
                vertical-align: middle;
            }
    
            .container .item .change .num {
                 40px;
                height: 25px;
            }
    
            .container .item .del {
                position: absolute;
                top: 0;
                right: 0px;
                 40px;
                text-align: center;
                font-size: 40px;
                cursor: pointer;
                color: red;
            }
    
            .container .item .del:hover {
                background-color: orange;
            }
        </style>
    </head>
    <body>
    <div id="app">
        <div class="container">
            <my-cart></my-cart>
        </div>
    </div>
    <script type="text/javascript" src="js/vue.js"></script>
    <script type="text/javascript">
    
        var CartTitle = {
            props: ['uname'],
            template: `
            <div class="title">{{ uname }}的商品</div>
          `
        }
        var CartList = {
            props: ['list'],
            template: `
            <div>
              <div :key='item.id' v-for='item in list' class="item">
                <img :src="item.img" />
                <div class="name">{{ item.name }}</div>
                <div class="change">
                  <a href="" @click.prevent="sub(item.id)">-</a>
                  <input type="text" class="num" :value='item.num' @blur='changeNum(item.id,$event)' />
                  <a href="" @click.prevent="add(item.id)">+</a>
                </div>
                <div class="del" @click="del(item.id)">×</div>
              </div>
            </div>
          `,
            methods: {
                changeNum: function (id, event) {
                    this.$emit('change-num', {
                        id: id,
                        type: 'change',
                        num: event.target.value
                    })
                },
                sub: function (id) {
                    this.$emit('change-num', {
                        id: id,
                        type: 'sub'
                    })
                },
                add: function (id) {
                    this.$emit('change-num', {
                        id: id,
                        type: 'add'
                    })
                },
                del: function (id) {
                    // 把获取到的id传递给父组件
                    this.$emit('cart-del', id)
                }
            }
        }
        var CartTotal = {
            props: ['list'],
            template: `
            <div class="total">
              <span>总价:{{ total }}</span>
              <button>结算</button>
            </div>
          `,
            computed: {
                total: function () {
                    // 计算商品的总价
                    var t = 0;
                    this.list.forEach(item => {
                        t += item.price * item.num
                    })
                    return t
                }
            }
        }
        Vue.component('my-cart', {
            data: function () {
                return {
                    uname: '张三',
                    list: [{
                        id: 1,
                        name: 'TCL彩电',
                        price: 1000,
                        num: 1,
                        img: 'img/a.jpg'
                    }, {
                        id: 2,
                        name: '机顶盒',
                        price: 1000,
                        num: 1,
                        img: 'img/b.jpg'
                    }, {
                        id: 3,
                        name: '海尔冰箱',
                        price: 1000,
                        num: 1,
                        img: 'img/c.jpg'
                    }, {
                        id: 4,
                        name: '小米手机',
                        price: 1000,
                        num: 1,
                        img: 'img/d.jpg'
                    }, {
                        id: 5,
                        name: 'PPTV电视',
                        price: 1000,
                        num: 2,
                        img: 'img/e.jpg'
                    }]
                }
            },
            template: `
            <div class='cart'>
              <cart-title :uname='uname'></cart-title>
              <cart-list :list='list' @change-num='changeNum($event)'  @cart-del='delCart($event)'></cart-list>
              <cart-total :list='list'></cart-total>
            </div>
          `,
            components: {
                'cart-title': CartTitle,
                'cart-list': CartList,
                'cart-total': CartTotal
            },
            methods: {
                changeNum: function (val) {
                    // 分为三种情况: 输入域变更,加号变更,减号变更
                    if (val.type == 'change') {
                        // 根据子组件传递过来的数据,跟新list中对应数据
                        this.list.some(item => {
                            if (item.id == val.id) {
                                item.num = val.num
                                // 终止遍历
                                return true
                            }
                        })
                    } else if (val.type == 'sub') {
                        // 减一操作
                        this.list.some(item => {
                            if (item.id == val.id) {
                                item.num -= 1
                                // 终止遍历
                                return true
                            }
                        })
                    } else if (val.type = 'add') {
                        // 加一操作
                        this.list.some(item => {
                            if (item.id == val.id) {
                                item.num += 1
                                // 终止遍历
                                return true
                            }
                        })
                    }
                },
                delCart: function (id) {
                    // 根据id删除list中对应的数据
                    // 1. 找到id对应数据的索引
                    var index = this.list.findIndex(item => {
                        return item.id == id
                    })
    
                    // 2. 根据索引删除对应数据
                    this.list.splice(index, 1)
    
                }
            }
        })
        ;
    
        var vm = new Vue({
            el: '#app',
            data: {}
        });
    
    </script>
    </body>
    </html>
    
    fetch请求组件

    fetch

    XMLHttpRequest是一个设计粗糙的API, 配置和调用方式非常混乱,而且基于事件的异步模型写起来不友好,兼容性不好.

    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="utf-8">
    		<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    		<title>Examples</title>
    		<meta name="description" content="">
    		<meta name="keywords" content="">
    		<link href="" rel="stylesheet">
    
    		<script type="text/javascript" src="lib/vue.js"></script>
    	</head>
    	<body>
    
    		<div id="box">
    			<button @click="handleClick()">获取影片信息</button>
    			<ul>
    				<li v-for="data in datalist">
    					<h3>{{ data.name }}</h3>
    					<img :src="data.poster">
    				</li>
    			</ul>
    		</div>
    
    		<script>
    			new Vue({
    				el: "#box",
    				data: {
    					datalist: []
    				},
    				methods: {
    					handleClick() {
    						fetch("./json/test.json").then(res => res.json()).then(res => {
    							console.log(res.data.films)
    							this.datalist = res.data.films
    						})
    					}
    				}
    			})
    		</script>
    
    
    		<!-- new Vue({
    		el: "#box",
    		data:{
    			datalist:["111","222","333"]
    		}
    	}) -->
    	</body>
    </html>
    
    axios请求组件
    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="utf-8">
    		<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    		<title>Examples</title>
    		<meta name="description" content="">
    		<meta name="keywords" content="">
    		<link href="" rel="stylesheet">
    		<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
    		<script type="text/javascript" src="lib/vue.js"></script>
    	</head>
    	<body>
    
    		<div id="box">
    			<button @click="handleClick()">正在热映</button>
    
    			<ul>
    				<li v-for="data in datalist">
    					<h1>{{ data.name }}</h1>
    					<img :src="data.poster">
    				</li>
    			</ul>
    		</div>
    
    		<script>
    			new Vue({
    				el: "#box",
    				data: {
    					datalist: []
    				},
    				methods: {
    					handleClick() {
    						axios.get("./json/test.json").then(res => {
    							// axios 自欧东包装data属性 res.data
    							console.log(res.data.data.films)
    							this.datalist = res.data.data.films
    						}).catch(err => {
    							console.log(err);
    						})
    					}
    				}
    			})
    		</script>
    	</body>
    </html>
    
  • 相关阅读:
    禁止用户打开HTML页面调试
    Git 忽略提交 .gitignore
    PHP日期时间处理
    HTML页面中JavaScript能获取到的各种屏幕大小信息
    移动浏览器H5页面通过scheme打开本地应用
    Python爬虫利器:Beautiful Soup
    MySQL分页查询优化
    JavaScrpit中异步请求Ajax实现
    PHP反射机制
    CentOS下nginx php mysql 环境搭建
  • 原文地址:https://www.cnblogs.com/you-men/p/13998304.html
Copyright © 2020-2023  润新知