<template>
<div>
<my-component v-model="value"></my-component>
<!-- 等同 -->
<my-component :value="value" @input="value=$event"></my-component>
<button @click="value=true">顯示</button>
</div>
</template>
<script>
export default{
data(){
return{
value:false,
}
},
components:{
myComponent:resolve =>require(['./my_component'],resolve),
}
}
</script>
複製代碼
<template>
<div v-show="value">
<span>個人組件</span>
<button @click="$emit('input',false)">隱藏</button>
</div>
</template>
<script>
export default{
props:{
value:{
type:Boolean,
default:false,
}
},
data(){
return{}
},
}
</script>
複製代碼
其有三個參數css
include
定義緩存白名單,會緩存的組件;exclude
定義緩存黑名單,不會緩存的組件;include="a,b"
、:include="/a|b/"
、:include="['a', 'b']"
;max
最多能夠緩存多少組件實例。一旦這個數字達到了,在新實例被建立以前,已緩存組件中最久沒有被訪問的實例會被銷燬掉;當它們處於同一節點,v-for
的優先級比v-if
更高,這意味着v-if
將分別重複運行於每一個v-for
循環中。當你只想爲部分項渲染節點時,這種優先級的機制會十分有用。html
<ul>
<li v-for="item in items" v-if="item.show">{{item}}</li>
</ul>
複製代碼
若是你的目的是有條件地跳過循環的執行,那麼能夠將 v-if 置於外層元素 (或<template>
)上。vue
<ul v-if="items.length">
<li v-for="item in items">{{item}}</li>
</ul>
複製代碼
主要看v-for渲染的是什麼。node
<template>
<div>
<span v-for="item in lists">{{item}}</span>
</div>
</template>
<script>
export default {
data() {
return {
lists: [1, 2, 3, 4, 5]
}
},
}
</script>
複製代碼
以上的例子,v-for的內容會生成如下的DOM節點數組,咱們給每個節點標記一個身份id,以辨別節點的位置:[
'<span>1</span>', // id: A
'<span>2</span>', // id: B
'<span>3</span>', // id: C
'<span>4</span>', // id: D
'<span>5</span>' // id: E
]
複製代碼
將lists中的數據進行位置調換,變成[2,4,3,1,5]
,在沒有key的情景下,節點位置不變,可是節點的內容更新了,這就是「就地更新」[
'<span>2</span>', // id: A
'<span>4</span>', // id: B
'<span>3</span>', // id: C
'<span>1</span>', // id: D
'<span>5</span>' // id: E
]
複製代碼
可是在有key的情景下,節點位置進行了交換,可是內容沒有更新[
'<span>2</span>', // id: B
'<span>4</span>', // id: D
'<span>3</span>', // id: C
'<span>1</span>', // id: A
'<span>5</span>' // id: E
]
複製代碼
// vue源碼 src/core/vdom/patch.js 488行
// 如下是爲了閱讀性進行格式化後的代碼
// oldCh 是一箇舊虛擬節點數組
// oldKeyToIdx map映射對象
// idxInOld 對比後獲得舊節點下標
if (isUndef(oldKeyToIdx)) {
oldKeyToIdx = createKeyToOldIdx(oldCh, oldStartIdx, oldEndIdx)
}
if (isDef(newStartVnode.key)) {
// map 方式獲取
idxInOld = oldKeyToIdx[newStartVnode.key]
} else {
// 遍歷方式獲取
idxInOld = findIdxInOld(newStartVnode, oldCh, oldStartIdx, oldEndIdx)
}
複製代碼
建立map函數function createKeyToOldIdx(children, beginIdx, endIdx) {
let i, key
const map = {}
for (i = beginIdx; i <= endIdx; ++i) {
key = children[i].key
if (isDef(key)) map[key] = i
}
return map
}
複製代碼
遍歷尋找函數// sameVnode 是對比新舊節點是否相同的函數
function findIdxInOld(node, oldCh, start, end) {
for (let i = start; i < end; i++) {
const c = oldCh[i];
if (isDef(c) && sameVnode(node, c)) return i
}
}
複製代碼
還能夠強制替換元素/組件而不是重複使用它。在如下場景可使用正則表達式
<transition>
<span :key="text">{{ text }}</span>
</transition>
複製代碼
當 text 發生改變時,<span>
會隨時被更新,所以會觸發過渡。算法
不要使用對象或數組之類的非基本類型值做爲key,請用字符串或數值類型的值;npm
不要使用數組的index做爲key值,由於在刪除數組某一項,index也會隨之變化,致使key變化,渲染會出錯。json
例:在渲染[a,b,c]
用 index 做爲 key,那麼在刪除第二項的時候,index 就會從 0 1 2 變成 0 1(而不是 0 2),隨之第三項的key變成1了,就會誤把第三項刪除了。後端
給組件命名有兩種方式,一種是使用鏈式命名my-component,一種是使用大駝峯命名MyComponent,數組
在字符串模板中<my-component></my-component>
和 <MyComponent></MyComponent>
均可以使用,
在非字符串模板中最好使用<MyComponent></MyComponent>
,由於要遵循W3C規範中的自定義組件名 (字母全小寫且必須包含一個連字符),避免和當前以及將來的 HTML 元素相沖突。
<myComponent@diy="handleDiy"></myComponent>
,在子組件用this.$emit('diy',data)
來觸發這個diy事件,其中data爲子組件向父組件通訊的數據,在父組件中監聽diy個事件時,能夠經過$event訪問data這個值。.sync
綁定一個數據<myComponent :show.sync="show"></myComponent>
,在子組件用this.$emit('updata:show',data)
來改變父組件中show
的值。v-model
。is
特殊特性和component
內置組件標籤時使用;keep-alive
內置組件標籤中include
和exclude
屬性中使用。遞歸引用能夠理解爲組件調用自身,在開發多級菜單組件時就會用到,調用前要先設置組件的name選項, 注意必定要配合v-if使用,避免造成死循環,用element-vue組件庫中NavMenu導航菜單組件開發多級菜單爲例:
<template>
<el-submenu :index="menu.id" popper-class="layout-sider-submenu" :key="menu.id">
<template slot="title">
<Icon :type="menu.icon" v-if="menu.icon"/>
<span>{{menu.title}}</span>
</template>
<template v-for="(child,i) in menu.menus">
<side-menu-item v-if="Array.isArray(child.menus) && child.menus.length" :menu="child"></side-menu-item>
<el-menu-item :index="child.id" :key="child.id" v-else>
<Icon :type="child.icon" v-if="child.icon"/>
<span>{{child.title}}</span>
</el-menu-item>
</template>
</el-submenu>
</template>
<script>
export default{
name: 'sideMenuItem',
props: {
menu: {
type: Object,
default(){
return {};
}
}
}
}
</script>
複製代碼
$attrs
和$listeners
的使用場景?$attrs
: 包含了父做用域中(組件標籤)不做爲 prop 被識別 (且獲取) 的特性綁定 (class 和 style 除外)。 在建立基礎組件時候常用,能夠和組件選項inheritAttrs:false
和配合使用在組件內部標籤上用v-bind="$attrs"
將非prop特性綁定上去;$listeners
: 包含了父做用域中(組件標籤)的 (不含.native
) v-on 事件監聽器。 在組件上監聽一些特定的事件,好比focus事件時,若是組件的根元素不是表單元素的,則監聽不到,那麼能夠用v-on="$listeners"
綁定到表單元素標籤上解決。在有使用$on
的組件中要在beforeDestroy
鉤子函數中用$off
銷燬。
要,否則會形成屢次綁定和內存泄露。關於移除事件監聽的坑。
data
選項中建立一個對象timer
,給每一個定時器取個名字一一映射在對象timer
中, 在beforeDestroy
構造函數中for(let k in this.timer){clearInterval(k)}
;const timer = setInterval(() =>{}, 500);
this.$once('hook:beforeDestroy', () => {
clearInterval(timer);
})
複製代碼
push()
、pop()
、shift()
、unshift()
、splice()
、sort()
、reverse()
,這些方法在Vue中被從新定義了,故能夠監聽到數組變化;filter()
、concat()
、slice()
,這些方法會返回一個新數組,也能夠監聽到數組的變化。利用索引直接設置一個數組項時;
修改數組的長度時。
Object.defineProperty()
是能夠監聽到,利用不存在的索引直接設置一個數組項時Object.defineProperty()
是不能夠監聽到,可是官方給出的解釋是因爲JavaScript的限制,Vue不能檢測以上數組的變更,其實根本緣由是性能問題,性能代價和得到的用戶體驗收益不成正比。Object.defineProperty()
不能監聽到數組的length
屬性。用this.$set(this.items, indexOfItem, newValue)
或this.items.splice(indexOfItem, 1, newValue)
來解決第一種狀況;
用this.items.splice(newLength)
來解決第二種狀況。
由於Vue是經過Object.defineProperty
來將對象的key轉成getter/setter的形式來追蹤變化,但getter/setter只能追蹤一個數據是否被修改,沒法追蹤新增屬性和刪除屬性,因此纔會致使上面對象變化沒法監聽。
this.$set(this.obj,"key","newValue")
來解決第一種狀況;Object.assign
來解決第二種狀況。' '
或undefined
,其餘元素鍵值不變;watch
:一個數據影響多個數據,當須要在數據變化時執行異步或開銷較大的操做時;有三種
掛載在Vue的prototype上
// base.js
const install = function (Vue, opts) {
Vue.prototype.demo = function () {
console.log('我已經在Vue原型鏈上')
}
}
export default {
install
}
複製代碼
//main.js
//註冊全局函數
import base from 'service/base';
Vue.use(base);
複製代碼
利用全局混入mixin
用this.$root.$on
綁定方法,用this.$root.$off
解綁方法,用this.$root.$emit
全局調用。
this.$root.$on('demo',function(){
console.log('test');
})
this.$root.$emit('demo');
this.$root.$off('demo');
複製代碼
el
:提供一個在頁面上已存在的DOM元素做爲Vue實例的掛載目標。能夠是CSS選擇器,也能夠是一個HTMLElement實例。
const vm = new Vue({})
中存在這個選項,實例將當即進入編譯過程,不然,須要顯式調用vm.$mount()
手動開啓編譯。<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
</head>
<body>
<div id="app">我是el掛載的內容:小明今年{{age}}歲了</div>
</body>
<script>
const vm= new Vue({
el:'#app',
data:{
age:17
},
}
</script>
</html>
複製代碼
<script>
const vm= new Vue({
data:{
age:17
},
})
vm.$mount('#app')
</script>
複製代碼
template
:一個字符串模板做爲Vue實例的標識使用。若是el
存在,模板將會替換掛載的元素。掛載元素的內容都將被忽略,除非模板的內容有分發插槽。
<script>
const vm= new Vue({
el:'#app',
data:{
age:17
},
template:'<div>我是template的內容:小明今年{{age}}歲了</div>',
})
</script>
複製代碼
<script type="x-template" id="mb">
<div>我是template的內容:小明今年{{age}}歲了</div>
</script>
<script>
const vm= new Vue({
el:'#app',
data:{
age:17
},
template:'#mb',
})
</script>
複製代碼
<body>
<div id="app">
我是el掛載的內容:小明今年{{age}}歲了
</div>
<template id="mb">
<div>我是template的內容:小明今年{{age}}歲了</div>
</template>
</body>
<script>
const vm= new Vue({
el:'#app',
data:{
age:17
},
template:'#mb',
})
</script>
複製代碼
render
:Vue 選項中的 render 函數若存在,則 Vue 構造函數不會從 template 選項或經過 el 選項指定的掛載元素中提取出的 HTML 模板編譯渲染函數。<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
</head>
<body>
<div id="app">
我是el掛載的內容:小明今年{{age}}歲了
</div>
</body>
<script>
const vm= new Vue({
el:'#app',
data:{
age:17
},
template:'<div>我是template的內容:小明今年{{age}}歲了</div>',
render(h){
return h('div',`我是render的內容:小明今年${this.age}歲了`)
}
})
</script>
</html>
複製代碼
<template></template>
有什麼用?用delimiters
選項,其默認是["{{", "}}"]
// 將分隔符變成ES6模板字符串的風格
new Vue({
delimiters: ['${', '}']
})
複製代碼
以 _
或 $
開頭的屬性 不會 被 Vue 實例代理,由於它們可能和 Vue 內置的屬性、API 方法衝突,你可使用例如 vm.$data._property
的方式訪問這些屬性。
errorCaptured
是組件內部鉤子,當捕獲一個來自子孫組件的錯誤時被調用,接收error
、vm
、info
三個參數,return false
後能夠阻止錯誤繼續向上拋出。errorHandler
爲全局鉤子,使用Vue.config.errorHandler
配置,接收參數與errorCaptured
一致,2.6後可捕捉v-on
與promise
鏈的錯誤,可用於統一錯誤處理與錯誤兜底。<link rel="icon" href="<%= BASE_URL %>favicon.ico">
, 其中<%= BASE_URL %>
等同vue.config.js中publicPath
的配置;<link rel="icon" type="image/png" href="">
import browserImg from 'images/kong.png';//爲favicon的默認圖片
const imgurl ='後端傳回來的favicon.ico的線上地址'
let link = document.querySelector('link[type="image/png"]');
if (imgurl) {
link.setAttribute('href', imgurl);
} else {
link.setAttribute('href', browserImg);
}
複製代碼
build.assetsPublicPath
的值;在項目中通常經過配置alias路徑別名的方式解決,下面是Vue CLI3的配置。
configureWebpack: {
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'@': resolve('src'),
'assets': resolve('src/assets'),
'css': resolve('src/assets/css'),
'images': resolve('src/assets/images'),
}
},
},
複製代碼
由於動態添加src被當作靜態資源處理了,沒有進行編譯,因此要加上require。
<template>
<img class="logo" :src="logo" alt="公司logo">
</template>
<script>
export default {
data() {
return {
logo:require("assets/images/logo.png"),
};
}
};
</script>
複製代碼