vue2組件進(jìn)階與插槽詳解(推薦!)
一、組件進(jìn)階
1.v-model語(yǔ)法
v-model指令我們的一個(gè)初印象就是表單數(shù)據(jù)實(shí)現(xiàn)綁定雙向,一修改同步修改,那么本質(zhì)是什么?
博主認(rèn)為v-mode語(yǔ)法本質(zhì)上是簡(jiǎn)化了書(shū)寫(xiě)操作。觸發(fā)v-model需要滿(mǎn)足兩個(gè)條件的(標(biāo)紅部分是語(yǔ)法規(guī)定部分不可自定義)
- data中數(shù)據(jù)變化,表單的值也會(huì)變化 :value="data中的屬性名"
- 表單的值發(fā)生變化,data中的數(shù)據(jù)也會(huì)變化 @input="data中的屬性名=$event.target.value"
當(dāng)滿(mǎn)足了就可直接寫(xiě)上v-model="我們data中的屬性名"
舉個(gè)例子:
<template>
<div>
<h1>根組件App.vue</h1>
<!--
1.v-model = "msg"
(1)data中的數(shù)據(jù)變化,表單的值也會(huì)變化 :value="msg"
(2)表單的值發(fā)生變化,data中的數(shù)據(jù)也會(huì)變化 @input="msg=$event.target.value"
-->
<input type="text" v-model="msg" />
<hr />
<!-- 這種寫(xiě)法與上面寫(xiě)法功能一致 -->
<input type="text" :value="msg" @input="msg = $event.target.value" />
<hr />
<!-- 這種寫(xiě)法也與上面寫(xiě)法一致 -->
<input type="text" :value="msg" @input="doInput" />
<hr />
</div>
</template>
<script>
export default {
data() {
return {
msg: ""
};
},
methods: {
doInput(e) {
this.msg = e.target.value;
}
}
};
</script>
<style>
</style>效果演示:

可見(jiàn):當(dāng)我們直接用v-model="屬性名“這種方法寫(xiě)簡(jiǎn)化了書(shū)寫(xiě)的難度達(dá)到了同樣的效果。
2.ref與$ref語(yǔ)法
這個(gè)語(yǔ)法可使用操作dom元素。每個(gè) vue 的組件實(shí)例上,都包含一個(gè)$refs 對(duì)象,里面存儲(chǔ)著對(duì)應(yīng)的DOM 元素或組件的引用。
注意點(diǎn):
當(dāng)ref="自定義名"是寫(xiě)在組件身上就可以得到該對(duì)象實(shí)例vue
綁定是ref,調(diào)用是$refs
1.綁定dom寫(xiě)法:<標(biāo)簽 ref="自定義名"></標(biāo)簽>
<div ref="aaa" class="box"></div>
<input ref="bbb" type="text">
<my-goods ref="ccc" ></my-goods>2.調(diào)用dom寫(xiě)的:this.$refs.自定義屬性名
console.log(this.$refs.aaa); console.log(this.$refs.bbb); console.log(this.$refs.ccc); // 調(diào)用子組件方法 console.log(this.$refs.ccc.doClick());//都包含一個(gè)$refs 對(duì)象因此可已獲取標(biāo)簽里面的方法(組件)
參考下面這個(gè)例子:
父組件:App.vue
<template>
<div>
<h1>我是父組件</h1>
<button @click="onAdd">點(diǎn)我查看ref打印的啥</button>
<div ref="aaa" class="box"></div>
<input ref="bbb" type="text">
<my-goods ref="ccc" ></my-goods>
</div>
</template>
<script>
import MyGoods from '@/components/MyGoods.vue'
export default {
components: { MyGoods },
data() {
return {
}
},
methods: {
onAdd() {
console.log(this);
console.log(this.$refs.aaa);
console.log(this.$refs.bbb);
console.log(this.$refs.ccc);
// 調(diào)用子組件方法
console.log(this.$refs.ccc.doClick());
},
}
}
</script>
<style>
</style>子組件:MyGoods.vue
<template>
<div>
<p>商品名稱(chēng):小米</p>
<p>商品價(jià)格:{{ price }}</p>
<button @click="doClick">點(diǎn)我購(gòu)買(mǎi)</button>
</div>
</template>
<script>
export default {
props:{
value:Number
},
data(){
return{
price:'999'
}
},
methods: {
doClick() {
console.log("點(diǎn)擊了購(gòu)買(mǎi)");
return 0//當(dāng)不寫(xiě)的時(shí)候調(diào)用了方法沒(méi)有return會(huì)提示undefinded
}
}
}
</script>
<style>
</style>實(shí)現(xiàn)效果:

