vue插槽slot理解

vue的插槽用法,官方文檔寫的內(nèi)容個(gè)人感覺有點(diǎn)亂,不自己梳理一下的話,使用的時(shí)候也容易懵逼,下面是我對vue插槽使用的理解:

1.概念

slot概念源于web components規(guī)范草案(地址:https://github.com/WICG/webcomponents/blob/gh-pages/proposals/Slots-Proposal.md
vue官網(wǎng)關(guān)于插槽的文檔中,第一句話即說明了vue的slot插槽設(shè)計(jì)源于web components,具體內(nèi)容可以自行了解,這里只說vue框架下slot的用法。

概念:slot可將父組件子組件標(biāo)簽里寫的content渲染到子組件對應(yīng)的地方


2.用法

先說通用性用法,再說特殊情況會讓人比較容易接受。這里以最具通用性的寫法,以具名插槽的寫法為例子展開
父組件中:

<script>
...
</script>

<template> // 注意這個(gè)template是組件的template屬性,不要跟下面的template標(biāo)簽弄混
  <todo-item>
    <template v-slot:default> // 注意v-slot指令大多數(shù)情況都是寫在template標(biāo)簽里,有一種特殊情況在下一節(jié)會說到,即使不懂特殊情況也不會妨礙到使用。
      這里的內(nèi)容會渲染到子組件對應(yīng)的地方
    </template>
  </todo-item>
</template>

<style>
...
</style>

子組件中

<div>
  // 子組件中slot標(biāo)簽的name屬性值與父組件中的v-slot綁定的屬性值一致,形成對應(yīng)關(guān)系
  <slot name="default"></slot>
</div>

渲染結(jié)果:

<div>
  這里的內(nèi)容會渲染到子組件對應(yīng)的地方
</div>

父組件template標(biāo)簽上的v-slot指令與子組件的slot標(biāo)簽的name屬性,通過綁定一樣的值,形成一一對應(yīng)的關(guān)系。
父組件中:

<子組件標(biāo)簽>
  <template v-slot:default>
    我會渲染到name=default的slot中
  </template>

  <template v-slot:test1>
    我會渲染到name=test1的slot中
  </template>

  <template v-slot:test2>
    我會渲染到name=test2的slot中
  </template>
</子組件標(biāo)簽>

子組件中:

<div>
  <slot name="default"></slot> // 我會渲染到name=default的slot中
</div>

<div>
  <slot name="test1"></slot> // 我會渲染到name=test1的slot中
</div>

<div>
  <slot name="test2"></slot> // 我會渲染到name=test2的slot中
</div>

注意,上述例子中,都有v-slot綁定default屬性的情況,這里需要說明下,vue中的插槽用法,default屬性的模板和插槽存在特殊的對應(yīng)情況,而比較容易混亂的點(diǎn)就在這里,這也是vue官網(wǎng)插槽文檔讓人看得很蒙圈的地方,因?yàn)楣倬W(wǎng)并沒有給我們分區(qū)域的講述通用情況和特殊情況,而是穿插著講,讓人容易理不清楚關(guān)系。


3.插槽的默認(rèn)值

子組件的slot標(biāo)簽中的值可以寫入內(nèi)容,這部分內(nèi)容會在沒有對應(yīng)的模板內(nèi)容的時(shí)候,作為默認(rèn)值展示
父組件

<todo-item>
  <template v-slot:test1>
  我是模板1
  </template>
</todo-item>

子組件

<div>
  <slot name="test1">
  我是插槽1
  </slot>
</div>
<div>
  <slot name="test2">
  我是插槽2
  </slot>
</div>

渲染結(jié)果

<div>
我是模板1
</div>
<div>
我是插槽2
</div>

4.v-slot指令動態(tài)綁定屬性

<script>
export default {
  data() {
    return {
      slotName: 'test1'
    }
  }
}
</script>
<template>
  <todo-item>
    <template v-slot:[slotName]>
    </template>
  </todo-item>
</template>
<style>
</style>

具名插槽的寫法具備通用性,學(xué)會了具名插槽寫法,那么插槽的用法已經(jīng)能夠掌握8成了。下面將展開的是插槽中的特殊對應(yīng)關(guān)系


5.default模板和插槽中的特殊對應(yīng)關(guān)系

------------默認(rèn)的default模板和插槽-----------
父組件

<todo-item>
  我是default的內(nèi)容
  <template v-slot:test>
    我會渲染到name=test的slot標(biāo)簽中
  </template>
  我也是default的內(nèi)容
</todo-item>

子組件情形1

<div>
  <slot></slot>
</div>

子組件情形2

<div>
  <slot name="default"></slot>
</div>

渲染結(jié)果都是

<div>
  我是default的內(nèi)容  我也是default的內(nèi)容
</div>

由于兩種情形中都沒有name屬性是test的插槽,所以渲染結(jié)果中沒有出現(xiàn)test模板里的內(nèi)容。

上述例子中涵蓋了2個(gè)知識點(diǎn),首先通過子組件情形2能得到渲染結(jié)果,可以得出一個(gè)結(jié)論:

①.父組件中只要是不在template里的內(nèi)容,無論內(nèi)容在什么位置(必須在子組件標(biāo)簽里),默認(rèn)都是default模板的內(nèi)容,即
<todo-item>
  我是default的內(nèi)容 // 默認(rèn)算default模板內(nèi)容
  <template v-slot:test>
    我會渲染到name=test的slot標(biāo)簽中
  </template>
  我也是default的內(nèi)容 // 默認(rèn)算default模板內(nèi)容
