vue API 知識點(1)---全域性 API 總結
1.Vue.extend(options)
構造器,建立一個 子類 。引數是一個包含元件選項的物件
data 選項是特例,需要注意 在 Vue.extend() 中它必須是一個函式,
<div id="test"></div>
// 建立構造器 let MyTest = Vue.extend({ template: '<p>{{name}} {{age}}</p>', data(){ return { name: 'zhangning', age: '24' } } })
建立 MyTest 例項,並掛載到一個元素上
new MyTest().$mount('#test')
最終結果如下
<p>zhangning 24</p>
上面 extend 建立的是 Vue 構造器,而不是一個具體的元件例項,所以不能夠通過 new Vue({components: testExtend}) 來直接使用,需要通過 new MyTest().$mount('#test') 來掛載到指定的元素上
*呼叫 Vue.extend() 建立的是一個元件構造器
*通常在建立元件構造器時,傳入 template 代表我們自定義元件的模板
*該模板就是在使用到元件的地方,要顯示的 HTML 程式碼
*但是,這種寫法在vue2之後幾乎就不再使用了,都是直接使用語法糖,不過我們還是要學習的,為後面的學習打下基礎
現在我們通常不使用 Vue.extend() 來註冊元件了,使用語法糖的寫法,直接把物件放在 Vue.component() 來註冊元件,可以看第 7 個API進行學習
呼叫Vue.component() 是將剛才的元件構造器註冊為一個元件,並且給它起一個元件的標籤名字
所以需要傳遞兩個引數:1.註冊元件的標籤名 2.元件構造器
元件必須掛在在某個Vue例項下,否則不會生效
示例:封裝一個全域性提示元件
首先建立一個 message.vue 元件
<template> <transition> <div v-show='show'>{{message}}</div> </transition> </template> <script> export default{ data(){ return { show: false, message: '' } } } </script> <style scoped>
div {
padding: 10px;
color: #ddd;
background: red;
text-align: center;
position: fixed;
top: 30%;
left: 50%;
} </style>
然後在 main.js 中配置
import Message from './components/Message.vue' const MessageM = { install: function(Vue) { // 建立一個 vue 的子類元件 const MessageConstructor = Vue.extend(Message) // 建立子類例項,並掛載到動態建立的元素上,並將元素新增到全域性結構中 const inst = new MessageConstructor().$mount(document.createElement('div')) document.body.appendChild(inst.$el) // 在 vue 原型鏈上註冊方法,控制組件 Vue.prototype.$message = (msg, time = 1000) => { inst.message = msg inst.show = true setTimeout(( inst.show = false ), time) } } }
Vue.use(MessageM)
在元件內使用
this.$message('訊息提示')
以上就是一個簡單的全域性訊息提示
2.Vue.nextTick
在寫詞DOM更新迴圈結束之後執行延遲迴調。在修改資料之後立即使用這個方法,獲取更新後的DOM
<template> <div> <div ref='valRef'>{{ val }}</div> <div>{{ val1 }}</div> <div>{{ val2 }}</div> <div>{{ val3 }}</div> <el-button type="primary" @click.once='handleClick'>改變val</el-button> </div> </template> <script> export default { name: 'index', data() { return { val: 'zhangning', val1: '', val2: '', val3: '' } }, methods: { // 點選按鈕時,val1和val3獲取的是初次載入時候的val的值,因為vue的DOM是非同步載入, // 而使用了nextTick的val2的值在msg改變之後,就立刻獲取到了val更新之後的值 handleClick() { this.val = '我已改變'; // DOM 未更新,獲取不到最新的dom this.val1 = this.$refs.valRef.innerHTML; this.$nextTick(() => { // DOM 已更新,獲取最新的dom this.val2 = this.$refs.valRef.innerHTML; }) // DOM 未更新,獲取不到最新的dom this.val3 = this.refs.valRef.innerHTML; } } } </script>
官方給出的解釋和例子(非同步更新佇列)
Vue 在更新 DOM 時是非同步執行的。只要監聽到資料變化,Vue 將開啟一個佇列,並緩衝在同一事件迴圈中發生的所有資料變更,如果同一個 watcher 被多次觸發,只會被推入到佇列中一次。這種在緩衝時去除重複資料對於避免不必要的計算和 DOM 操作是非常重要的。然而在下一個的事件迴圈 tick 中,Vue 重新整理佇列並執行實際(已去重)工作。Vue 在內部對非同步佇列嘗試使用原生的Promise.then、MutationObserver 和 setImmediate,如果執行環境不支援,則會採用 setTimeout(fn, 0) 代替。
例如,當設定 vm.someData = 'newVlaue',該元件不會立即重新渲染,當重新整理佇列時,元件會在下一個事件迴圈 tick 中更新。多數情況我們不需要關心這個過程,但是如果想基於更新後的 DOM 狀態做點什麼,這就有點棘手。雖然Vue鼓勵我們使用資料驅動的方式思考,避免直接接觸 DOM ,但是有時我們必須要這麼做。為了在資料變化之後等待 Vue 完成更新 DOM,可以在資料變化之後立即使用 Vue.nextTick(callback)。這樣回撥函式將在 DOM 更新完成之後被呼叫。例如
<div id="example">{{message}}</div>
var vm = new Vue({ el: '#example', data: { message: '123' } }) vm.message = 'new message' // 更改資料 vm.$el.textContent === 'new message' // false Vue.nextTick(function () { vm.$el.textContent === 'new message' // true })
在元件內使用 vm.$nextTick() 例項方法特別方便,因為它不需要全域性 Vue ,並且回撥函式中的 this 將自動繫結到當前的 Vue 例項上
Vue.component('example', { template: '<span>{{ message }}</span>', data: function () { return { message: '未更新' } }, methods: { updateMessage: function () { this.message = '已更新' console.log(this.$el.textContent) // => '未更新' this.$nextTick(function () { console.log(this.$el.textContent) // => '已更新' }) } } })
因為 $nextTick() 返回一個 Promise 物件,所以你可以使用新的語法 async/await 完成相同的事情
methods: { updateMessage: async function () { this.message = '已更新' console.log(this.$el.textContent) // => '未更新' await this.$nextTick() console.log(this.$el.textContent) // => '已更新' } }
3.Vue.set
Vue.set(target, key, value)
target:要更改的資料來源(可以是物件或者陣列)
key:要更改的具體資料
value:重新賦的值
由於 js 的限制,Vue 不能檢測出資料的改變,但是通過這種方法修改陣列中的資料,就會檢測到陣列的改變,是響應式的
用法:向響應式物件中新增一個 property, 並確保這個新 property 同樣是響應式的,且觸發檢視更新。它必須用於向響應式物件上新增新 property,因為 Vue 無法探測普通的新增 property (比如 arr[1] = 110)
export default { name: 'index', data() { return { arr: [1,2,3] } }, methods: { // 修改 arr[1] 變為 200 handleChange(){ this.$set(this.arr, 1, 200);// arr: [1, 200, 3] }, // arr 陣列新增元素 600 handleAddArr(){ this.$set(this.arr, this.arr.length, 600); } } }
4.Vue.delete()
Vue.delete(target, key, value)
target:要刪除的資料來源(可以是物件或者陣列)
key:要刪除的具體資料
用法:刪除物件的 property。如果物件是響應式的,確保刪除能觸發更新檢視。這個方法主要用於避開 Vue 不能檢測到 property 被刪除的限制,雖然很少使用,但直到要會用
export default { name: 'index', data() { return { zhangning: { height: 187, name: 'zhangning', sex: '男' } } }, methods: { // 刪除 name handleDeleteName() { this.$set(this.zhangning, 'name'); } } }
5.Vue.directive()
Vue.directive(string, Function | Object)
註冊或獲取全域性指令
宣告週期:
bind:只調用一次,指令第一次繫結到元素時呼叫。在這裡可以進行一次性的初始化設定。
inserted:被繫結元素插入父節點時呼叫(僅保證父節點存在,但不一定被插入文件中)
update:所在元件的 VNode 更新時呼叫,但是可能發生在其子 VNode 更新之前。指令的值可能發生改變,也可能沒有,但是你可以通過比較更新前後的值來忽略不必要的模板更新(詳細的鉤子函式引數見下)
componentUpdated:指令所在元件的 VNode 及其子 VNode 全部更新後呼叫
unbind:只調用一次,指令與元素解綁時呼叫
鉤子函式引數
el:指令所繫結的元素,可以用來直接操作 DOM
binding:一個物件,包含以下 property:
name:指令名,不包括 v- 字首
value:指令的繫結值,例如:v-my-directive='1+1'中,繫結值為 2
oldValue:指令繫結的前一個值,僅在 update 和 componentUpdated 鉤子中可用,無論值是否改變都可用
expression:字串形式的指令表示式。例如 v-my-directive='1+1' 中,表示式為 ‘1+1’
arg:傳給指令的引數,可選。例如 v-my-directive: foo 中,引數為 'foo'
modifiers:一個包含修飾符的物件。例如:v-my-directive.foo.bar 中,修飾符物件為 {foo: true, bar: true}
vnode:Vue 編譯生成的虛擬節點
oldVnode:上一個虛擬節點,僅在 update 和 componentUpdated 鉤子中可用
<div id="hook-arguments-example" v-demo:foo.a.b="message"></div>
Vue.directive('demo', { bind: function (el, binding, vnode) { var s = JSON.stringify el.innerHTML = 'name: ' + s(binding.name) + '<br>' + 'value: ' + s(binding.value) + '<br>' + 'expression: ' + s(binding.expression) + '<br>' + 'argument: ' + s(binding.arg) + '<br>' + 'modifiers: ' + s(binding.modifiers) + '<br>' + 'vnode keys: ' + Object.keys(vnode).join(', ') } }) new Vue({ el: '#hook-arguments-example', data: { message: 'hello!' } })
頁面展示效果如下
name: 'demo'
value: 'hello!'
expression: 'message'
argument: 'foo'
modifiers: {a: true, b: true}
vnode keys: tag,data,children,text,elm,ns,context...
動態指令引數,指令的引數可以是動態的,例如,在 v-mydirective:[argument]='value'中,argument 引數可以根據元件資料進行更新,這可以讓我們的自定義指令靈活使用。
建立一個自定義指令,把元素固定在距離頂部 200px 的位置
<div id="test"> <p>Scroll down the page</p> <p v-pin="200">距離頂部200px</p> </div>
Vue.directive('pin', { bind: function(el, binding, vnode){ el.style.position = 'fixed' el.style.top = binding.value + 'px' } }) new Vue({ el: '#test' })
當我們需要固定在左側而不是頂部的時候,這時候我們就需要用到動態指令
<div id="test"> <p>Scroll down the page</p> <p v-pin:[direction]="200">距離頂部200px</p> </div>
Vue.directive('pin', { bind: function(el, binding, vnode){ el.style.position = 'fixed' let s = binding.arg == 'left' ? 'left' : 'top' el.style[s] = binding.value + 'px' } }) new Vue({ el: '#test' , data(){ return { direction: 'left' } } })
以上這個自定義指令現在的靈活性就足以支援一些不同的用例了
函式簡寫
很多時候,我們想在 bind 和 update 時觸發相同行為,而不關心其他的鉤子。
Vue.directive('pin', function(el, binding){ el.style.top = binding.value + 'px' })
如果指令需要多個值,可以傳入 js 物件,指令函式能夠接收所有合法的 js 表示式
<div v-demo="{ color: 'red', text: 'hello'}"></div>
Vue.directive('demo', function(el, binding){ console.log(binding.value.color) // red console.log(binding.value.text) // hello })
在專案中使用的案例
通過許可權控制每個頁面的按鈕,
先定義一個 directive.js,寫上全域性指令
import Vue from 'vue'; import store from './store'; Vue.directive('permission', { inserted: (el, binding) => { if (store.getters.userButtons.length) { const buttons = store.getters.userButtons; if (buttons.indexOf(binding.value) < 0) el.parentNode.removeChild(el); } else { store.dispatch('getInfo').then(data => { const { buttons } = data.buttons; if (buttons.indexOf(binding.value) < 0) el.parentNode.removeChild(el); }); } } });
在 main.js 中全域性引入
import './directive.js'
在 vue 元件中使用,判斷有沒有下載按鈕許可權
<el-button round icon="el-icon-document" type="primary" v-permission="'SJML_SQXZ'" @click="applyForDownload" >下載文件</el-button>
6.Vue.filter()
定義過濾器,可被用於常見的文字格式化。過濾器可以用在兩個地方:雙花括號插值和 v-bind 表示式,過濾器應該被新增在 js 表示式的尾部,由管道符號指示:'|'
<!-- 在雙花括號中 --> {{ message | capitalize }}
<!-- 在 `v-bind` 中 --> <div v-bind:id="rawId | formatId"></div>
在一個元件的選項中定義本地過濾器
filters: { capitalize: function (value) { if (!value) return '' value = value.toString() return value.charAt(0).toUpperCase() + value.slice(1) } }
在建立 Vue 例項之前全域性定義過濾器
Vue.filter('capitalize', function() { if (!value) return '' value = value.toString() return value.charAt(0).toUpperCase() + value.slice(1) }) new Vue({ // ... })
注意:當全域性過濾器和區域性過濾器重名時,會採用區域性過濾器
過濾器函式總接收表示式的值作為第一個引數
過濾器可以串聯:
{{ message | filterA | filterB }}
這個例子中,filterA 被定義為接收單個引數的過濾器函式,表示式 message 的值將作為引數傳入到函式中。然後繼續呼叫同樣被定義為接收單個引數的過濾器函式 filterB,將 filterA 的結果傳遞給 filterB 中。
過濾器時 js 函式,因此可以接收引數
{{ message | filterA('arg1', arg2) }}
這個例子,filterA 被定義為接收三個引數的過濾器函式,其中 message 的值作為第一個引數,普通字串 'arg1' 作為第二個引數, arg2 作為第三個引數
在專案中使用的案例
先定義一個 filters.js
export { formatBoolean, formatDate, formatNum, formatStatus }; // 布林值 function formatBoolean(value) { return value ? "是" : "否"; } // 狀態 function formatStatus(value) { return value ? "成功" : "失敗"; } // 時間戳轉換 function formatDate(value) { let date = new Date(parseInt(value)); let Y = date.getFullYear(); let M = date.getMonth() + 1 < 10 ? "0" + (date.getMonth() + 1) : date.getMonth() + 1; // let D = date.getDate(); let D = date.getDate() < 10 ? "0" + date.getDate() : date.getDate(); let h = date.getHours() < 10 ? "0" + date.getHours() : date.getHours(); let m = date.getMinutes() < 10 ? "0" + date.getMinutes() : date.getMinutes(); let s = date.getSeconds() < 10 ? "0" + date.getSeconds() : date.getSeconds(); return Y + "." + M + "." + D + " " + h + ":" + m + ":" + s; } // 數值加逗號 function formatNum(num) { num = (num || 0).toString(); let result = ""; while (num.length > 3) { result = "," + num.slice(-3) + result; num = num.slice(0, num.length - 3); } if (num) { result = num + result; } return result; }
然後在 main.js 中進行全域性引入
import * as filters from './filters.js' Object.keys(filters).forEach(item => { Vue.filter(item, filters[item]) })
// 這裡講一下 Object.keys() 方法,表示給定物件的所有可列舉屬性的字串陣列 let zn = {name: 'zhangning', age: '24', height: '187'} Object.keys(zn);// ['name', 'age', 'height'] 返回可列舉屬性組成的陣列 // 處理陣列,返回索引值陣列 let arr = [100, 200, 300, 400, 500] Object.keys(arr);// ['0', '1', '2', '3', '4'] 返回索引值字串組成的陣列 // 處理字串,返回索引值陣列 let str = 'zhang'; Object.keys(str);// ['0', '1', '2', '3', '4'] // 常用技巧 let zn = {name: 'zhangning', age: '25', address: '合肥', getName: function()} Object.keys(person).map(item => { person[item] // 獲取到屬性對應的值,做一些處理 })
7.Vue.component()
// 定義一個名為 button-counter 的新元件 Vue.component('button-counter', { data: function () { return { count: 0 } }, template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>' })
data 必須是一個函式,因此每個例項可以維護一份被返回物件的獨立的拷貝,如果不是一個函式,就會影響到元件所有例項
在專案中自定義全域性元件案例
首先建立一個元件 download.vue
然後建立一個 download.js,在 js 中引入元件
// 引入元件 import DLFLoading from './index.vue'; // 自定義元件物件 const DownloadDialog = { // install 是預設的方法。當外界在 use 這個元件的時候,就會呼叫本身的 install 方法,同時傳一個 Vue 這個類的引數 install: function(Vue) { // Vue.component() 與正常的全域性註冊元件用法相同,可以理解為通過 install 和 Vue.use()函式註冊了全域性元件 Vue.component('DownloadDialog', DLFLoading); } } // 匯出 export default DownloadDialog;
接著在 main.js 中全域性引入元件
// 全域性引入自定義下載 loading import DownloadDialog from '@/components/DownloadDialog/download.js'; Vue.use(DownloadDialog);
最後在專案中直接就可以使用
<DownloadDialog @cancelDownload="cancelDownload" :downloadOver="downloadOver" :downloadLoading="downloadLoading" ></DownloadDialog>
8.Vue.use()
安裝 Vue.js 外掛。如果外掛是一個物件,必須提供 install 方法。如果外掛是一個函式,它會被作為 install 方法。install 方法呼叫時,會將 Vue 作為引數傳入。
該方法需要在 new Vue() 之前被呼叫
當 install 方法被同一個外掛多次呼叫,外掛將只會被安裝一次。
外掛通常用來為 Vue 新增全域性功能。外掛的功能範圍沒有嚴格的限制 一般有以下幾種
1.新增全域性方法或者property
2.新增全域性資源:指令/過濾器/過渡等
3.通過全域性混入來新增一些元件選項
4.新增 Vue 例項方法,通過把他們新增到 Vue.prototype 上實現
5.一個庫,提供自己的 api,同時提供上面提到的一個或多個功能
使用外掛
通過全域性方法 Vue.use() 使用外掛。它需要在你呼叫 new Vue() 啟動應用之前完成
// 呼叫 MyPlugin.install(Vue) Vue.use(MyPlugin) new Vue({ // ...元件選項 })
也可以傳入一個可選的選項物件
Vue.use(MyPlugin, {someOption: true})
Vue.use 會自動阻止多次註冊相同外掛,即使多次呼叫也只會註冊一次該外掛
9.Vue.mixin()
全域性註冊一個混入,影響註冊之後所有建立的每個 Vue 例項。外掛作者可以使用混入,向元件注入自定義的行為(官方不推薦使用)
官網全域性混入案例。混入也可以進行全域性註冊,使用時格外小心,一旦使用全域性混入,它將影響每一個之後建立的 Vue 例項。使用恰當時,它可以用來自定義選項注入處理邏輯。
// 為自定義的選項 myOption 注入一個處理器
Vue.mixin({ created: function(){ var myOption = this.$options.myOption if(myOption) { console.log(myOption) } } }) new Vue({ myOption: 'zhangning' }) // => 'zhangning'
注意:要謹慎使用全域性混入,因為它影響每個單獨建立的 Vue 例項(包括第三方元件)。大多數情況下,之應當應用於自定義選項,就像上面例項一樣,推薦將其作為外掛釋出,以避免重複應用混入
使用案例
定義一個 mixin.js
let MiXin = { data(){ return { name: 'zhangning' } }, created(){ console.log('這是mixin中的name', this.name) }, mounted(){}, methods: {} } export default MiXin
// 全域性引入 import mixin from './mixin' Vue.mixin(mixin) // 在 vue 元件中區域性引入 import '@/mixin' export default { mixins: [mixin] }
混入和元件的合併注意事項
1.資料物件 data 在內部進行遞迴合併,在和元件的資料發生衝突時以元件資料優先
2.同名鉤子函式(created,mounted)將混合為一個數組,都將被呼叫。另外混入物件的鉤子將在元件自身鉤子之前呼叫
3.值為物件的選項(methods,components,directives)將被混合為同一個物件,兩個物件鍵名衝突時,去元件物件的鍵值對
10.Vue.compile() -- 模板渲染
將一個模板字串編譯成 render 函式。旨在完整版時可用
let res = Vue.compile('<div><span>{{ massage }}</span></div>')
new Vue({
data: {
message: 'hello'
},
render: res.render,
staticRenderFns: res.staticRenderFns
})
以上是官網給的一個小例項。
以後深入理解之後,再回來更新
11.Vue.observable() -- 可用於元件間共享資料
讓一個物件可響應,Vue 內部會用它來處理 data 函式返回的物件。
返回的物件可以直接用於渲染函式和計算屬性內,並且會在發生變更時出發相應的更新。
處理簡單的跨元件共享資料狀態的問題,可以說是個精簡的 vuex
示例
建立store.js
import Vue from 'vue' export const store = Vue.observable({num: 0}) export const mutations = { setNum (num) { store.num = num } }
在元件中使用(所有的說明都沒有舉例子來的實在,理解的更快)
<template> <div> <span>選擇數量</span> <button @click="setNum(num + 1)"> + </button> <span>count</span> <button @click="setNum(num - 1)"> - </button> </div> </template> <script> import { store, mutations } from '@/store/store' export default { name: 'numIndex', computed: { count() { return store.num } }, methods: { setNum: mutations.setNum } } </script>
12.Vue.version()
提供字串形式的 Vue 安裝版本號。這對社群的外掛和元件來說非常有用,你可以根據不同的版本號採取不同的策略
let version = Number(Vue.version.split('.')[0])
if (version == 2) {
} else if (version == 1) {
} else {}
就是獲取當前使用的 vue 版本號,原理就是讀取 package.json 中的 version 欄位
以上就是 vue API 全域性 API 的所有內容,
寶劍鋒從磨礪出,梅花香自苦寒