0%

[Vue] Vue 常用 API

Vue 提供的 API 很多,本篇筆記整理了一些常用的 API 用法,應該算得上實用。

Vue.extend() 及 extends

當數個元件的內容很相近、只有少部分不同時,可以使用 Vue.extend() 建立重複的部分,並在元件中搭配使用 extends 特性來取用 Vue.extend() 的內容。

首先宣告一個 Vue.extend() 方法,參數為一個物件。

1
2
3
var newExtend = Vue.extend({
// 把元件之間相同的內容寫在這裡
});

接著在元件裡面寫入各自不同的內容,並且要新增一個 extends 特性,對應的值為 Vue.extend() 的變數。

1
2
3
4
5
6
7
8
9
var childOne = {
props: ['item'],
extends: newExtend // 以 newExtend 為基底,延伸使用
}
var childTwo = {
props: ['item'],
template: '#row-component-two', // 跟 childOne 元件使用的模板不同,故寫在這裡
extends: newExtend
}

當元件使用 extends 來擴充內容時,若在元件中有新增不同的資料或函式,則 Vue.extend() 的內容與元件中的內容都會存在;若在元件中宣告與 Vue.extend() 相同名稱的資料或函式,則在 Vue.extend() 的內容會被覆寫掉。

參照:Vue 學習筆記-讓你 30 天掌握 Vue-Day 18 : Vue extend

Filter 自訂畫面資料呈現格式

局部:只限個別元件使用

在特定元件內想要套用特定資料格式時,使用局部的 filters 特性。

在雙花括號裡的資料後面,用一個 | 隔開,後面加上自訂的 filters 名稱。filters 可以重複使用,一個元素上也可以套用多個 filters

1
2
3
4
5
6
7
// 元件模板
<script type="text/x-template" id="row-component">
<tr>
<td> {{ item.cash | currency}} </td>
<td> {{ item.icash | currency}} </td>
</tr>
</script>

回到元件,在 data 同層加上 filters 特性,filters 的值為物件型別,裡面的特性就是剛剛在模板中自訂的 filters 名稱,且它會對應一個函式,該函式要回傳「資料轉化為特定格式後的值」。

以下以「將數字加上千分號」為例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 局部註冊的元件
var child = {
props: ['item'],
template: '#row-component',
data: function () {
return {
data: {}
}
},
filters: {
// 參數 n 代表要加上特定格式的資料
currency: function (n) {
return n.toFixed(2).replace(/\d(?=(\d{3})+\.)/g, '$&,');
// 算式是從 stackoverflow 抄來的
}
}
}

一個資料上可以加上多個 filters,只需要重複進行以上步驟即可。

全域:所有元件與根實例共用

如果所有元件及根實例都想要使用同樣的資料格式時,使用 Vue.filter()。同樣的 filters 如果在全域有設定了,元件內就不用再設定。

1
2
3
4
5
6
7
// 結構
Vue.filter('filters 名稱', 處理資料的函式);

// JS
Vue.filter('currency', function (n) {
return n.toFixed(2).replace(/\d(?=(\d{3})+\.)/g, '$&,');
});

$set() 動態寫入資料

向響應式物件中添加一個特性,並確保該新特性同樣是響應式的,並觸發 View 更新。它必須用於向響應式物件上添加新特性,因為 Vue 無法檢測到普通的添加特性。—— Vue 官方文件

有時候我們沒辦法預先定義好資料內容,尤其是需要從 AJAX 抓資料的時候。如果要事後補資料到元件的 data 內且被 Vue 的 setter、getter 監控的話,就要使用 this.$set() 語法。

$set() 有三個參數,第一個是資料要存放的物件(例如 this.data),第二個是資料在存放物件中對應的特性,第三個是要寫入的資料內容。

注意,this.$set() 要寫在元件的 methods 裡面。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 元件
var child = {
props: ['item'],
template: '#row-component',
data: function() {
return {
data: {} // data 留空,用 $set() 動態寫入資料
}
},
methods: {
addData: function() {
this.$set(this.data, 'item', {
name: this.item.name
});
}
},
}

this.$set 等同於 Vue.set 嗎?

mixins 混合其他的元件內容

先宣告一個變數,把多個元件會共用的程式碼以物件的形式存放在該變數裡。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 宣告 mixins 內容
// 第一個 mixins
var mixinFilter = {
template: '#row-component',
filters: {
dollarSign: function (n) {
return `$ ${n}`
},
currency: function (n) {
return n.toFixed(2).replace(/./g, function (c, i, a) {
return i && c !== "." && ((a.length - i) % 3 === 0) ? ',' + c : c;
});
}
}
};