3.dynamic動(dòng)態(tài)組件
什么是動(dòng)態(tài)組件: 讓多個(gè)組件使用同一個(gè)掛載點(diǎn)并動(dòng)態(tài)切換,這就是動(dòng)態(tài)組件。
通過(guò)設(shè)置組件名,讓一個(gè)掛載點(diǎn)可以切換不同的組件。
語(yǔ)法格式:
<component :is="組件名"></component>
舉個(gè)例子:
父組件App.vue
<template>
<div>
<h1>我是父組件</h1>
<button @click="comName='login'">登錄</button>
<button @click="comName='user'">信息</button>
<component :is="comName"></component>
</div>
</template>
<script>
import login from '@/components/login.vue'
import user from '@/components/user.vue'
export default {
components: { login, user },
data() {
return {
comName:"user"
}
}
}
</script>
<style>
</style>子組件 user.vue
<template>
<div>
<p>我是個(gè)人信息組件</p>
</div>
</template>
<script>
export default {
name:"user"
}
</script>
<style>
</style>子組件 login.vue
<template>
<div>
<p>我是登錄組件</p>
</div>
</template>
<script>
export default {
name:"login"
}
</script>
<style>
</style>實(shí)現(xiàn)效果:

可以看到我們通過(guò)<component :is="組件名">找到相應(yīng)的標(biāo)簽運(yùn)行
4.this.$nextTick()
是用來(lái)將我們vue的異步操作進(jìn)行放在頁(yè)面dom渲染前面。想要在修改數(shù)據(jù)后立刻得到更新后的DOM結(jié)構(gòu),可以使用Vue.nextTick()
上個(gè)例子:
<template>
<div>
<h1>我是父組件</h1>
<input type="text" v-if="flag" ref="input">
<button v-else @click="doClick">點(diǎn)我開(kāi)始輸入</button>
</div>
</template>
<script>
export default {
data() {
return {
flag: false
}
},
methods: {
doClick() {
this.flag = true
this.$nextTick(
() => {//一定要箭頭函數(shù),因?yàn)榧^函數(shù)的this指向上一層作用域與原本的this是同一個(gè)
this.$refs.input.focus()
}
)
}
}
}
</script>
<style>
</style>實(shí)現(xiàn)的效果:

當(dāng) this.flag = true執(zhí)行完成之后頁(yè)面應(yīng)該是執(zhí)行渲染在頁(yè)面的操作,但是我們的 vue是異步的微任務(wù)(Vue將開(kāi)啟一個(gè)異步更新隊(duì)列,視圖需要等隊(duì)列中所有數(shù)據(jù)變化完成之后,再統(tǒng)一進(jìn)行更新),渲染的時(shí)候找不到ref="input"這個(gè)dom就會(huì)報(bào)錯(cuò),因此需要就用 this.$nextTick來(lái)將需要的操作放在渲染之前。