</todo-item>
等價(jià)于
<todo-item>
  <template v-slot:default>
    我是default的內(nèi)容  我也是default的內(nèi)容
  </template>
  
  <template v-slot:test>
    我會渲染到name=test的slot標(biāo)簽中
  </template>
</todo-item>

default模板的內(nèi)容必定會渲染到defalut插槽中,所以,通過子組件情形1能得出渲染結(jié)果,也可以得出一個(gè)結(jié)論:

②.子組件中沒有指定name屬性的slot標(biāo)簽,默認(rèn)都是default插槽,即
<div>
  <slot></slot>
</div>
等價(jià)于
<div>
  <slot name="default"></slot>
</div>

最后還需要注意,模板和插槽的對應(yīng)關(guān)系是1對多的關(guān)系。即同名模板只能有一個(gè),但是同名插槽可以有無數(shù)個(gè),會同時(shí)渲染

以上內(nèi)容涵蓋了9成的插槽用法,足以滿足日常使用。下面將要對插槽作用域問題展開講解


6.模板內(nèi)容的作用域和插槽內(nèi)容的作用域

很簡單
1.模板內(nèi)容一般都是在父組件,所以模板內(nèi)容的作用域自然是父組件的作用域,父組件的動態(tài)內(nèi)容基本上取自父組件的變量或函數(shù),但是有特殊情況可以讀取到子組件傳出來的值,第3點(diǎn)會講。

2.同理,插槽一般都是在子組件,所以作用域自然在子組件,比如子組件插槽中放入了動態(tài)內(nèi)容作為默認(rèn)值,該動態(tài)內(nèi)容必定取值于子組件的變量,也只能讀取到子組件的變量和函數(shù)

3.特殊情況,父組件可以用子組件傳出來的值,這個(gè)時(shí)候會有寫法上的變化:
子組件

<script>
export default {
  data() {
    return {
      content: '我是子組件',
      show: true
    }
  }
}
</script>
<template>
  <div>
    <slot name="default" :todo-item-content="content" :show="show"></slot> // 通過格式:自定義屬性名="變量名"將值傳出
  </div>
</template>
<style>
</style>

父組件正常調(diào)用

<todo-item>
  <template v-slot:default="props"> //這里的props是我們自己定義的名稱,你可以自己起任意名,它是一個(gè)對象,包含子組件傳過來的所有值
    <div> // 這里需要注意的是,子組件用橫杠屬性名傳過來的值,在調(diào)用的時(shí)候要用駝峰名調(diào)用
        {{props.todoListContent}}
    </div>
    <div> // 不是橫杠屬性名傳過來的值可以直接調(diào)用
        {{props.show}}
    </div>
  </template>
</todo-item>

父組件解構(gòu)對象調(diào)用

<todo-item>
  <template v-slot:default="{todoListContent,show}">
    <div>
        {{todoListContent}}
    </div>
    <div>
        {{show}}
    </div>
  </template>
</todo-item>

渲染結(jié)果

<div>
  我是子組件
</div>
<div> 
    true
</div>

7.v-slot指令縮寫

v-slot指令可以變成縮寫的寫法,類似v-bind縮寫為:,v-on縮寫為@,v-slot可以縮寫為#
例如

<template v-slot:default>
</template>

<template v-slot:test1>
</template>

<template v-slot:test2>
</template>

等價(jià)于

<template #default>
</template>

<template #test1>
</template>

<template #test2>
</template>

8.default模板一種特殊的接受子組件插槽傳值的寫法(結(jié)合第6點(diǎn)的例子)

<todo-item #default="{todoListContent,show}">
  <div>
      {{todoListContent}}
  </div>
  <div>
      {{show}}
  </div>
</todo-item>

這里出現(xiàn)了v-slot指令直接綁定在子組件標(biāo)簽名上的情況,使用場景是,當(dāng)前模板只有一個(gè)default模板,并且需要獲取子組件傳來的值時(shí),才能這樣使用。

不接受傳值的情況,會報(bào)錯(cuò)

<todo-item #default> // 報(bào)錯(cuò),必須是接受傳值的寫法,即#default="xxx.."
  <div>
      我是模板
  </div>
</todo-item>

非default模板,也會報(bào)錯(cuò)
子組件

<script>
export default {
  data() {
    return {
      content: '我是子組件',
      show: true
    }
  }
}
</script>
<template>
  <div> // 這里是test插槽
    <slot name="test" :todo-item-content="content" :show="show"></slot> 
  </div>
</template>
<style>
</style>

父組件

// 這里是test模板,是具名模板的寫法,會報(bào)錯(cuò),因?yàn)檫@種寫法只支持default模板
<todo-item #test="{todoListContent,show}"> 
  <div>
      {{todoListContent}}
  </div>
  <div>
      {{show}}
  </div>
</todo-item>

除了default模板外,還存在其他模板時(shí),也會報(bào)錯(cuò)

<todo-item #default="{todoListContent,show}"> // default模板
  <div>
      {{todoListContent}}
  </div>
  <div>
      {{show}}
  </div>
  <template v-slot:test> // test模板  此處將不生效,并且會拋出警告
  </template>
</todo-item>

結(jié)語:

以上基本總結(jié)了插槽的所有用法,其中第5點(diǎn)和第8點(diǎn)的特殊情況都是針對default模板的,這一點(diǎn)一定要分清楚。

還有1點(diǎn)很關(guān)鍵的知識,即default模板和插槽不算是具名模板和插槽,第8點(diǎn)的非default模板會報(bào)錯(cuò)的原因,即該特殊情況不支持具名模板和插槽。但是default模板和插槽在平時(shí)寫的時(shí)候可以用具名模板和插槽的寫法,也可以用省略的寫法,即第5點(diǎn)描述的情況。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容