当前位置: 首页 > 科技观察

一个案例看懂Vue.jsscopedslot

时间:2023-03-13 13:53:17 科技观察

Scopedslot是Vue.js中一个非常有用的特性,可以显着提高组件的通用性和复用性。问题是,这并不容易理解。试图弄清楚父子作用域关系的复杂性就像解决一个棘手的数学方程式一样痛苦。当你无法理解某件事时,最好的方法就是体验它在解决问题过程中的应用。本文将向您展示如何使用作用域插槽构建可重用的列表组件。注:完整代码可以去Codepen查看最基本的组件。我们即将构建的组件称为my-list,它用于显示一系列项目。它的特别之处在于,您可以自定义每次使用该组件时列表项的呈现方式。让我们从最简单的单个列表开始:几何名称和边数的数组。app.jsVue.component('my-list',{template:'#my-list',data(){return{title:'Shapes',shapes:[{name:'Square',sides:4},{name:'Hexagon',sides:6},{name:'Triangle',sides:3}]};}});newVue({el:'#app'});index.html

添加一点样式,大概如下图所示:moregeneralmy-list现在我们想让我的列表更通用并且可以呈现任何类型的列表。这次我们展示了一堆颜色名称和相应的颜色方块。为此,我们需要抽象出上面列表特有的数据。由于列表中的项目可能具有不同的结构,我们将给my-list一个插槽,让父组件定义列表的显示方式。app.jsVue.component('my-list',{template:'#my-list',props:['title']});index.html现在,我们在根实例中创建my-list组件的两个实例来显示两个测试用例列表:lists:app.jsnewVue({el:'#app',data:{shapes:[{name:'Square',sides:4},{name:'Hexagon',sides:6},{name:'Triangle',sides:3}],colors:[{name:'Yellow',hex:'#F4D03F',},{name:'Green',hex:'#229954'},{name:'Purple',hex:'#9B59B6'}]}});
{{shape.name}}({{shape.sides}}sides)
<div>
{{color.name}}
的效果如下图所示:my-list应该是一个显示列表的组件,但是我们抽象了渲染列表所需的逻辑。在父组件中,这样子组件只是用来把列表包裹在这里,显得大材小用。更糟糕的是,两个组件的声明中有很多重复(例如,)。如果我们能把这些代码写在子组件中,那么子组件就不再是“打酱油的角色”了。Scopeslots普通的slots不能满足我们的需求。这时候作用域槽就派上用场了。Scopedslots允许您将模板而不是已经呈现的元素传递给插槽。之所以称为“作用域”槽,是因为虽然模板是在父作用域中渲染的,但它可以获取到子组件的数据。例如,具有作用域插槽的子组件可能如下所示:.这个模板元素会有一个scope(译者注:Vue2.6之后改为v-slot属性)属性指向一个对象,任何添加到slot(位于子组件模板中)的属性都会作为这个对象的属性。Hellofromparent{{props.my-prop}}将呈现为:
HellofromparentHellofromchild
在my-list中使用作用域槽我们通过props将两个列表数组传递给my-list。然后把普通的slots换成scopedslots,这样my-list就可以负责迭代列表项,而父组件仍然可以定义每个item的具体显示方式。index.html然后我们让my-list迭代项目。在v-for循环中,item是当前迭代项的别名。我们可以创建一个插槽并通过v-bind="item"将该项目绑定到插槽。app.jsVue.component('my-list',{template:'#my-list',props:['title','items']});index.html注意:可能你之前没有见过没有参数的v-bind用法。这种用法会将整个对象的所有属性绑定到当前元素。这种用法在scopedslots的时候是很常见的,因为绑定的对象可能有很多属性,一一列举出来手动绑定显然太麻烦了。现在,回到根实例,在my-list槽中声明一个模板。首先看geometries列表(第一个例子中的列表),我们声明的模板必须有一个scope属性,这里赋值为shape。shape别名使我们可以访问作用域插槽。在模板中,我们可以继续使用原始示例中的标记来显示项目。
{{shape.name}}({{shape.sides}}边)
整个模板大概如下:
{{shape.name}}({{shape.sides}}sides)
{{color.name}}结论虽然使用scopeslots后代码量并没有减少,但是我们将通用功能交给了子组件,显着提高了代码的健壮性。完整代码的Codepen在这里:https://codepen.io/anthonygor...译者注:Vue.js2.6.0changedslot-scopetov-slot