用Vue已經有2年多了,用本文詳解講解Vue組件開發過程當中的方方面面,供你們學習,若是以爲還能夠,點個贊收藏一下,持續更新中。html
給組件命名有兩種方式,一種是使用鏈式命名my-component
,一種是使用大駝峯命名MyComponent
,vue
在字符串模板中<my-component></my-component>
和 <MyComponent></MyComponent>
均可以使用,ios
在非字符串模板中最好使用<MyComponent></MyComponent>
,由於要遵循 W3C 規範中的自定義組件名 (字母全小寫且必須包含一個連字符),避免和當前以及將來的 HTML 元素相沖突。axios
Vue.component('my-component', {
props:{
title:{
type: String,
default:'全局組件',
}
},
data(){
return {}
},
created(){},
mounted(){},
methods:{
handleClick(){
alert(this.title)
}
},
template: '<h3 @click="handleClick">{{ title }}</h3>',
})
複製代碼
在項目中static文件中創建my_component.html文件,文件內容以下數組
<h3 @click="handleClick">{{ title }}</h3>
複製代碼
Vue.component('my-component', (resolve, reject) =>{
// 能夠請求一個html文件,既然存放模板仍是html文件存放比較好
axios.get("../static/my_component.html").then(res =>{
resolve({
template: res,
props: {
title: {
type: String,
default: '全局組件',
}
},
methods: {
handleClick() {
alert(this.title)
}
},
})
});
});
複製代碼
同步註冊瀏覽器
import myComponent from './my_component';
export default {
components: {
myComponent,
},
}
複製代碼
異步註冊(懶加載)bash
export default{
components:{
myComponent: resolve => require(['./my_component'],resolve)
}
}
複製代碼
在非字符串模板中,若是prop是用小駝峯方式命名,在模板中要使用其等價的鏈式方式命名。iview
在字符串模板中就不要這麼處理了。dom
index.vue文件異步
<template>
<myComponent :my-title="my_title"></myComponent>
</template>
<script>
export default{
data(){
return{
my_title:"個人組件"
}
},
components:{
myComponent:resolve => require(['./my_component'],resolve)
}
}
</script>
複製代碼
my_component.vue文件
<template>
<div>
<h1>{{myTitle}}</h1>
</div>
</template>
<script>
export default{
props:{
myTitle:{
type:String,
default:'',
}
},
data(){
return{}
},
}
</script>
複製代碼
由於HTML(非字符串模板)中的特性名是大小寫不敏感的,因此瀏覽器會把全部大寫字符解釋爲小寫字符。
<myComponent my-title="個人組件"></myComponent>
複製代碼
<myComponent :num="100"></myComponent>
<myComponent :isload="true"></myComponent>
複製代碼
不能,防止從子組件意外改變父級組件的狀態。
在data中定義一個值,並將prop值賦值給它,若是prop值是對象和數組時,賦值時要深拷貝一下。
<script>
export default{
props:{
myTitle:{
type:String,
default:'',
},
myInfo:{
type:Object,
default(){
return:{}
}
}
},
//this.deepClone爲自定義的深拷貝方法
data(){
return{
title:this.myTitle,
info:this.deepClone(this.myInfo),
}
},
}
</script>
複製代碼
2.若是prop以一種原始的值傳入且須要進行轉換。要使用這個 prop 的值來定義一個計算屬性。
<script>
export default{
props:{
myAchievement:{
type:Number,
default:0,
},
},
data(){
return{}
},
computed: {
result: function () {
return this.myAchievement*0.7+12;
}
}
}
</script>
複製代碼
String、Number、Boolean、Array、Object、Date、Function、Symbol。 此外還能夠是一個自定義的構造函數Personnel
,而且經過 instanceof 來驗證propwokrer
的值是不是經過這個自定義的構造函數建立的。
function Personnel(name,age){
this.name = name;
this.age = age;
}
export default {
props:{
wokrer:Personnel
}
}
複製代碼
export default {
props:{
propA:String,
propB:{
type:Number,
},
propC:Boolean,
}
}
複製代碼
export default {
props:{
propA:[String,Number],
propB:{
type:[String,Number]
}
}
}
複製代碼
export default{
props:{
propA:{
type: String,
required: true,
}
}
}
複製代碼
export default{
props:{
propA:{
type:Object,
default(){
return {
a: 1,
}
}
},
propB:{
type:Array,
default(){
return [1,2,3]
}
}
}
}
複製代碼
export default{
props:{
propA:{
validator(val){
return 0 < val < 18
}
}
}
}
複製代碼
不會,由於prop會在一個組件實例建立以前進行驗證,因此data和computed在default或validator函數中是不可用的。
使用不帶參數的 v-bind,例:對於一個給定的對象 post
post: {
id: 1,
title: 'My Journey with Vue'
}
複製代碼
<myComponent v-bind="post"></myComponent>
複製代碼
至關
<myComponent :id="post.id" :title="post.title"></myComponent>
複製代碼
先舉個例子,用v-model
來控制一個組件的顯示隱藏
my_component.vue
<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>
複製代碼
<template>
<div>
<myComponent v-model="value"></myComponent>
<button @click="value=true">顯示</button>
</div>
</template>
<script>
export default{
data(){
return{
value:false,
}
},
components:{
myComponent:resolve =>require(['./my_component'],resolve),
}
}
</script>
複製代碼
那爲何這麼寫?不明白的能夠看的不是很清楚,那麼在看下面代碼就清楚。
<template>
<div>
<myComponent :value="value" @input="value=$event"></myComponent>
<button @click="value=true">顯示</button>
</div>
</template>
複製代碼
在父組件中用$event
訪問經過$emit
拋出的值。
這麼寫是否是很清楚了,組件上的v-model='value'
至關 :value="value" @input="value=$event"
。
再舉個例子
<template>
<div>
{{value}}
<myInput v-model="value"></myInput>
<!-- 等價於 -->
<myInput :value="value" @input="value=$event"></myInput>
</div>
</template>
<script>
export default {
data() {
return {
value: '',
}
},
components: {
myInput: resolve => require(['./my_input'], resolve),
}
}
</script>
複製代碼
my_input.vue
<template>
<input :value="value" @input="$emit('input',$event.target.value)"/>
</template>
<script>
export default{
props:['value'],
data(){
return{}
},
}
</script>
複製代碼
從以上代碼能夠看出,組件上的v-model='value'
至關 :value="value" @input="value=$event"
,
其組件的自定義事件必須是input
。
既而後能夠實現v-model,那麼model選項是用來幹嗎的,
由於一個組件上的v-model 默認會利用名爲value的prop和名爲input的事件,
可是像單選框、複選框等類型的輸入控件可能會將value 特性用於不一樣的目的,
model 選項能夠用來避免這樣的衝突。
那麼上面的例子也能夠這麼實現
my_input.vue
<template>
<input :value="val" @input="$emit('change',$event.target.value)"/>
</template>
<script>
export default{
model:{
prop:'val',
event:'change'
},
props:['val'],
data(){
return{}
},
}
</script>
複製代碼
<myComponent>
經過插槽傳進去的內容
</myComponent>
複製代碼
<template>
<div>
<h1>個人組件</h1>
<p>
<slot></slot>
</p>
</div>
</template>
複製代碼
頁面渲染出
個人組件
經過插槽傳進去的內容
複製代碼
若是 <myComponent>
沒有包含一個 <slot></slot>
元素,則該組件起始標籤和結束標籤之間的任何內容都會被拋棄。
<slot>默認內容</slot>
複製代碼
<template>
<div>
<h2>默認插槽</h2>
<slot>默認內容</slot>
<h2>頭部插槽</h2>
<slot name="header"></slot>
<h2>側邊欄插槽</h2>
<slot name="sider"></slot>
</div>
</template>
複製代碼
<template>
<div>
<myComponent>
我是默認插槽
<template v-slot:header>我是頭部插槽</template>
<template #sider>
我是側邊欄插槽
</template>
</myComponent>
</div>
</template>
複製代碼
v-slot
指令的縮寫是 #
,v-slot
只能添加在<template></template>
上
<slot></slot>
上面沒有name屬性,會自動渲染成<slot name="default"></slot>
,
也能夠這麼調用<template v-slot:default></template>
在實際項目中,咱們要獲取子組件的數據在父組件中渲染插槽的內容。怎麼辦?
首先要在子組件中給slot
綁定一個子組件的data中的一個對象childrenData,
例:<slot :toParent="childrenData"></slot>
topParent是給父組件中調用的,以上稱爲插槽prop。
而後在父組件中這樣調用 <template v-slot:default="slotProps">{{slotProps.toParent}}</template>
,
其中slotProps是表明插槽prop的集合,其命名能夠隨便取的。此時slotProps.toParent的值
就是childrenData的值
下面是完整例子
<template>
<div>
<h2>默認插槽</h2>
<slot :toParent="childrenData" :toParent2="childrenData2">
{{childrenData.data1}}
{{childrenData2.data1}}
</slot>
<h2>頭部插槽</h2>
<slot name="header" :headerData="headerData">
{{headerData.data1}}
</slot>
</div>
</template>
<script>
export default{
data(){
return{
childrenData:{
data1:'子組件數據一',
data2:'子組件數據二',
},
childrenData2:{
data1:'子組件數據三',
data2:'子組件數據四',
},
headerData:{
data1:'子組件頭部數據一',
data2:'子組件頭部數據二',
},
}
},
}
</script>
複製代碼
<template>
<div>
<myComponent>
<template v-slot:default="slotProps">
{{slotProps.toParent.data2}}
{{slotProps.toParent2.data2}}
</template>
<template v-slot:header="headerProps">
{{headerProps.headerData.data2}}
</template>
</myComponent>
</div>
</template>
複製代碼
當有子組件slot上有多個插槽prop時,父組件調用時候能夠ES6對象解構的方法,例:
<template>
<div>
<myComponent>
<template v-slot:default="{toParent,toParent2}">
{{toParent.data2}}
{{toParent2.data2}}
</template>
<template v-slot:header="{headerData}">
{{headerData.data2}}
</template>
</myComponent>
</div>
</template>
複製代碼
也能夠給子組件slot上綁定的值從新命名,例:
<template>
<div>
<myComponent>
<template #default="{toParent:a,toParent2:b}">
{{a.data2}}
{{b.data2}}
</template>
<template #header="{headerData:c}">
{{c.data2}}
</template>
</myComponent>
</div>
</template>
複製代碼
在組件標籤上添加的屬性,沒有在組件中props中定義,這些屬性會被添加到這個組件的根元素上,這就是組件的非Prop特性,例:
<template>
<div data="">
<h2>個人組件</h2>
</div>
</template>
複製代碼
<template>
<div>
<myComponent data="noProp"></myComponent>
</div>
</template>
複製代碼
按F12打開調試工具能夠看到
若是組件的根節點已有data="children"
,那麼在組件標籤再定義data="noProp"
,這樣根節點的data屬性就會被替換。
按F12打開調試工具能夠看到
若是組件的根節點上有Class、Style屬性,那麼在組件標籤再定義Class、Style,這樣根節點的Class、Style是把二者合併後在賦值。例:
<template>
<div class="children" style="font-size:16px;">
<h2>個人組件</h2>
</div>
</template>
複製代碼
<template>
<div>
<myComponent class="parent" style="font-size:18px;color:red">
</myComponent>
</div>
</template>
複製代碼
按F12打開調試工具能夠看到
用實例屬性$attrs,包含了組件標籤上不做爲 prop被識別(且獲取)的特性綁定(class 和 style 除外)。
在寫基礎組件中常常用到,下面舉個基礎輸入框組件爲例子:
<template>
<label>
{{ label }}
<input
v-bind="$attrs"
:value="value"
@input="$emit('input', $event.target.value)"
>
</label>
</template>
<script>
export default {
inheritAttrs: false,
props: ['label', 'value'],
data(){
return{}
},
mounted(){
console.log(this.$attrs)
}
}
</script>
複製代碼
<template>
<baseIinput class="input" style="color:red" v-model="val" placeholder="請輸入" label="基礎輸入框"></baseInput>
</template>
<script>
export default {
data() {
return {
val:'',
};
},
components:{
baseInput:resolve => require(['./base_input.vue'],resolve)
}
};
</script>
複製代碼
例子中。mounted鉤子函數打印出來是{placeholder:'請輸入'}
,用v-bind
指令將 $attrs
綁定到要繼承的元素上便可繼承。
組件中的inheritAttrs選項爲false時禁止組件的根節點繼承非Prop特性,但不影響Class、Style
當inheritAttrs爲true時,不由用用v-on
的 .native
修飾符,來實現。例:監聽輸入框獲取焦點事件
<baseInput @focus.native="onFocus"></baseInput>
複製代碼
可是你會發現,監聽失敗,也不產生任何報錯。
這是由於這個組件的根元素是<label></label>
,而這標籤是沒有focus
這個事件。
你能夠用實例屬性$listeners
,其包含做用在這個組件上的全部監聽器,配合v-on="$listeners"
將全部的事件監聽器指向組件內部的任一個元素,若是改元素上還有其餘監聽器,能夠用computed屬性來合併監聽器。
下面請看實例:
<template>
<label>
{{ label }}
<input v-bind="$attrs" v-bind:value="value" v-on="inputListeners">
</label>
</template>
<script>
export default {
props: ['label', 'value'],
data() {
return {}
},
computed: {
inputListeners: function(){
return Object.assign(
{},
// 組件標籤上添加全部的監聽器
this.$listeners,
//組件內部原來的監聽器
{
input:(event) =>{
this.$emit('input',event.target.value)
}
}
)
}
}
}
</script>
複製代碼
<template>
<div>
{{val}}
<baseInput v-model="val" @focus="onFocus"></baseInput>
</div>
</template>
<script>
export default {
data() {
return {
val:'',
}
},
components: {
baseInput: resolve => require(['./base_input'], resolve),
},
methods:{
onFocus(){
console.log('獲取到焦點')
}
}
}
</script>
複製代碼
component
標籤和 is
特殊特性在組件上的應用<component :is="componentName"></component>
複製代碼
componentName
能夠是在本頁面已經註冊的局部組件名和全局組件名,也能夠是一個組件的選項對象。
當控制componentName
改變時就能夠動態切換選擇組件。
有些HTML元素,諸如 <ul>、<ol>、<table> 和 <select>
,對於哪些元素能夠出如今其內部是有嚴格限制的。而有些元素,諸如 <li>、<tr> 和 <option>
,只能出如今其它某些特定的元素內部。
<ul>
<card-list></card-list>
</ul>
複製代碼
因此上面<card-list></card-list>
會被做爲無效的內容提高到外部,並致使最終渲染結果出錯。應該這麼寫
<ul>
<li is="cardList"></li>
</ul>
複製代碼
遞歸引用能夠理解爲組件調用自身,在開發多級菜單組件時就會用到,調用前要先設置組件的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>
複製代碼
經過props來通訊
經過在父組件上自定義一個監聽事件<myComponent @diy="handleDiy"></myComponent>
在子組件用this.$emit('diy',data)
來觸發這個diy
事件,其中data爲子組件向父組件通訊的數據, 在父組件中監聽diy
個事件時,能夠經過$event
訪問data這個值。
<baseInput ref="myInput"></<baseInput>
this.$refs.myInput.focus()
this.$refs.myInput.value
用this.$parent
來訪問
上面寫到,子組件能夠用this.$parent
訪問父組件的實例,孫子組件能夠用this.$parent.$parent
來訪問,那曾孫子組件呢,是否是要寫不少個$parent
。
若是父組件下不少個子孫組件都要用祖先組件中的一個數據,這時候就要用到組件的依賴注入。
依賴注入,是經過provide
inject
這兩選項實現,provide
是寫在祖先組件中,inject
是寫在須要注入的子孫組件中。
provide
選項應該是一個對象或返回一個對象的函數.
inject
選項應該是一個字符串數組或一個對象
對象的key是本地的綁定名,value是provide
的 key (字符串或 Symbol)。
value也能夠是個一個對象,該對象的:
from 屬性是provide
的 key (字符串或 Symbol)
default屬性是在form定義的key在provide
中未定義,使用的默認值。
祖先組件
<template>
<div>
<son></son>
</div>
</template>
<script>
export default{
data(){
return {}
},
provide(){
return{
top:20,
}
},
components:{
son:resolve => require(['./son.vue'],resolve)
}
}
</script>
複製代碼
son兒子組件
<template>
<div>
<grandson></grandson>
</div>
</template>
<script>
export default{
data(){
return {}
},
inject:['top'],
components:{
grandson:resolve => require(['./grandson.vue'],resolve)
},
mounted(){
console.log(this.top)//20
}
}
</script>
複製代碼
grandson兒子組件
<template>
<div></div>
</template>
<script>
export default{
data(){
return {}
},
inject:{
top:{
from:'top',
default:'30'
},
bottom:{
from:'bottom',
default:'30'
}
},
components:{
grandson:resolve => require(['./grandson.vue'],resolve)
},
mounted(){
console.log(this.top)//20
console.log(this.bottom)//30
}
}
</script>
複製代碼
一般在子組件中是不容許對props中的值進行修改,可是有些狀況下,要對一個 prop 進行「雙向綁定」。真正的雙向綁定會帶來維護上的問題,由於子組件能夠修改父組件,且在父組件和子組件都沒有明顯的改動來源。
這時候咱們能夠用.sync修飾符來進行「雙向綁定」,其原理是經過update:myPropName 的模式觸發事件。
<template>
<div>
<button @click="show=true">顯示</button>
<myComponent :show="show" v-on:update:show="show = $event"></myComponent>
</div>
</template>
<script>
export default{
data(){
return{
show:false,
}
},
components:{
myComponent:resolve=>require(['./my_conponent'],resolve)
}
}
</script>
複製代碼
<template>
<div v-show="show">
<button @click="hide">隱藏</button>
</div>
</template>
<script>
export default{
props:{
show:{
type:Boolean,
default:false,
}
},
data(){
return{}
},
methods:{
hide(){
this.$emit('update:show',false)
}
}
}
</script>
複製代碼
爲了方便起見,咱們爲這種模式提供一個縮寫,即 .sync
修飾符:
<my-component :show.sync="show"></my-component>
複製代碼
注意帶有 .sync 修飾符的 v-bind 不能和表達式一塊兒使用,:show.sync="name=='小明'? true : false"
是無效的
將 v-bind.sync 用在一個對象上,例:v-bind.sync='{ title: doc.title }'
也是無效的。
<myComponent
:show.sync="info.show"
:name.sync="info.name"
:age.sync="info.age"
></myComponent>
複製代碼
若是遇到上述狀況能夠怎麼這麼寫
<myComponent v-bind.sync="info"></myComponent>
複製代碼
這樣會把 info 對象中的每個屬性 (如 show) 都做爲一個獨立的 prop 傳進去,而後各自添加用於更新的 v-on 監聽器。
render選項的值是一個函數,一般叫渲染函數。
該函數接收一個createElement的方法做爲第一參數來建立VNode(虛擬DOM),並返回。
先舉個全局組件的例子
Vue.component('myComponent', {
render: function (createElement) {
return createElement(
'h1',
this.title
)
},
props: {
title: {
type: String,
default: '我是渲染出來的組件'
}
}
})
複製代碼
以上組件調用後渲染出<h1>我是渲染出來的組件</h1>
在單頁面組件中使用要去掉<template></template>
標籤
<script>
export default {
props: {
title: {
type: String,
default: "我是渲染出來的組件"
}
},
data() {
return {};
},
render: function(createElement) {
return createElement("h1", this.title);
},
};
</script>
複製代碼
以上組件被調用後也渲染出<h1>我是渲染出來的組件</h1>
接收一個String類型的元素標籤如'div'
,或者接收一個Function類型的函數返回元素標籤;
總之第一個參數是必填項,接收一個元素標籤。
class項,綁定ClassName,對應:class
,值爲一個字符串、對象或字符串和對象組成的數組,例:
值爲對象:
data(){
classA:true
},
render: function (createElement) {
return createElement('div',
{
class:{'classA':this.classA},
},
'我是渲染出來的組件',
);
},
複製代碼
值爲字符串:
render: function (createElement) {
return createElement('div',
{
class:'classA',
},
'我是渲染出來的組件',
);
},
複製代碼
值爲字符串和對象組成的數組
data() {
return {
classB:true
};
},
render: function (createElement) {
return createElement('div',
{
class:['classA',{'classB':this.classB}],
},
'我是渲染出來的組件',
);
},
複製代碼
style項,綁定style,對應:style
,接受一個字符串、對象,或對象組成的數組,例:
值爲字符串
render: function (createElement) {
return createElement('div',
{
style:'color:red'
},
'我是渲染出來的組件',
);
},
複製代碼
值爲對象
render: function (createElement) {
return createElement('div',
{
style:{
color:'red',
fontSize: '14px'
}
},
'我是渲染出來的組件',
);
},
複製代碼
值爲對象組成的數組
render: function (createElement) {
return createElement('div',
{
style:[
{
color:'red',
},
{
fontSize: '14px'
}
]
},
'我是渲染出來的組件',
);
},
複製代碼
attrs項,普通的HTML特性,如id、title特性,例:
render: function (createElement) {
return createElement('div',
{
attrs:{
id:'idA',
title:'我是渲染出來的組件'
}
},
'我是渲染出來的組件',
);
},
複製代碼
渲染出<div id="idA" title="我是渲染出來的組件">我是渲染出來的組件</div>
domProps項,DOM屬性,如innerHTML,列:
render: function (createElement) {
return createElement('div',
{
domProps: {
innerHTML: 'DOM屬性內容'
}
},
'我是渲染出來的組件',
);
},
複製代碼
渲染出<div>DOM屬性內容</div>
我是渲染出來的組件
props項,用法和組件的props同樣;
on項,事件監聽器,其它用法和v-on
同樣,例:
render: function (createElement) {
return createElement('div',
{
on: {
click: function(e){
console.log(e)
},
}
},
'我是渲染出來的組件',
);
},
複製代碼
nativeOn項,只用於第一個參數爲組件標籤時,用來監聽組件內根節點上的事件,列:
components:{
myComponent:resolve =>require(['./my_component'],resolve)
},
render: function (createElement) {
return createElement('myComponent',
{
nativeOn: {
click: function(e){
console.log(e)
}
}
},
);
},
複製代碼
scopedSlots項,在父組件中用子組件的數據渲染插槽內容,例:
子組件
<template>
<div>
<slot :title="title"></slot>
<slot name="content" :content="content"></slot>
</div>
</template>
<script>
export default {
data() {
return {
title: '個人組件',
content: '內容'
}
},
}
</script>
複製代碼
父組件
components: {
myComponent: resolve => require(['./my_component'], resolve)
},
render: function (createElement) {
return createElement('myComponent',
{
scopedSlots: {
default: ({ title }) => createElement('span', title),
content: ({ content }) => createElement('p', content)
}
},
);
},
複製代碼
slot項,若是組件是其它組件的子組件,需爲插槽指定名稱(demo待續);
directives項,自定義指令(demo待續);
key項,定義組件的key(demo待續);
ref項,給組件增長ref屬性,經過this.$refs
,在render函數組件中調用其子組件的方法,例:
子組件
<template>
<div>{{title}}</div>
</template>
<script>
export default {
data() {
return {
title: '個人組件',
}
},
methods:{
show(){
console.log(this.title)
}
}
}
</script>
複製代碼
render函數組件
<script>
export default {
data() {
return {};
},
components: {
myComponent: resolve => require(['./my_component'], resolve)
},
render: function (createElement) {
var myChild = createElement('myComponent', { ref: 'myRef' });
const _this = this;
return createElement('div', {
on: {
click: function () {
_this.$refs.myRef.show();//個人組件
}
},
ref: 'myRef',
}, [myChild])
},
};
</script>
複製代碼
類型能夠是String,能夠是文字類型的節點,例:
render: function (createElement) {
return createElement('div', '我是渲染出來的組件');
},
複製代碼
或者
<script>
export default {
props: {
title: {
type: String,
default: "我是渲染出來的組件"
}
},
data() {
return {};
},
render: function (createElement) {
return createElement('div', this.title);
},
};
</script>
複製代碼
類型能夠是Array,其中值可爲字符串、createElement函數,例:
<script>
export default {
props: {
title: {
type: Function,
default: "我是渲染出來的組件"
}
},
data() {
return {};
},
render: function (createElement) {
return createElement('div', [this.title,'我是字符串',createElement('h1','我是子節點')]);
},
};
</script>
複製代碼
利用this.$slots
在render函數組件中實現插槽功能,例:
子組件
<script>
export default {
data() {
return {
};
},
render: function (createElement) {
return createElement(
'div',
[
createElement('h1',this.$slots.default),
createElement('h2',this.$slots.header)
]
)
},
};
</script>
複製代碼
父組件
<template>
<div>
<myRender>
父默認內容
<template v-slot:header>父內容</template>
</myRender>
</div>
</template>
<script>
export default {
data() {
return {}
},
components: {
myRender: resolve => require(['./my_render.vue'], resolve),
},
}
</script>
複製代碼
渲染出
<div>
<h1>父默認內容</h1>
<h2>父內容</h2>
</div>
複製代碼
利用this.$scopedSlots
實現調用render函數組件時用render函數組件中的數據編輯插槽,例:
子組件
<script>
export default {
data() {
return {
info:'我是render函數組件'
};
},
render: function(createElement) {
return createElement("div", [
this.$scopedSlots.header({
title: this.info
})
]);
}
};
</script>
複製代碼
父組件
<template>
<div>
<myRender>
<template v-slot:header="{title}">{{title}}</template>
</myRender>
</div>
</template>
<script>
export default {
data() {
return {};
},
components: {
myRender: resolve => require(["./my_render.vue"], resolve)
}
};
</script>
複製代碼
組件樹中的全部 VNode 必須是惟一的,因此當參數類型爲Array時,每一個值不可重複,例:
render: function (createElement) {
var myChild = createElement('p', 'hi')
return createElement('div', [
// 錯誤 - 重複的 VNode
myChild,myChild,myChild
])
},
複製代碼
應該這麼作
render: function (createElement) {
return createElement('div',
Array.from({ length: 20 }).map(function () {
return createElement('p', 'hi')
})
)
}
複製代碼
v-if
v-else
v-for
模板功能,例:<ul v-if="lists.length">
<li v-for="item in lists">{{ item.name }}</li>
</ul>
<p v-else>沒有數據</p>
複製代碼
props: ['lists'],
render: function (h) {
if (this.lists.length) {
return h('ul', this.lists.map(function (item) {
return h('li', item.name)
}))
} else {
return h('p', '沒有數據')
}
}
複製代碼
v-model
模板功能,例:props: ["value"],
render: function(h) {
var _this = this;
return h("input", {
domProps: {
value: _this.value
},
on: {
input: function(event) {
_this.$emit("input", event.target.value);
}
}
});
}
複製代碼
在使用iview中Tree組件,你會發現組件提供了render屬性讓你能夠自定義樹節點。那是怎麼實現的,下面舉個簡單列子:
子組件
<script>
export default {
props: {
render: {
type: Function,
},
data: {
type: Object,
default(){
return {}
},
}
},
render: function (h) {
const params = {
data: this.data,
};
return this.render(h,params);
},
};
</script>
複製代碼
父組件
<template>
<div>
<myRender :render="this.render" :data="this.data">
</myRender>
</div>
</template>
<script>
export default {
data() {
return {
render: function(h,{data}) {
const info= `我是${data.name},今年${data.age}歲`;
return h('h1', info);
},
data:{
name:'小明',
age:18,
},
}
},
components: {
myRender: resolve => require(['./my_render.vue'], resolve),
},
}
</script>
複製代碼
渲染出
我是小明,今年18歲
複製代碼
注意 render值不能用箭頭函數,不然this指向會出錯。
什麼是函數式組件,知足如下幾個特色能夠稱爲函數式組件
函數式組件優勢,渲染開銷低
怎麼使用函數式組件
將functional
選項標記爲true
,此時組件成爲
那麼上個例子的子組件能夠這麼寫
<script>
export default {
functional:true,
render: function (h,context) {
const params = {
data: context.props.data,
};
return context.props.render(h,params);
},
};
</script>
複製代碼
組件須要的一切都是經過 context 參數傳遞,它是一個包括以下字段的對象:
在模板中使用函數式組件這樣聲明:
<template functional>
<div>
<p v-for="item in props.lists" @click="props.listClick(item);">
{{ item }}
</p>
</div>
</template>
複製代碼