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


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>