此文源碼案例:歡迎Star
目錄
Vue 組件的開發有幾種方式:單文件組件,使用 render 函數渲染,使用 template。
在大多數的情況下,Vue 可以使用單文件/template 的方式來創建頁面;然而在有一些情況我們需要使用 JavaScript 的編程能力,比如使用第三方框架時,想要自定義某個功能;這個時候就可以使用到 render 函數。
本文將使用 iView table 爲例,通過 render 函數添加可搜索的表頭篩選。
一、Render 函數參數詳解
//一個簡單的例子:渲染一個p標籤,內容爲 '我是p標籤的內容'
new Vue({
render: createElement => createElement("p", "我是p標籤的內容")
});
其實 createElement()還有更強大的參數:
// @returns {VNode}
createElement(
// {String | Object | Function}
// 一個 HTML 標籤字符串,組件選項對象,或者
// 解析上述任何一種的一個 async 異步函數。必需參數。
"div",
// {Object}
// 一個包含模板相關屬性的數據對象,
// 你可以在 template 中使用這些特性。可選參數。
{
// (詳情見下一節)
},
// {String | Array}
// 子虛擬節點 (VNodes),由 `createElement()` 構建而成,
// 也可以使用字符串來生成“文本虛擬節點”。可選參數。
[
"先寫一些文字",
createElement("h1", "一則頭條"),
createElement(MyComponent, {
props: {
someProp: "foobar"
}
})
]
);
createElement(obj,{},[])
參數詳解:
- 第一個參數爲渲染成哪個節點,接受 String,Object,Function 三種類型;
- 如果是 String,比如是 div,那麼表示此標籤將會渲染成 div 標籤;String 渲染成普通的 html 標籤
- 如果是 Object,比如是一個 Vue 的組件:TableFilter,那麼表示此標籤將會渲染一個組件。通常我們在單文件組件中使用的時候是 import {Table} from “iview”;然後在 template 中引用此標籤;而使用 render 則需要使用 createElement 方式創建一個。
- 如果是 Function,則可以根據自己的業務邏輯動態覺得是渲染成普通的 html 標籤還是 Vue 組件。
- 第二個參數接受 一個對象{}類型的數據。其主要作用類似於組件中對某一個節點設置各種 bind 屬性:設置樣式 style,設置事件 on,設置類 class,設置自定義的命令,設置普通的 html 屬性,設置傳遞參數 props 等等。
有一點要注意:正如在模板語法中,v-bind:class 和 v-bind:style,會被特別對待一樣,在 VNode 數據對象中,下列屬性名是級別最高的字段。該對象也允許你綁定普通的 HTML 特性,就像 DOM 屬性一樣,比如 innerHTML (這會取代 v-html 指令)。
{
// 和`v-bind:class`一樣的 API
// 接收一個字符串、對象或字符串和對象組成的數組
'class': {
foo: true,
bar: false
},
// 和`v-bind:style`一樣的 API
// 接收一個字符串、對象或對象組成的數組
style: {
color: 'red',
fontSize: '14px'
},
// 普通的 HTML 特性
attrs: {
id: 'foo'
},
// 組件 props
props: {
myProp: 'bar'
},
// DOM 屬性
domProps: {
innerHTML: 'baz'
},
// 事件監聽器基於 `on`,當子組件使用$emit()方式發生,使用on接收
// 所以不再支持如 `v-on:keyup.enter` 修飾器
// 需要手動匹配 keyCode。
on: {
click: this.clickHandler
},
// 僅用於組件,用於監聽原生事件,而不是組件內部使用
// `vm.$emit` 觸發的事件。
nativeOn: {
click: this.nativeClickHandler
},
// 自定義指令。注意,你無法對 `binding` 中的 `oldValue`
// 賦值,因爲 Vue 已經自動爲你進行了同步。
directives: [
{
name: 'my-custom-directive',
value: '2',
expression: '1 + 1',
arg: 'foo',
modifiers: {
bar: true
}
}
],
// 作用域插槽格式
// { name: props => VNode | Array<VNode> }
scopedSlots: {
default: props => createElement('span', props.text)
},
// 如果組件是其他組件的子組件,需爲插槽指定名稱
slot: 'name-of-slot',
// 其他特殊頂層屬性
key: 'myKey',
ref: 'myRef',
// 如果你在渲染函數中向多個元素都應用了相同的 ref 名,
// 那麼 `$refs.myRef` 會變成一個數組。
refInFor: true
}
你會發現使用 render 函數沒有與 v-model 的直接對應 - 你必須自己實現相應的邏輯:比如
props: ['value'],
render: function (createElement) {
var self = this
return createElement('input', {
domProps: {
value: self.value
},
on: {
input: function (event) {
self.$emit('input', event.target.value)
}
}
})
}
- 第三個參數爲列表類型的數據,表示當前渲染組件的有哪些子組件。
render(createElement=>
return createElement(
'div',
{
},
// {String | Array}
// 子虛擬節點 (VNodes),由 `createElement()` 構建而成,
// 也可以使用字符串來生成“文本虛擬節點”。可選參數。
[//
'先寫一些文字',
createElement('h1', '一則頭條'),
createElement(MyComponent, {
props: {
someProp: 'foobar'
}
})
]
))
注意:子組件中的每一項(VNodes)都必須是唯一的;意味着,下面的 render function 是無效的:
render: function (createElement) {
var myParagraphVNode = createElement('p', 'hi')
return createElement('div', [
// 錯誤-重複的 VNodes
myParagraphVNode, myParagraphVNode
])
}
二、樣例:如何給表格組件添加表頭篩選
效果圖:
iview的默認table組件不支持 表頭輸入框篩選,官方地址
此處默認您有了一定的vue開發基礎。
套用iview官方的例子:
//顯示錶格的例子
<template>
<Table border :columns="columns7" :data="data6"></Table>
</template>
<script>
import { Table ,Button,Icon,Modal} from "iview";
import Vue from "vue";
export default {
components: {
Table
},
data() {
return {
columns7: [
{
title: "Name",
key: "name",
//使用render函數自定義列顯示效果:文本加粗
render: (h, params) => {
return h("div", [//使用render渲染一個div標籤
h(Icon, {//使用render渲染一個iview的組件
props: {//傳遞參數
type: "person"
}
}),
h("strong", params.row.name)//文字加粗
]);
}
},
{
title: "Age",
key: "age"
},
{
title: "Address",
key: "address"
},
{
title: "Action",
key: "action",
width: 150,
align: "center",
render: (h, params) => {
return h("div", [//渲染一個div標籤
h(
Button,//在div標籤下渲染一個iview組件
{
props: {//傳遞參數
type: "primary",
size: "small"
},
style: {//設置樣式
marginRight: "5px"
},
on: {//監聽$emit事件
click: () => {
this.show(params.index);
}
}
},
"View"
),
h(
Button,
{
props: {
type: "error",
size: "small"
},
on: {
click: () => {
this.remove(params.index);
}
}
},
"Delete"
)
]);
}
}
],
data6: [
{
name: "John Brown",
age: 18,
address: "New York No. 1 Lake Park"
},
{
name: "Jim Green",
age: 24,
address: "London No. 1 Lake Park"
},
{
name: "Joe Black",
age: 30,
address: "Sydney No. 1 Lake Park"
},
{
name: "Jon Snow",
age: 26,
address: "Ottawa No. 2 Lake Park"
}
]
};
},
methods: {
show(index) {
this.$Modal.info({
title: "User Info",
content: `Name:${this.data6[index].name}<br>Age:${
this.data6[index].age
}<br>Address:${this.data6[index].address}`
});
},
remove(index) {
this.data6.splice(index, 1);
}
},
mounted(){
//modal注入
Vue.prototype.$Modal=Modal;
}
};
</script>
由於table組件表頭篩選不支持輸入框篩選,那麼我們就必須的自己繪製。
思路如下:
- 找到表頭所在的節點
- 在表頭節點後添加一個自定義篩選的div節點;
- 使用render函數渲染一個下拉輸入的單文件組件
mounted(){
//modal注入
Vue.prototype.$Modal=Modal;
//等dom元素渲染完成之後渲染篩選
this.$nextTick(()=>{
this.renderHeaderFilter();
})
}
methods:{
//添加頭部篩選
renderHeaderFilter(){
let allHeader =document.querySelectorAll(".ivu-table-header .ivu-table-cell");
console.log(allHeader);
allHeader.forEach((element)=>{
let createNew=document.createElement("div");
createNew.classList.add("vue-header-filter");
element.appendChild(createNew);
new Vue({
render(h){
return h(TableHeaderFilter,{
props:{}
})
}
}).$mount(createNew);
})
}
}
最後實現的效果爲:
此文源碼案例:歡迎Star