// 第二個 mixins
var mixinMounted = {
mounted() {
console.log('這段是 Mixin 產生');
}
};

在需要使用共用程式碼的元件中,新增 mixins 特性,mixins 的值要以陣列的方式呈現,在該陣列中放入剛剛宣告的變數。

1
2
3
4
5
6
7
8
9
10
// 元件
Vue.component('row-component', {
props: ['item'],
data: function () {
return {
data: {},
}
},
mixins: [ mixinFilter, mixinMounted ],
});

mixins 和 extends 的差異

mixinsextends 兩者都有擴展的作用,只差在 mixins 是陣列,因此可以將不同元件內容分成多個物件後,在需要的元件內使用多個 mixins;而 extends 用於擴展單個元件

當有相同模板要重複使用的時候透過 extend 去實現,而有零散功能需要套用到不同的模板上的時候,則透過 mixin 去達成。

Directive 開發互動 UI

基本語法結構為:Vue.directive('自訂名稱', {鉤子函式})。然後在要使用 directive 的 HTML 元素上,加上 v-自訂名稱

directive 有自己的生命週期,且有 elbindingvnodeoldVnode 等參數可以帶入鉤子函式。在特定生命週期要執行的任務,要寫在鉤子函式內。

至於總共有哪些鉤子函式,請參閱官方文件。

鉤子函式的參數

  • el:代表選取的 DOM,跟使用 querySelector 效果一樣
  • binding:一個物件,裡面包含了 directive 自帶的特性
  • vnode:Vue 的虛擬節點

參照:官方文件-自定義指令

範例:製作表單驗證器

假設我們已經有一個現成的 <input> 了,接著宣告一個 directive,先幫這個 <input> 加上 BS 表單樣式。

1
2
3
4
5
6
Vue.directive('validation', {
bind: function (el, binding, vnode) {
// 鉤子函式通常帶入的參數就這三個
el.className = 'form-control';
}
});

directive 中加入 update() 鉤子,當表單有資料變動時就會觸發。上網查一下驗證 email 格式的正規式,並判斷使用者輸入的值是否符合格式。是的話就加上通過驗證的 class,不是的話就加上未通過的 class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Vue.directive('validation', {
update: function (el, binding, vnode) {
// 可以在這裡取得 input 的 value
var value = el.value;

// Email 格式驗證的正規式
var re = /^(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i;

if (!re.test(value)) {
el.className = 'form-control is-invalid'
} else {
el.className = 'form-control is-valid'
}
},
bind: function (el, binding, vnode) {
// 鉤子函式通常帶入的參數就這三個
el.className = 'form-control';
}
});

表單驗證,完成~

用自訂指令傳入資料

v-directive 可以傳入物件,冒號左邊是屬性,右邊是屬性對應的值。

上一段範例中,.form-control 是寫在 directive 中,但其實它可以用這個方式動態傳入 className

1
v-validation="{ className: 'form-control' }"

接著鉤子函式的 binding 參數就會接收到透過 v-validation 傳入的值(存放在 binding 物件中的 value 特性裡)。

以這邊的例子來說,就是在 binding.value 中可以找到 className: 'form-control'。然後我們再把它指定給 el.className,如此一來 DOM 就會被加上 .form-control

1
2
3
4
5
6
Vue.directive('validation', {
...
bind: function(el, binding, vnode) {
el.className = binding.value.className;
}
});

不知道 v-model 對應的 data 特性時

首先,我們要做的是找出 DOM 所綁定的 v-model 對應哪個 data 特性。關於 Vue 的指令會放在 vnode.data.directives 裡面,而 v-model 的名稱則是放在 vnode.data.directives[i].expression

1
2
3
4
5
6
7
// 以下內容是寫在 bind() 裡

// 在有關 Vue 的指令中尋找 v-model 指令
var currentModel = vnode.data.directives.find(function(item) {
// find() 會回傳第一個符合條件的值
return item.name === 'model';
}).expression; // 取得 v-model 對應的特性

取得 v-model 對應的特性後,可以在 vnode.context 找到該特性的值。

1
2
var value = vnode.context[currentModel];
// 因為 v-model 的值不固定,所以用 [ ] 選取

使用外部載入套件

BootstrapVue 是一個結合 Bootstrap 及 Vue.js 的套件(官網),可以用 CDN 的方式載入,也可以用 Webpack 載入。

如果使用 Vue Cli 就要使用 Webpack 載入方式:

1
2
3
// CLI 版本請加入以下套用 BootstrapVue
import BootstrapVue from 'bootstrap-vue';
Vue.use(BootstrapVue);