可看上圖:當(dāng)我寫(xiě)在外面的時(shí)候就會(huì)報(bào)錯(cuò)。
原理:vue操作dom是異步的操作,如果需要同步顯示出來(lái)需要利用this.$nextTick()將異步操作提前放在dom樹(shù)更新前
二、匿名|具名|作用域插槽
插槽概念:
slot相當(dāng)于是組件里面的一個(gè)內(nèi)置的開(kāi)關(guān),打開(kāi)了這個(gè)開(kāi)關(guān)就可以在復(fù)用組件的同時(shí)修改單個(gè)組件中的HTML的結(jié)構(gòu)。用來(lái)解決組件復(fù)用的同時(shí)可以對(duì)單個(gè)組件進(jìn)行修改操作,讓組件變得更加靈活
1.匿名插槽
我們?cè)诟钢姓{(diào)用子組件,在復(fù)用組件的同時(shí)修改單個(gè)組件不受影響
插槽書(shū)寫(xiě)結(jié)構(gòu):
父?jìng)鳎?lt;子組件名>HTML結(jié)構(gòu)</子組件名>
子收: <slot>此處寫(xiě)默認(rèn)值</slot>
我們一起來(lái)看看這個(gè)例子:
父組件:App01(匿名插槽).vue
<template>
<div>
<h1>我是父組件</h1>
<goods><button>已下單</button></goods>
<goods></goods>
<goods ><button disabled>已賣(mài)完</button></goods>
<goods><a href="#">點(diǎn)我跳轉(zhuǎn)</a></goods>
</div>
</template>
<script>
import goods from '@/components/goods.vue'
export default {
components:{goods}
}
</script>
<style>
</style>子組件:goods.vue
<template>
<div class="son">
<h3>我是子組件</h3>
<h4>商品名稱(chēng)</h4>
<!-- slot相當(dāng)于是一個(gè)開(kāi)關(guān),打開(kāi)了這個(gè)開(kāi)關(guān)就可以插入想要的值
從父?jìng)?HTML的結(jié)構(gòu) -->
<slot>我是默認(rèn)的插槽</slot>
</div>
</template>
<script>
export default {
name: "goods",
data() {
return {}
}
}
</script>
<style scoped>
.son {
border: 1px solid red;
}
</style>我們先看下我們的實(shí)現(xiàn)效果:

可以看出來(lái),我們的<goods></goods>調(diào)用了四次,我們?cè)诟钢械闹祩鞯阶又械亩疾灰粯?,?yè)面也根據(jù)我們所想的展示出來(lái)了不同的組件。
2.具名插槽
使用多個(gè)slot實(shí)現(xiàn)精準(zhǔn)的傳遞多個(gè)位置的插槽給子組件 ,寫(xiě)的時(shí)候必須在<template></template>中
具名插槽書(shū)寫(xiě)結(jié)構(gòu):
父?jìng)鳎?/p>
<組件名>
<template v-slot:自定義名>
<h2>HTML結(jié)構(gòu)</h2>
</template>
</組件名>子收:
<div >
<slot name="自定義插槽名">插槽默認(rèn)值</slot>
</div>我們一起來(lái)看看這個(gè)例子:
父組件:App02(具名插槽).vue
<template>
<div>
<h1>我是父組件</h1>
<cell>
<template v-slot:title>
<h2>I am Tittle</h2>
</template>
<template v-slot:content>
<i>I am goodsInfo</i>
</template>
<template v-slot:right>
<i>My position</i>
</template>
</cell>
</div>
</template>
<script>
import cell from '@/components/cell.vue'
export default {
components:{cell}
}
</script>
<style>
</style>子組件:cell.vue
<template>
<div class="cell">
<!--
具名插槽使用:
1.在子組件鐘使用 slot+name確定組件的作用域
2.在父組件鐘用template 接收 使用v-slot:name傳遞
-->
<div class="title" >
<slot name="title">我是默認(rèn)標(biāo)題</slot>
</div>
<div class="content" >
<slot name="content"> 我是文本信息</slot>
</div>
<div class="right" >
<slot name="right">我是右側(cè)信息</slot>
</div>
</div>
</template>
<script>
export default {
}
</script>
<style>
.cell{
border: 1px solid #f00;
height: 60px;
padding: 10px;
position: relative;
}
.title{
float: left;
line-height: 1px;
}
.content{
position: absolute;
bottom: 10px;
left: 10px;
}
.right{
float: right;
}
</style>實(shí)現(xiàn)效果:

