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>
原文地址:https://www.cnblogs.com/you-men/p/13998304.html