- 原文地址:https://github.com/vuejs/rfcs/blob/master/active-rfcs/0001-new-slot-syntax.md
- 作者:yyx990803, galchenkov,vaaski
- Git Commit:f38a8f2
以下為原文翻譯
- 開始時間: 2019-01-14
- 目標主版本: 2.x & 3.x
- 相關Issues: https://github.com/vuejs/vue/issues/7740, https://github.com/vuejs/vue/issues/9180, https://github.com/vuejs/vue/issues/9306
- 實現(xiàn) PR:
綜述
引入一個新的作用域插槽語法:
新的指令
v-slot使用同一個指令語法統(tǒng)一了slot與slot-scope的語法。v-slot的簡化寫法可以同時統(tǒng)一有作用域的插槽和普通插槽。
基本示例
使用v-slot來聲明傳入<foo>作用域插槽的屬性。
<!-- 默認插槽 -->
<foo v-slot="{ msg }">
{{ msg }}
</foo>
<!-- 命名插槽 -->
<foo>
<template v-slot:one="{ msg }">
{{ msg }}
</template>
</foo>
動機
在我們最初引入作用域插槽時,代碼因為總是需要使用 <template slot-scope>而變得十分啰嗦:
<foo>
<template slot-scope="{ msg }">
<div>{{ msg }}</div>
</template>
</foo>
為了簡化代碼,在2.5中我們賦予了插槽元素直接使用slot-scope的能力:
<foo>
<div slot-scope="{ msg }">
{{ msg }}
</div>
</foo>
同時也可以直接用在插槽組件上:
<foo>
<bar slot-scope="{ msg }">
{{ msg }}
</bar>
</foo>
然而,上述的用法帶來了一些問題:slot-scope的位置并不能總是明確地反應作用域變量來自哪個組件。比如slot-scope雖然聲明在<bar>組件上,但它實際上定義了一個由<foo>的默認插槽提供的作用域變量。
這種情況隨著嵌套加深愈來愈復雜:
<foo>
<bar slot-scope="foo">
<baz slot-scope="bar">
<div slot-scope="baz">
{{ foo }} {{ bar }} {{ baz }}
</div>
</baz>
</bar>
</foo>
我們很難立即明確地指出,在這個模版中是哪個組件提供的變量。
有人建議我們應該允許把slot-scope直接聲明在組件本身上以表示它的默認插槽范圍:
<foo slot-scope="foo">
{{ foo }}
</foo>
不幸的是,這種寫法在嵌套組件出現(xiàn)時會有歧義:
<parent>
<foo slot-scope="foo"> <!-- parent還是foo提供的? -->
{{ foo }}
</foo>
</parent>
這就是我認為在template之外使用slot-scope是個錯誤的原因。
為什么使用新的指令而不是修改slot-scope?
如果時間可以倒流,我可能會改變slot-scope的語義,但:
現(xiàn)在這樣做會導致breaking change,這意味著我們永遠無法在2.x中使用這個特性。
即使我們在3.x中才改變已有語法的語義,在使用搜索引擎查詢到過時的文檔時,也會給未來的學習者帶來非常多的問題。所以我們決定引入一個新的語法。
在3.x中,我們計劃統(tǒng)一插槽類型使其不需要區(qū)分概念上的插槽和作用域插槽。一個插槽不論有沒有屬性都是插槽。隨著概念的統(tǒng)一,就沒有必要繼續(xù)占用
slot與slot-scope兩個特殊的屬性了,并且在一個相同的結構下統(tǒng)一語法也是很好的選擇。
細節(jié)設計
引入新指令: v-slot.
-
他可以用在
<template>插槽容器上代表插槽會傳入組件,指令參數(shù)可以表示插槽的名字。<foo> <template v-slot:header> <div class="header"></div> </template> <template v-slot:body> <div class="body"></div> </template> <template v-slot:footer> <div class="footer"></div> </template> </foo>如果一個插槽是作用域插槽有屬性,我們可以使用指令值來聲明插槽屬性。
v-slot的值與slot-scope的值完全相同,所以支持JavaScript參數(shù)解構語法。<foo> <template v-slot:header="{ msg }"> <div class="header"> Message from header slot: {{ msg }} </div> </template> </foo> -
直接在組件上使用無參
v-slot代表組件的默認插槽是一個作用域插槽,而傳入插槽的屬性應該和聲明的屬性相同。(翻譯不通順)<foo v-slot="{ msg }"> {{ msg }} </foo>
新舊對比
讓我們回顧一下這個提議是否能實現(xiàn)上文中的目標。
-
仍然支持大部分用例下的簡潔作用域插槽語法(只有默認插槽)
<foo v-slot="{ msg }">{{ msg }}</foo> -
作用域變量與提供其之組件之間的關系更清晰:
讓我們再次觀察上文中的深層嵌套例子,注意
<foo>提供的作用域變量如何在<bar>上聲明等等。<foo> <bar slot-scope="foo"> <baz slot-scope="bar"> <div slot-scope="baz"> {{ foo }} {{ bar }} {{ baz }} </div> </baz> </bar> </foo>
這是新語法下的等價例子:
<foo v-slot="foo">
<bar v-slot="bar">
<baz v-slot="baz">
{{ foo }} {{ bar }} {{ baz }}
</baz>
</bar>
</foo>
注意組件提供的作用域變量直接聲明在組件自身上。新的語法使作用域變量與提供其之組件之間的關系更清晰。
更多用法比較
默認文本插槽
<!-- old -->
<foo>
<template slot-scope="{ msg }">
{{ msg }}
</template>
</foo>
<!-- new -->
<foo v-slot="{ msg }">
{{ msg }}
</foo>
默認元素插槽
<!-- old -->
<foo>
<div slot-scope="{ msg }">
{{ msg }}
</div>
</foo>
<!-- new -->
<foo v-slot="{ msg }">
<div>
{{ msg }}
</div>
</foo>
嵌套默認插槽
<!-- old -->
<foo>
<bar slot-scope="foo">
<baz slot-scope="bar">
<template slot-scope="baz">
{{ foo }} {{ bar }} {{ baz }}
</template>
</baz>
</bar>
</foo>
<!-- new -->
<foo v-slot="foo">
<bar v-slot="bar">
<baz v-slot="baz">
{{ foo }} {{ bar }} {{ baz }}
</baz>
</bar>
</foo>
命名插槽
<!-- old -->
<foo>
<template slot="one" slot-scope="{ msg }">
text slot: {{ msg }}
</template>
<div slot="two" slot-scope="{ msg }">
element slot: {{ msg }}
</div>
</foo>
<!-- new -->
<foo>
<template v-slot:one="{ msg }">
text slot: {{ msg }}
</template>
<template v-slot:two="{ msg }">
<div>
element slot: {{ msg }}
</div>
</template>
</foo>
命名插槽和默認插槽的混合嵌套用法
<!-- old -->
<foo>
<bar slot="one" slot-scope="one">
<div slot-scope="bar">
{{ one }} {{ bar }}
</div>
</bar>
<bar slot="two" slot-scope="two">
<div slot-scope="bar">
{{ two }} {{ bar }}
</div>
</bar>
</foo>
<!-- new -->
<foo>
<template v-slot:one="one">
<bar v-slot="bar">
<div>{{ one }} {{ bar }}</div>
</bar>
</template>
<template v-slot:two="two">
<bar v-slot="bar">
<div>{{ two }} {{ bar }}</div>
</bar>
</template>
</foo>
缺點
-
引入新語法會使大量的學習資料過時,新用戶可能在學習已有的教程后接觸新語法時感到困惑。
- 我們需要良好的文檔說明語法的遷移。
默認的用法中
v-slot="{ msg }"并未明確的表達出msg應當作為參數(shù)傳入插槽。
替代方案
- 新的特殊屬性
slot-props(之前版本的草案); - 用指令(
v-scope)替代原先的特殊屬性#9180; - 可替代的簡寫符號(
&)由@rellect[提出];(https://github.com/vuejs/vue/issues/9306#issuecomment-453946190)
采用策略
這個特性完全向后兼容,所以我們可以在一個小版本中推出它(計劃在2.6中)(實際上已發(fā)布)
slot-scope會逐漸被廢棄:首先它會在文檔中標記為廢棄,我們會鼓勵所有人使用新語法,但是我們目前不會提示廢棄消息,因為它在最新的語法遷移中并非最高優(yōu)先級。
在3.0中我們確實希望移除slot-scope用法,并只支持新語法。我們會發(fā)出廢棄slot-scope的信息以減輕遷移至3.0的壓力。
由于這是一個良好定義的語法變化,我們可能提供一個自動化遷移工具來幫助你的模版文件進行遷移。
以上為原文翻譯