Vue.js 組件 組件(Component)是 Vue.js 最強大的功能之一。 組件可以擴展 HTML 元素,封裝可重用的代碼。 <template> <div id="app"> <!-- 使用自定義組件 --> <runoob></runoob> </div> </template> <sc ...
Vue.js 組件
組件(Component)是 Vue.js 最強大的功能之一。
組件可以擴展 HTML 元素,封裝可重用的代碼。
<template> <div id="app"> <!-- 使用自定義組件 --> <runoob></runoob> </div> </template> <script> import Vue from 'vue' // 註冊組件 Vue.component('runoob', { template: '<h1>自定義組件!</h1>' }) var count=1; export default { name: 'App', data(){ return{ } }, methods:{ }, } </script> <style scoped> </style>
也可以在實例選項中註冊局部組件,這樣組件只能在這個實例中使用:
<template> <div id="app"> <!-- 使用自定義組件 --> <runoob></runoob> </div> </template> <script> import Vue from 'vue' var Child = { template: '<h1>自定義組件!</h1>' } var count=1; export default { name: 'App', data(){ return{ } }, components:{ 'runoob':Child }, methods:{ }, } </script> <style scoped> </style>
prop 是子組件用來接受父組件傳遞過來的數據的一個自定義屬性。
父組件的數據需要通過 props 把數據傳給子組件,子組件需要顯式地用 props 選項聲明 "prop":
<template> <div id="app"> <!-- 使用自定義組件 --> <child msg="hello,cyy"></child> </div> </template> <script> import Vue from 'vue' Vue.component('child',{ props:['msg'], template:'<span>{{msg}}</span>' }) var count=1; export default { name: 'App', data(){ return{ } }, methods:{ }, } </script> <style scoped> </style>
類似於用 v-bind 綁定 HTML 特性到一個表達式,也可以用 v-bind 動態綁定 props 的值到父組件的數據中。每當父組件的數據變化時,該變化也會傳導給子組件:
<template> <div id="app"> <input type="text" v-model="info"> <!-- 使用自定義組件 --> <child v-bind:msg="info"></child> </div> </template> <script> import Vue from 'vue' Vue.component('child',{ props:['msg'], template:'<span>template content: {{msg}}</span>' }) var count=1; export default { name: 'App', data(){ return{ info:'' } }, methods:{ }, } </script> <style scoped> </style>
以下實例中使用 v-bind 指令將 item傳到每一個重覆的組件中:
<template> <div id="app"> <!-- 使用自定義組件 --> <child v-for="(item,index) in list" :key="index" v-bind:msg="item.name"></child> </div> </template> <script> import Vue from 'vue' Vue.component('child',{ props:['msg'], template:'<span>{{msg}}<br></span>' }) var count=1; export default { name: 'App', data(){ return{ list:[ { name:'cyy1' }, { name:'cyy2' }, { name:'cyy3' } ] } }, methods:{ }, } </script> <style scoped> </style>
註意: prop 是單向綁定的:當父組件的屬性變化時,將傳導給子組件,但是不會反過來。
組件可以為 props 指定驗證要求。
為了定製 prop 的驗證方式,你可以為 props 中的值提供一個帶有驗證需求的對象,而不是一個字元串數組。例如:
Vue.component('my-component', {
props: {
// 基礎的類型檢查 (`null` 和 `undefined` 會通過任何類型驗證)
propA: Number,
// 多個可能的類型
propB: [String, Number],
// 必填的字元串
propC: {
type: String,
required: true
},
// 帶有預設值的數字
propD: {
type: Number,
default: 100
},
// 帶有預設值的對象
propE: {
type: Object,
// 對象或數組預設值必須從一個工廠函數獲取
default: function () {
return { message: 'hello' }
}
},
// 自定義驗證函數
propF: {
validator: function (value) {
// 這個值必須匹配下列字元串中的一個
return ['success', 'warning', 'danger'].indexOf(value) !== -1
}
}
}
})
當 prop 驗證失敗的時候,(開發環境構建版本的) Vue 將會產生一個控制台的警告。
type 可以是下麵原生構造器:
String
Number
Boolean
Array
Object
Date
Function
Symbol
type 也可以是一個自定義構造器,使用 instanceof 檢測。
父組件是使用 props 傳遞數據給子組件,但如果子組件要把數據傳遞迴去,就需要使用自定義事件!
我們可以使用 v-on 綁定自定義事件, 每個 Vue 實例都實現了事件介面(Events interface),即:
- 使用
$on(eventName)
監聽事件 - 使用
$emit(eventName)
觸發事件
另外,父組件可以在使用子組件的地方直接用 v-on 來監聽子組件觸發的事件。
以下實例中子組件已經和它外部完全解耦了。它所做的只是觸發一個父組件關心的內部事件。
<template> <div id="app"> <!-- 使用自定義組件 --> <child @add-count="addCount"></child> <child @add-count="addCount"></child> <p>{{total}}</p> </div> </template> <script> import Vue from 'vue' Vue.component('child',{ template:'<button @click="addNum">click me</button>', data(){ return{ num:0 } }, methods:{ addNum(){ this.num+=1; this.$emit('add-count'); } } }) var count=1; export default { name: 'App', data(){ return{ total:0 } }, methods:{ addCount(){ this.total+=1; } }, } </script> <style scoped> </style>
如果你想在某個組件的根元素上監聽一個原生事件。可以使用 .native 修飾 v-on 。例如:
<my-component v-on:click.native="doTheThing"></my-component>
子組件通過 $emit 觸發父組件的方法時,如果需要傳遞參數,可在方法名後面加可選參數,參數以逗號隔開。
比如 $emit("FunctionName") 當要傳遞參數時 :$emit("FunctionName",[arg1,arg2...])。
Vue.js 自定義指令
除了預設設置的核心指令( v-model 和 v-show ), Vue 也允許註冊自定義指令。
下麵我們註冊一個全局指令 v-focus, 該指令的功能是在頁面載入時,元素獲得焦點:
<template> <div id="app"> <input type="text" v-focus> </div> </template> <script> import Vue from 'vue' //註冊自定義指令v-focus Vue.directive('focus',{ inserted:function(el){ el.focus(); } }) var count=1; export default { name: 'App', data(){ return{ } }, methods:{ }, } </script>
也可以在實例使用 directives 選項來註冊局部指令,這樣指令只能在這個實例中使用:
<template> <div id="app"> <input type="text" v-focus> </div> </template> <script> import Vue from 'vue' var count=1; export default { name: 'App', data(){ return{ } }, directives:{//註冊自定義指令v-focus focus:{ inserted:function(el){ el.focus(); } } } } </script>
指令定義函數提供了幾個鉤子函數(可選):
-
bind
: 只調用一次,指令第一次綁定到元素時調用,用這個鉤子函數可以定義一個在綁定時執行一次的初始化動作。 -
inserted
: 被綁定元素插入父節點時調用(父節點存在即可調用,不必存在於 document 中)。 -
update
: 被綁定元素所在的模板更新時調用,而不論綁定值是否變化。通過比較更新前後的綁定值,可以忽略不必要的模板更新(詳細的鉤子函數參數見下)。 -
componentUpdated
: 被綁定元素所在模板完成一次更新周期時調用。 -
unbind
: 只調用一次, 指令與元素解綁時調用。
鉤子函數的參數有:
- el: 指令所綁定的元素,可以用來直接操作 DOM 。
- binding: 一個對象,包含以下屬性:
- name: 指令名,不包括
v-
首碼。 - value: 指令的綁定值, 例如:
v-my-directive="1 + 1"
, value 的值是2
。 - oldValue: 指令綁定的前一個值,僅在
update
和componentUpdated
鉤子中可用。無論值是否改變都可用。 - expression: 綁定值的表達式或變數名。 例如
v-my-directive="1 + 1"
, expression 的值是"1 + 1"
。 - arg: 傳給指令的參數。例如
v-my-directive:foo
, arg 的值是"foo"
。 - modifiers: 一個包含修飾符的對象。 例如:
v-my-directive.foo.bar
, 修飾符對象 modifiers 的值是{ foo: true, bar: true }
。
- name: 指令名,不包括
- vnode: Vue 編譯生成的虛擬節點。
- oldVnode: 上一個虛擬節點,僅在
update
和componentUpdated
鉤子中可用。
<template> <div id="app"> <div v-cyy:hello.a.b="msg"></div> </div> </template> <script> import Vue from 'vue' //自定義指令cyy Vue.directive('cyy',{ bind:function(el,binding,vnode){ el.innerHTML=` 指令名:${JSON.stringify(binding.name)}<br/> 指令的綁定值:${JSON.stringify(binding.value)}<br/> 指令綁定的前一個值:${JSON.stringify(binding.oldValue)}<br/> 綁定值的表達式或變數名:${JSON.stringify(binding.expression)}<br/> 傳給指令的參數:${JSON.stringify(binding.arg)}<br/> 一個包含修飾符的對象:${JSON.stringify(binding.modifiers)}<br/> 虛擬節點的鍵值:${Object.keys(vnode).join(', ')}<br/> `; } }) export default { name: 'App', data(){ return{ msg:'i am cyy' } }, } </script>
不需要其他鉤子函數時,可以簡寫函數,如下格式
<template> <div id="app"> <div v-cyy:backgroundColor="styleCls">this is a text</div> </div> </template> <script> import Vue from 'vue' //自定義指令cyy Vue.directive('cyy',{ bind:function(el,binding){ el.style.backgroundColor=binding.value.backgroundColor; } }) export default { name: 'App', data(){ return{ styleCls:{ backgroundColor:'pink' } } }, } </script>
指令函數可接受所有合法的 JavaScript 表達式,以下實例傳入了 JavaScript 對象:
<template> <div id="app"> <div v-cyy="{text:text,color:color}">this is a text</div> </div> </template> <script> import Vue from 'vue' //自定義指令cyy Vue.directive('cyy',{ bind:function(el,binding){ el.innerHTML=binding.value.text; el.style.color=binding.value.color; } }) export default { name: 'App', data(){ return{ text:'cyy', color:'orange' } }, } </script>
Vue.js 路由 推薦使用淘寶鏡像:
cnpm install vue-router
<router-link> 是一個組件,該組件用於設置一個導航鏈接,切換不同 HTML 內容。 to 屬性為目標地址, 即要顯示的內容。
以下實例中我們將 vue-router 加進來,然後配置組件和路由映射,再告訴 vue-router 在哪裡渲染它們。代碼如下所示:
使用模塊化機制編程,導入 Vue 和 VueRouter,要調用 Vue.use(VueRouter)
App.vue
<template> <div id="app"> <p> <!-- 通過傳入 `to` 屬性指定鏈接. --> <!-- <router-link> 預設會被渲染成一個 `<a>` 標簽 --> <router-link to="/">home page</router-link> <router-link to="/next">next page</router-link> </p> <!-- 路由匹配到的組件將渲染在這裡 --> <router-view></router-view> </div> </template> <script> import Vue from 'vue' export default { name: 'App', data(){ return{ } }, } </script>
router/index.js
import Vue from 'vue' import Router from 'vue-router' import HelloWorld from '@/components/HelloWorld' //1. 定義(路由)組件,可以從其他文件 import 進來 const Next = { template: '<div>next</div>' } const routes = [ { path: '/Next', component: Next }, { path: '/', component: HelloWorld }, ] Vue.use(Router) export default new Router({ routes })
效果圖
點擊過的導航鏈接都會加上樣式 class ="router-link-exact-active router-link-active"。
to
表示目標路由的鏈接。 當被點擊後,內部會立刻把 to 的值傳到 router.push(),所以這個值可以是一個字元串或者是描述目標位置的對象。
<!-- 字元串 --> <router-link to="home">Home</router-link> <!-- 渲染結果 --> <a href="home">Home</a> <!-- 使用 v-bind 的 JS 表達式 --> <router-link v-bind:to="'home'">Home</router-link> <!-- 不寫 v-bind 也可以,就像綁定別的屬性一樣 --> <router-link :to="'home'">Home</router-link> <!-- 同上 --> <router-link :to="{ path: 'home' }">Home</router-link> <!-- 命名的路由 --> <router-link :to="{ name: 'user', params: { userId: 123 }}">User</router-link> <!-- 帶查詢參數,下麵的結果為 /register?plan=private --> <router-link :to="{ path: 'register', query: { plan: 'private' }}">Register</router-link>
replace
設置 replace 屬性的話,當點擊時,會調用 router.replace() 而不是 router.push(),導航後不會留下 history 記錄。
<router-link :to="{ path: '/abc'}" replace></router-link>
append
設置 append 屬性後,則在當前 (相對) 路徑前添加基路徑。例如,我們從 /a 導航到一個相對路徑 b,如果沒有配置 append,則路徑為 /b,如果配了,則為 /a/b
<router-link :to="{ path: 'relative/path'}" append></router-link>
tag
有時候想要 <router-link>
渲染成某種標簽,例如 <li>
。 於是我們使用 tag
prop 類指定何種標簽,同樣它還是會監聽點擊,觸發導航。
<router-link to="/foo" tag="li">foo</router-link> <!-- 渲染結果 --> <li>foo</li>
active-class
設置 鏈接激活時使用的 CSS 類名。可以通過以下代碼來替代。
<style> ._active{ background-color : red; } </style> <p