給 props 屬性設定多個類型
這個技巧在開發元件的時候用的較多,為了更大的容錯性考慮,同時代碼也更加人性化:
export default {
props: {
width: {
type: [String, Number],
default: '100px'
}
// 或者這樣
// width: [String, Number]
}
}
複制
比如一個
<my-button>
上暴露了一個
width
屬性,我們既可以傳
100px
,也可以傳
100
:
<!-- my-button.vue -->
<template>
<button :style="computedWidth">{{ computedWidth }}</button>
</template>
<script>
export default {
props: {
width: [String, Number]
},
computed: {
computedWidth () {
let o = {}
if (typeof this.width === 'string') o.width = this.width
if (typeof this.width === 'number') o.width = this.width + 'px'
return o
}
}
}
</script>
複制
使用:
<!-- 在其他元件中使用 -->
<template>
<my-button :width="100px"></my-button>
<!-- or -->
<my-button :width="100"></my-button>
</template>
複制
data 初始化
因為
props
要比
data
先完成初始化,是以我們可以利用這一點給
data
初始化一些資料進去,看代碼:
export default {
data () {
return {
buttonSize: this.size
}
},
props: {
size: String
}
}
複制
除了以上,子元件的
data
函數也可以有參數,且該參數是目前執行個體對象。所有我們可以利用這一點做一些自己的判斷。如,改寫上面的代碼:
export default {
data (vm) {
return {
buttonSize: vm.size
}
},
props: {
size: String
}
}
複制
template
我們在做
v-if
判斷的時候,可以把判斷條件放在
template
元件上,最終的渲染結果将不包含
<template>
元素。
<template>
<div class="box">
<template v-if="isVal">
<h2>...</h2>
</template>
<template v-else>
<h2>...</h2>
</template>
</div>
</template>
複制
v-for
也同樣适用。
Lifecycle hook
生命周期鈎子可以是一個數組類型,且數組中的函數會依次執行。
export default {
...
created: [
function one () {
console.log(1)
},
function two () {
console.log(2)
}
]
...
}
複制
沒什麼用,知道就行了。事實上生命周期鈎子還可以作用于 DOM 元素上,利用這一點,我們可以用父元件中的方法來初始化子元件的生命周期鈎子:
<!-- Child.vue -->
<template>
<h3>I'm child!</h3>
</template>
<!-- Parent.vue -->
<template>
<child @hook:created="handleChildCreated"></child>
</template>
<script>
import Child from './child.vue'
export default {
components: [ Child ],
methods: {
handleChildCreated () {
console.log('handle child created...')
}
}
}
</script>
複制
其他鈎子雷同,不再贅述。
v-for 和 v-if 一起使用
由于
v-for
比
v-if
渲染優先級更高,是以有時候可以一起使用。下面兩種常見的情況下會傾向于把
v-for
和
v-if
放在同一個标簽上使用:
- 篩選一些不想顯示的條目
- 為了避免渲染本應該被隐藏的清單
舉個栗子:
<template>
<ul class="items">
<!-- 隻有激活的使用者才可以顯示 -->
<li
v-for="(user, index) in users"
v-if="user.isActive"
:key="user.id">
{{ user.name }}
</li>
</ul>
</template>
複制
關于以上兩點不明白的地方可以參見 Vue 風格指南。
混合
如果好多元件都共用到一些像
props
、
data
、
methods
等,可以單獨抽出來放到
mixins
混合器中。比如,在使用者管理清單中使用。
分頁混合器:
// paging-mixin.vue
export default {
props: {
pageSize: 1,
pageLength: 10,
currentPage: 1
total: 20
},
methods: {
/**
* 上一頁
*/
prevPage (page) {
...
},
/**
* 下一頁
*/
nextPage (page) {
...
}
/**
* 跳轉到目前頁
*/
currentPage (page) {
...
}
}
}
複制
Users.vue:
<template>
<div class="user-model">
<my-table :data="users"></my-table>
<my-paging
:page-length="pageLength"
:page-size="pageSize"
:current-page="currentPage"
:total="total">
</my-paging>
</div>
</template>
<script>
import PagingMixin from '../mixins/paging-mixin.vue'
export default {
mixins: [PagingMixin],
data () {
return {
users: [],
pageLength: 10,
pageSize: 1,
currentPage: 1,
total: 20
}
}
}
</script>
複制
不用每個頁面都寫一遍
props
和
methods
了。
render 函數
下面是一段簡單的 template 模闆代碼:
<template>
<div class="box">
<h2>title</h2>
this is content
</div>
</template>
複制
我們用渲染函數來重寫上面的代碼:
export default {
render (h) {
let _c = h
return _c('div',
{ class: 'box'},
[_c('h2', {}, 'title'), 'this is content'])
}
}
複制
事實上,Vue 會把模闆(template)編譯成渲染函數(render),你可以通過一個線上工具 實時檢視編譯結果。上面的 template 模闆會被編譯成如下渲染函數:
let render = function () {
return _c('div',
{staticClass:"box"},
[_c('h2', [_v("title")]), _v("this is content")])
}
複制
是不是很像? 正如官方說的,渲染函數比 template 更接近編譯器。如果用一個流程圖來解釋的話,大概是這個樣子:
template
↓
預編譯工具(vue-loader + vue-template-compile)
↓
render
↓
resolve vnode
複制
具體參見 Vue聲明周期圖示。
渲染函數用處:
- 開發元件庫,Element 源碼用的都是 render
- 封裝一些高階元件。元件裡面嵌套元件就是高階元件,前提是要滿足元件三要素:
、props
、event
slot
- 用于處理一些複雜的邏輯判斷。如果我們一個元件裡面有很多
判斷的話,用模闆就顯得不合适了,這個時候可以用渲染函數來輕松處理v-if
errorCaptured
捕獲一個來自子孫元件的錯誤時被調用。有時候當我們想收集錯誤日志,卻不想把錯誤暴露到浏覽器控制台的時候,這很有用。下面是個例子:
Child.vue
<template>
<!-- 省略一些無關代碼 -->
</template>
<script>
export default {
mounted () {
// 故意把 console 寫錯
consol.log('這裡會報錯!')
}
}
</script>
複制代碼
複制
Parent.vue
<template>
<child></child>
</template>
<script>
import Child from './Child.vue'
export default {
components: [ Child ],
/**
* 收到三個參數:
* 錯誤對象、發生錯誤的元件執行個體
* 以及一個包含錯誤來源資訊的字元串。
* 此鈎子可以傳回 false 以阻止該錯誤繼續向上傳播。
*/
errorCaptured (err, vm, info) {
console.log(err)
// -> ReferenceError: consle is not defined ...
console.log(vm)
// -> {_uid: 1, _isVue: true, $options: {…}, _renderProxy: o, _self: o,…}
console.log(info)
// -> `mounted hook`
// 告訴我們這個錯誤是在 vm 元件中的 mounted 鈎子中發生的
// 阻止該錯誤繼續向上傳播
return false
}
}
</script>
複制
關于 errorCaptured 更多說明,請移步官網-> 。
v-once
通過
v-once
建立低開銷的靜态元件。渲染普通的 HTML 元素在 Vue 中是非常快速的,但有的時候你可能有一個元件,這個元件包含了大量靜态内容。在這種情況下,你可以在根元素上添加
v-once
特性以確定這些内容隻計算一次然後緩存起來,就像這樣:
<template>
<div class="box" v-once>
<h2> 使用者協定 </h2>
... a lot of static content ...
</div>
</template>
複制
隻渲染元素群組件一次。随後的重新渲染,元素/元件及其所有的子節點将被視為靜态内容并跳過。這可以用于優化更新性能。關于
v-once
更多介紹,請移步官網->。
slot-scope
作用域插槽。
版本以前叫
scope
,之後的版本用
slot-scope
将其代替。除了 scope 隻可以用于
<template>
元素,其它和
slot-scope
都相同。
用過 Element 元件的同學都知道,當我們在使用
<el-table>
的時候會看到如下代碼:
[email protected] 的版本:
<el-table-column label="操作">
<template scope="scope">
<el-button
size="small"
@click="handleEdit(scope.$index, scope.row)">編輯</el-button>
<el-button
size="small"
type="danger"
@click="handleDelete(scope.$index, scope.row)">删除</el-button>
</template>
</el-table-column>
複制
但在 2.0 之後的版本替換成了
slot-scope
。
<el-table-column label="操作">
<template slot-scope="scope">
<el-button
size="mini"
@click="handleEdit(scope.$index, scope.row)">編輯</el-button>
<el-button
size="mini"
type="danger"
@click="handleDelete(scope.$index, scope.row)">删除</el-button>
</template>
</el-table-column>
複制
說白了,
slot-scope
相當于函數的回調,我把結果給你,你想怎麼處理就怎麼處理,一切随你:
function getUserById (url, data, callback) {
$.ajax({
url,
data,
success: function (result) {
callback(result)
}
})
}
// 使用
getUserById('/users', { id: 1 }, function (response) {
// 拿到資料并開始處理自己的頁面邏輯
})
複制
下面我們來簡單模拟下
<el-table>
元件内部是怎麼使用
slot-scope
的,看代碼:
模拟的
<el-table>
元件:
// 定義模闆
let template = `
<ul class="table">
<li v-for="(item, index) in data" :key="index">
<!-- 我希望資料由調用者自己處理 -->
<!-- 'row' 相當于變量名,随便定義,比如 aaa,bbb 啥的 -->
<slot :row="item">
<!-- 當使用者什麼都沒寫的時候,預設值才會顯示-->
{{ item.name }}
</slot>
</li>
</ul>
`
Vue.component('el-table', {
template,
props: {
data: Array,
default: []
}
})
複制
在你需要的地方使用
<el-table>
元件:
HTML:
<div id="app">
<el-table :data="userData">
<!-- 使用的時候可以用 template -->
<!-- `scope` 也是個變量名,随便命名不是固定的,比如 foo, bar -->
<template slot-scope="scope">
<!-- 其中 `scope.row` 中的 row 就是我們上邊定義的變量啦-->
<!-- `scope.row`傳回的是 `item` 對象 -->
<template v-if="scope.row.isActived">
<span class="red">{{ scope.row.name }}</span>
</template>
<template v-else>
{{ scope.row.name }}
</template>
</template>
</el-table>
</div>
複制
JavaScript:
new Vue({
el: '#app',
data: {
userData: [
{id: 1, name: '張三', isActived: false},
{id: 2, name: '李四', isActived: false},
{id: 1, name: '王五', isActived: true},
{id: 1, name: '趙六', isActived: false},
]
}
})
複制
CSS:
.red {
color: red
}
複制
你可以狠狠的戳這裡檢視上面的效果!最後,我們再使用 render 函數來重構上面的代碼:
JavaScript:
// `<el-table>` 元件
Vue.component('el-table', {
name: 'ElTable',
render: function (h) {
return h('div', {
class: 'el-table'
}, this.$slots.default)
},
props: {
data: Array
}
})
// `<el-table-column>`
Vue.component('el-table-column', {
name: 'ElTableColumn',
render: function (h) {
// 定義一個存放 li 元素的數組
let lis = [],
// 擷取父元件中的 data 數組
data = this.$parent.data
// 周遊數組,也就是上面的 `v-for`,生成 `<li>` 标簽
// `this.$scopedSlots.default` 擷取的就是上面 slot-scope 作用于插槽的部分,
// 并把 `{ row: item }` 傳給上面的 `scope` 變量
data.forEach((item, index) => {
let liEl = h('li', {
key: item.id
}, [ this.$scopedSlots.default({ row: item }) ])
// 把生成的 li 标簽存到數組
lis.push(liEl)
})
return h('ul', {
class: 'el-table-column'
}, lis)
}
})
複制
在你的頁面這樣來使用:
HTMl:
<div id="app">
<el-table :data="list">
<el-table-column>
<template slot-scope="scope">
<span class="red" v-if="scope.row.actived">{{ scope.row.name }}</span>
<span v-else>{{ scope.row.name }}</span>
</template>
</el-table-column>
</el-table>
</div>
複制
JavaScript:
new Vue({
el: '#app',
data: {
list: [
{ id: 1, name: '張三', actived: false },
{ id: 1, name: '李四', actived: false },
{ id: 1, name: '王五', actived: true },
{ id: 1, name: '趙六', actived: false },
]
}
})
複制
疑問:我們完全可以在
<li>
中進行邏輯判斷,為什麼還要放到外面進行處理呢? 因為有時候我們用的不是自己開發的元件,比如上面的
<el-table>
,是以就有必要這麼做了。
作者:gongph
連結:https://juejin.im/post/5be01d0ce51d450700084925
來源:掘金
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。