1. 程式人生 > 實用技巧 >04 . Vue元件註冊,元件間資料互動,除錯工具及元件插槽介紹及使用

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 {
            width: 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;
            width: 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 {
            width: 45px;
            height: 45px;
            margin: 5px;
        }

        .container .item .name {
            position: absolute;
            width: 90px;
            top: 0;
            left: 55px;
            font-size: 16px;
        }

        .container .item .change {
            width: 100px;
            position: absolute;
            top: 0;
            right: 50px;
        }

        .container .item .change a {
            font-size: 20px;
            width: 30px;
            text-decoration: none;
            background-color: lightgray;
            vertical-align: middle;
        }

        .container .item .change .num {
            width: 40px;
            height: 25px;
        }

        .container .item .del {
            position: absolute;
            top: 0;
            right: 0px;
            width: 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>