Vue.js 教程

Vue.js 插槽特殊用法

前面介绍了插槽通过插槽 prop 访问子组件的数据。

插槽 prop 允许我们将插槽转换为可复用的模板,这些模板可以基于输入的 prop 渲染出不同的内容。这在设计封装数据逻辑的同时,还允许父级组件自定义部分布局的可复用组件时是最有用的。

例如,我们要实现一个 <todo-list> 组件,它是一个列表且包含布局和过滤逻辑:

<ul>
   <li v-for="todo in filteredTodos" v-bind:key="todo.id">
       {{ todo.text }}
   </li>
</ul>

我们可以将每个 todo 作为父级组件的插槽,以此通过父级组件对其进行控制,然后将 todo 作为一个插槽 prop 进行绑定:

<ul>
   <li v-for="todo in filteredTodos" v-bind:key="todo.id">
       <!-- 我们为每个 todo 准备了一个插槽,将 `todo` 对象作为一个插槽的 prop 传入。-->
       <slot name="todo" v-bind:todo="todo">
           <!-- 默认内容 -->
           {{ todo.text }}
       </slot>
   </li>
</ul>

现在当我们使用 <todo-list> 组件的时候,我们可以选择为 todo 定义一个不一样的 <template> 作为替代方案,并且可以从子组件获取数据:

<todo-list v-bind:todos="todos">
   <template v-slot:todo="{ todo }">
       <span v-if="todo.isComplete">✓</span>
       {{ todo.text }}
   </template>
</todo-list>

完整示例

<html>
<head>
   <meta charset="UTF-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>Vue</title>
   <!-- 使用 CDN 引入 Vue 库 -->
   <!-- <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script> -->
   <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.7.9/vue.js"></script>
   <style type="text/css">
       html,body { padding:20px; margin:0; width:100%; height:100%; box-sizing: border-box;}
       #app .condition { width:100%; }
       .todo_ul { list-style: none; padding: 0; }
       .todo_ul li { padding: 5px; }
       .todo_status {
           background: #F0F0F0; font-size: 12px; padding: 2px 6px;
           border-radius: 5px; margin-right: 10px;
       }
       .todo_status_ok { background:green; color:#FFF; }
       .btn_active { font-weight: bold; color: green; font-size: 16px; }
   </style>
</head>
<body>

   <div id="app">
       <p>
           <button v-bind:class="{btn_active: currentStyle == ''}" v-on:click="changeStyle('')">默认样式</button>
           <button v-bind:class="{btn_active: currentStyle == 'style1'}" v-on:click="changeStyle('style1')">样式一</button>
           <button v-bind:class="{btn_active: currentStyle == 'style2'}" v-on:click="changeStyle('style2')">样式二</button>
       </p>
       <p>
           <input type="text" placeholder="TODO 查询" v-model="condition" />
       </p>

       <!-- TODO 列表 -->
       <todo-list v-bind:filtered_todos="filteredTodos">
           <!-- 自定义样式一 -->
           <template v-if="currentStyle == 'style1'" v-slot:todo="{ todo }">
               <input type="checkbox" v-model="todo.isComplete" />
               {{ todo.text }}
           </template>

           <!-- 自定义样式二 -->
           <template v-else-if="currentStyle == 'style2'" v-slot:todo="{ todo }">
               <span v-if="todo.isComplete" class="todo_status todo_status_ok">已完成</span>
               <span v-else  class="todo_status">未完成</span>
               {{ todo.text }}
           </template>
       </todo-list>
   </div>

   <script type="text/javascript">
       Vue.component('todo-list', {
           props: [ "filtered_todos" ],
           template: `
               <ul>
                   <li v-for="todo in filtered_todos" v-bind:key="todo.id">
                       <!-- 我们为每个 todo 准备了一个插槽,将 todo 对象作为一个插槽的 prop 传入。-->
                       <slot name="todo" v-bind:todo="todo">
                           <!-- 默认内容 -->
                           {{ todo.isComplete ? "√" : "-" }}
                           {{ todo.text }}
                       </slot>
                   </li>
               </ul>
           `
       });

       var app = new Vue({
           el: "#app",
           data: {
               currentStyle: "",
               condition: "",
               todoList: [
                   { id:1, text:"搭建 Vue.js 开发环境", isComplete:true },
                   { id:2, text:"学习 Vue.js 基础语法", isComplete:true },
                   { id:3, text:"学习 Vue.js 组件知识", isComplete:false },
                   { id:4, text:"学习 Vue.js 插槽知识", isComplete:false },
                   { id:5, text:"学习 Vue.js 工作原理", isComplete:false },
                   { id:6, text:"利用 Vue.js 实现 ToDO App", isComplete:false }
               ]
           },
           computed: {
               filteredTodos: function(){
                   return this.todoList.filter(item => {
                       return (item.text || "").indexOf(this.condition) != -1;
                   });
               }
           },
           methods: {
               changeStyle: function(style) {
                   this.currentStyle = style;
               }
           }
       });
   </script>

</body>
</html>

运行效果图:

说说我的看法
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
公众号