??博???????主:初映CY的前說(前端領(lǐng)域)
??個人信條:想要變成得到,中間還有做到!
??本文核心:v-modedl表單雙向綁定、ref|$ref操作dom、dynamic動態(tài)組件、$nextTick同步、匿名插槽、具名插槽、作用域插槽
目錄(文末有給大家準(zhǔn)備好的Xmind思維導(dǎo)圖)
一、組件進(jìn)階
1.v-model語法
2.ref與$ref語法
3.dynamic動態(tài)組件
4.this.$nextTick()
二、匿名|具名|作用域插槽
插槽概念:
1.匿名插槽
2.具名插槽
3.作用域插槽
一、組件進(jìn)階
1.v-model語法
v-model指令我們的一個初印象就是表單數(shù)據(jù)實(shí)現(xiàn)綁定雙向,一修改同步修改,那么本質(zhì)是什么?
博主認(rèn)為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="屬性名“這種方法寫簡化了書寫的難度達(dá)到了同樣的效果。
2.ref與$ref語法
這個語法可使用操作dom元素。每個 vue 的組件實(shí)例上,都包含一個$refs 對象,里面存儲著對應(yīng)的DOM 元素或組件的引用。
注意點(diǎn):
當(dāng)ref="自定義名"是寫在組件身上就可以得到該對象實(shí)例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">點(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>商品名稱:小米</p>
<p>商品價(jià)格:{{ price }}</p>
<button @click="doClick">點(diǎn)我購買</button>
</div>
</template>
<script>
export default {
props:{
value:Number
},
data(){
return{
price:'999'
}
},
methods: {
doClick() {
console.log("點(diǎn)擊了購買");
return 0//當(dāng)不寫的時(shí)候調(diào)用了方法沒有return會提示undefinded
}
}
}
</script>
<style>
</style>
實(shí)現(xiàn)效果:
3.dynamic動態(tài)組件
什么是動態(tài)組件: 讓多個組件使用同一個掛載點(diǎn)并動態(tài)切換,這就是動態(tài)組件。
通過設(shè)置組件名,讓一個掛載點(diǎn)可以切換不同的組件。
語法格式:
<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>
實(shí)現(xiàn)效果:
?可以看到我們通過<component :is="組件名">找到相應(yīng)的標(biāo)簽運(yùn)行
4.this.$nextTick()
是用來將我們vue的異步操作進(jìn)行放在頁面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">點(diǎn)我開始輸入</button>
</div>
</template>
<script>
export default {
data() {
return {
flag: false
}
},
methods: {
doClick() {
this.flag = true//異步操作,生命周期中修改階段
this.$nextTick(
() => {//一定要箭頭函數(shù),因?yàn)榧^函數(shù)的this指向上一層作用域與原本的this是同一個
this.$refs.input.focus()
}
)
}
}
}
</script>
<style>
</style>
?實(shí)現(xiàn)的效果:
當(dāng) this.flag = true執(zhí)行完成之后頁面應(yīng)該是執(zhí)行渲染在頁面的操作,但是我們的 vue是異步的微任務(wù)(Vue將開啟一個異步更新隊(duì)列,視圖需要等隊(duì)列中所有數(shù)據(jù)變化完成之后,再統(tǒng)一進(jìn)行更新),渲染的時(shí)候找不到ref="input"這個dom就會報(bào)錯,因此需要就用 ?this.$nextTick來將需要的操作放在渲染之前。
?可看上圖:當(dāng)我寫在外面的時(shí)候就會報(bào)錯。
原理:vue操作dom是異步的操作,如果需要同步顯示出來需要利用this.$nextTick()將異步操作提前放在dom樹更新后,頁面渲染前
二、匿名|具名|作用域插槽
插槽概念:
- slot相當(dāng)于是組件里面的一個內(nèi)置的開關(guān),打開了這個開關(guān)就可以在復(fù)用組件的同時(shí)修改單個組件中的HTML的結(jié)構(gòu)。
- 用來解決組件復(fù)用的同時(shí)可以對單個組件進(jìn)行修改操作,讓組件變得更加靈活
1.匿名插槽
我們在父中調(diào)用子組件,在復(fù)用組件的同時(shí)修改單個組件不受影響
插槽書寫結(jié)構(gòu):? ?
父傳:<子組件名>HTML結(jié)構(gòu)</子組件名>
子收: <slot>此處寫默認(rèn)值</slot>
我們一起來看看這個例子:
父組件:App01(匿名插槽).vue
<template>
<div>
<h1>我是父組件</h1>
<goods><button>已下單</button></goods>
<goods></goods>
<goods ><button disabled>已賣完</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>商品名稱</h4>
<!-- slot相當(dāng)于是一個開關(guān),打開了這個開關(guān)就可以插入想要的值
從父傳 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)效果:
?可以看出來,我們的<goods></goods>調(diào)用了四次,我們在父中的值傳到子中的都不一樣,頁面也根據(jù)我們所想的展示出來了不同的組件。
2.具名插槽
使用多個slot實(shí)現(xiàn)精準(zhǔn)的傳遞多個位置的插槽給子組件 ,寫的時(shí)候必須在<template></template>中
具名插槽書寫結(jié)構(gòu):?
父傳:
<組件名>
<template v-slot:自定義名>
<h2>HTML結(jié)構(gòu)</h2>
</template>
</組件名>
子收:
? ? ? <div >
? ? ? ? ? <slot name="自定義插槽名">插槽默認(rèn)值</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">我是默認(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)效果:
?通過這個例子,我們可以看到,我們具名比匿名插槽多了一個精準(zhǔn)定位的功能。
3.作用域插槽
父組件可根據(jù)子組件傳過來的插槽數(shù)據(jù)來進(jìn)行不同的方式展現(xiàn)和填充插槽內(nèi)容
作用域插槽書寫結(jié)構(gòu):?
子組件傳遞:
<slot 屬性名="屬性值">默認(rèn)值</slot>
父組件接收:(注意接收的是一個對象)
<組件名 父傳值屬性>
<template v-slot="{一個對象}">
HTML屬性
</template>
</組件名>
來個例子:
父組件:App03(作用域插槽).vue
<template>
<div>
<!--
1.匿名插槽:父組件傳遞 單個HTML結(jié)構(gòu) 給子組件
父傳:<子組件>HTML結(jié)構(gòu)</子組件>
子收:<slot>默認(rèn)HTML結(jié)構(gòu)</slot>
2.具名插槽:父組件傳遞 多個HTML結(jié)構(gòu) 給子組件
父傳:
<子組件>
<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="對象名">
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的組件都分別實(shí)現(xiàn)了不同的效果,第一個因?yàn)槲覜]有將父組件中的arr傳進(jìn)去,因此arr提示undefin,后面兩個組件分別實(shí)現(xiàn)了不同的功能。對比具名插槽,作用域插槽實(shí)現(xiàn)了
總結(jié)匿名|具名|作用域函數(shù):
匿名插槽:插槽可以實(shí)現(xiàn)組件復(fù)用的同時(shí)顯示不同的內(nèi)容
具名插槽:slot開關(guān)可以寫多個,并且可以精準(zhǔn)定位到我們想要的位置
作用域插槽:子組件可以傳遞數(shù)據(jù)給父組件
好了,兄弟姐妹們,本文結(jié)束嘍!如果有未知的疑問,大家留言我會盡我所能幫助大家文章來源:http://www.zghlxwxcb.cn/news/detail-779134.html
下篇文章將講解【路由】的使用,本專欄將持續(xù)更新,歡迎關(guān)注~?文章來源地址http://www.zghlxwxcb.cn/news/detail-779134.html
到了這里,關(guān)于【vue2】組件進(jìn)階與插槽詳解的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!