通過(guò)這個(gè)例子,我們可以看到,我們具名比匿名插槽多了一個(gè)精準(zhǔn)定位的功能。
3.作用域插槽
父組件可根據(jù)子組件傳過(guò)來(lái)的插槽數(shù)據(jù)來(lái)進(jìn)行不同的方式展現(xiàn)和填充插槽內(nèi)容
作用域插槽書(shū)寫(xiě)結(jié)構(gòu):
子組件傳遞:
<slot 屬性名="屬性值">默認(rèn)值</slot>
父組件接收:(注意接收的是一個(gè)對(duì)象)
<組件名 父?jìng)髦祵傩?gt;
<template v-slot="{一個(gè)對(duì)象}">
HTML屬性
</template>
</組件名>來(lái)個(gè)例子:
父組件:App03(作用域插槽).vue
<template>
<div>
<!--
1.匿名插槽:父組件傳遞 單個(gè)HTML結(jié)構(gòu) 給子組件
父?jìng)鳎?lt;子組件>HTML結(jié)構(gòu)</子組件>
子收:<slot>默認(rèn)HTML結(jié)構(gòu)</slot>
2.具名插槽:父組件傳遞 多個(gè)HTML結(jié)構(gòu) 給子組件
父?jìng)鳎?
<子組件>
<template #插槽名>
HTML結(jié)構(gòu)
</template>
</子組件>
子收:<slot name="插槽名">默認(rèn)HTML結(jié)構(gòu)</slot>
3.作用域插槽:子組件傳遞數(shù)據(jù)給父組件
子傳:<slot 屬性名="屬性值">默認(rèn)HTML結(jié)構(gòu)</slot>
父收:
<子組件>
<template v-slot="對(duì)象名">
HTML結(jié)構(gòu)
</template>
</子組件>
-->
<!-- (具名插槽 + 作用域插槽)組合寫(xiě)法:#插槽名 = "對(duì)象名" -->
<h1>父組件</h1>
<student></student>
<h3>刪除功能</h3>
<student :arr="list1">
<template v-slot="{ $index }">
<button @click="list1.splice($index, 1)">刪除</button>
</template>
</student>
<h3>頭像功能</h3>
<student :arr="list2">
<template v-slot="{ row }">
<img :src="row.headImgUrl" alt="" />
</template>
</student>
</div>
</template>
<script>
import student from "./components/student.vue";
export default {
components: { student },
data() {
return {
list1: [
{
id: "13575",
name: "小傳同學(xué)",
age: 18,
headImgUrl:
"http://yun.itheima.com/Upload/./Images/20210303/603f2d2153241.jpg",
},
{
id: "62408",
name: "小黑同學(xué)",
age: 25,
headImgUrl:
"http://yun.itheima.com/Upload/./Images/20210304/6040b101a18ef.jpg",
},
{
id: "73969",
name: "智慧同學(xué)",
age: 21,
headImgUrl:
"http://yun.itheima.com/Upload/./Images/20210302/603e0142e535f.jpg",
},
],
list2: [
{
id: "13575",
name: "傳同學(xué)",
age: 8,
headImgUrl:
"http://yun.itheima.com/Upload/./Images/20210303/603f2d2153241.jpg",
},
{
id: "62408",
name: "黑同學(xué)",
age: 5,
headImgUrl:
"http://yun.itheima.com/Upload/./Images/20210304/6040b101a18ef.jpg",
},
{
id: "73969",
name: "慧同學(xué)",
age: 1,
headImgUrl:
"http://yun.itheima.com/Upload/./Images/20210302/603e0142e535f.jpg",
},
],
};
},
};
</script>
<style>
</style>子組件: student.vue
<template>
<div>
<slot name="title" >修改</slot>
<table border="1">
<thead>
<tr>
<th>序號(hào)</th>
<th>姓名</th>
<th>年齡</th>
<th>頭像</th>
</tr>
</thead>
<tbody>
<tr v-for="(item,index) in arr" :key="item.id">
<td>{{ index+1 }}</td>
<td>{{ item.name }}</td>
<td>{{ item.age }}</td>
<td>
<slot :row="item" :$index="index"></slot>
</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
export default {
props: { arr: Array },
data() {
return {}
}
}
</script>
<style scoped>
table {
margin-top: 20px;
}
td {
height: 60px;
}
img {
height: 90%;
}
</style>
效果如下:

