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

可見:當(dāng)我們直接用v-model="屬性名“這種方法寫簡化了書寫的難度達到了同樣的效果。
2.ref與$ref語法
這個語法可使用操作dom元素。每個 vue 的組件實例上,都包含一個$refs 對象,里面存儲著對應(yīng)的DOM 元素或組件的引用。
注意點:
當(dāng)ref="自定義名"是寫在組件身上就可以得到該對象實例vue
綁定是ref,調(diào)用是$refs
1.綁定dom寫法:<標(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寫的: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());//都包含一個$refs 對象因此可已獲取標(biāo)簽里面的方法(組件)
參考下面這個例子:
父組件:App.vue
<template>
<div>
<h1>我是父組件</h1>
<button @click="onAdd">點我查看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>商品名稱:小米</p>
<p>商品價格:{{ price }}</p>
<button @click="doClick">點我購買</button>
</div>
</template>
<script>
export default {
props:{
value:Number
},
data(){
return{
price:'999'
}
},
methods: {
doClick() {
console.log("點擊了購買");
return 0//當(dāng)不寫的時候調(diào)用了方法沒有return會提示undefinded
}
}
}
</script>
<style>
</style>實現(xiàn)效果:

3.dynamic動態(tài)組件
什么是動態(tài)組件: 讓多個組件使用同一個掛載點并動態(tài)切換,這就是動態(tài)組件。
通過設(shè)置組件名,讓一個掛載點可以切換不同的組件。
語法格式:
<component :is="組件名"></component>
舉個例子:
父組件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>我是個人信息組件</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>實現(xiàn)效果:

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

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

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

可以看出來,我們的<goods></goods>調(diào)用了四次,我們在父中的值傳到子中的都不一樣,頁面也根據(jù)我們所想的展示出來了不同的組件。
2.具名插槽
使用多個slot實現(xiàn)精準的傳遞多個位置的插槽給子組件 ,寫的時候必須在<template></template>中
具名插槽書寫結(jié)構(gòu):
父傳:
<組件名>
<template v-slot:自定義名>
<h2>HTML結(jié)構(gòu)</h2>
</template>
</組件名>子收:
<div >
<slot name="自定義插槽名">插槽默認值</slot>
</div>我們一起來看看這個例子:
父組件: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">我是默認標(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>實現(xiàn)效果:

通過這個例子,我們可以看到,我們具名比匿名插槽多了一個精準定位的功能。
3.作用域插槽
父組件可根據(jù)子組件傳過來的插槽數(shù)據(jù)來進行不同的方式展現(xiàn)和填充插槽內(nèi)容
作用域插槽書寫結(jié)構(gòu):
子組件傳遞:
<slot 屬性名="屬性值">默認值</slot>
父組件接收:(注意接收的是一個對象)
<組件名 父傳值屬性>
<template v-slot="{一個對象}">
HTML屬性
</template>
</組件名>來個例子:
父組件:App03(作用域插槽).vue
<template>
<div>
<!--
1.匿名插槽:父組件傳遞 單個HTML結(jié)構(gòu) 給子組件
父傳:<子組件>HTML結(jié)構(gòu)</子組件>
子收:<slot>默認HTML結(jié)構(gòu)</slot>
2.具名插槽:父組件傳遞 多個HTML結(jié)構(gòu) 給子組件
父傳:
<子組件>
<template #插槽名>
HTML結(jié)構(gòu)
</template>
</子組件>
子收:<slot name="插槽名">默認HTML結(jié)構(gòu)</slot>
3.作用域插槽:子組件傳遞數(shù)據(jù)給父組件
子傳:<slot 屬性名="屬性值">默認HTML結(jié)構(gòu)</slot>
父收:
<子組件>
<template v-slot="對象名">
HTML結(jié)構(gòu)
</template>
</子組件>
-->
<!-- (具名插槽 + 作用域插槽)組合寫法:#插槽名 = "對象名" -->
<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>序號</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>
效果如下:

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

總結(jié)
到此這篇關(guān)于vue2組件進階與插槽詳解的文章就介紹到這了,更多相關(guān)vue2組件進階與插槽內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue利用路由鉤子token過期后跳轉(zhuǎn)到登錄頁的實例
下面小編就為大家?guī)硪黄猇ue利用路由鉤子token過期后跳轉(zhuǎn)到登錄頁的實例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-10-10
vue axios數(shù)據(jù)請求及vue中使用axios的方法
axios 是一個基于Promise 用于瀏覽器和 nodejs 的 HTTP 客戶端,在vue中數(shù)據(jù)請求需要先安裝axios。這篇文章主要介紹了vue axios數(shù)據(jù)請求及vue中使用axios的方法,需要的朋友可以參考下2018-09-09
vue.js的狀態(tài)管理vuex中store的使用詳解
今天小編就為大家分享一篇vue.js的狀態(tài)管理vuex中store的使用詳解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-11-11
Vue利用History記錄上一頁面的數(shù)據(jù)方法實例
這篇文章主要給大家介紹了關(guān)于Vue利用History記錄上一頁面的數(shù)據(jù)的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-11-11