可以看見(jiàn),我們復(fù)用的三個(gè)student的組件都分別實(shí)現(xiàn)了不同的效果,第一個(gè)因?yàn)槲覜](méi)有將父組件中的arr傳進(jìn)去,因此arr提示undefin,后面兩個(gè)組件分別實(shí)現(xiàn)了不同的功能。對(duì)比具名插槽,作用域插槽實(shí)現(xiàn)了
總結(jié)匿名|具名|作用域函數(shù):
匿名插槽:插槽可以實(shí)現(xiàn)組件復(fù)用的同時(shí)顯示不同的內(nèi)容
具名插槽:slot開(kāi)關(guān)可以寫(xiě)多個(gè),并且可以精準(zhǔn)定位到我們想要的位置
作用域插槽:子組件可以傳遞數(shù)據(jù)給父組件

總結(jié)
到此這篇關(guān)于vue2組件進(jìn)階與插槽詳解的文章就介紹到這了,更多相關(guān)vue2組件進(jìn)階與插槽內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue利用路由鉤子token過(guò)期后跳轉(zhuǎn)到登錄頁(yè)的實(shí)例
下面小編就為大家?guī)?lái)一篇Vue利用路由鉤子token過(guò)期后跳轉(zhuǎn)到登錄頁(yè)的實(shí)例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-10-10
vue實(shí)現(xiàn)tab路由切換組件的方法實(shí)例
這篇文章主要給大家介紹了關(guān)于vue實(shí)現(xiàn)tab路由切換組件的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-05-05
vue axios數(shù)據(jù)請(qǐng)求及vue中使用axios的方法
axios 是一個(gè)基于Promise 用于瀏覽器和 nodejs 的 HTTP 客戶(hù)端,在vue中數(shù)據(jù)請(qǐng)求需要先安裝axios。這篇文章主要介紹了vue axios數(shù)據(jù)請(qǐng)求及vue中使用axios的方法,需要的朋友可以參考下2018-09-09
vue.js的狀態(tài)管理vuex中store的使用詳解
今天小編就為大家分享一篇vue.js的狀態(tài)管理vuex中store的使用詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-11-11
vue路由攔截器和請(qǐng)求攔截器知識(shí)點(diǎn)總結(jié)
在本篇文章里小編給各位整理的是一篇關(guān)于vue路由攔截器和請(qǐng)求攔截器知識(shí)點(diǎn)總結(jié)文章,有興趣的朋友們學(xué)習(xí)下。2019-11-11
Vue利用History記錄上一頁(yè)面的數(shù)據(jù)方法實(shí)例
這篇文章主要給大家介紹了關(guān)于Vue利用History記錄上一頁(yè)面的數(shù)據(jù)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2018-11-11
不同場(chǎng)景下Vue中虛擬列表實(shí)現(xiàn)
虛擬列表用來(lái)解決大數(shù)據(jù)量數(shù)據(jù)渲染問(wèn)題,由于一次性渲染性能低,所以誕生了虛擬列表渲染,下面我們就來(lái)學(xué)習(xí)一下不同場(chǎng)景下Vue中虛擬列表是如何實(shí)現(xiàn)的吧2023-10-10

