• Vue的插槽的简单介绍以及示例


    Vue插槽的概念

    Vue的插槽,是一种内容分发机制,但是我感觉它更加像组件的一种占位符的概念,通过插槽,等待组件外部传入复杂的内容。

    使用插槽的好处

    在以前的例子中todo-item插槽直接写在了todo-list插槽中,其实是比较不合理的,它会导致todo-list插槽比较死板,无法重用更多的其他组件。

     Vue.component("todo-list", {
            template: `
                    <ul>
                        <todo-item v-on:delete="handleDelete" v-for="item in list" data-wen="wen" :title="item.title" :del="item.del"></todo-item>
                    </ul>
                `,
            data: function() {
              return {
                
              };
            },
            methods:{
                
            }
          });
    

    通过插槽化改造,则可以允许使用todo-list组件的用户自行的传入想要使用的todo-item,而不是一个固定的内容。

    插槽改造过程

    改造示例:

    • 将todo-item组件从todo-list组件中移除,放到页面的html代码中。
    • 将todo-list组件中原todo-item的位置修改为
    • 因为todo-item移到了页面html代码中,所以需要将todo-list的data中的list,移回全局vue中,防止组件找不到list导致v-for报错;handleDelete同理也要移至全局vue中
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <meta http-equiv="X-UA-Compatible" content="ie=edge" />
        <title>Document</title>
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      </head>
      <body>
        <div id="app">
            <todo-list>
                <todo-item v-on:delete="handleDelete" v-for="item in list" data-wen="wen" :title="item.title" :del="item.del"></todo-item>
            </todo-list>
        </div>
    
        <script>
          Vue.component("todo-list", {
            template: `
                    <ul>
                        <slot></slot>
                    </ul>
                `,
            data: function() {
              return {
                
              };
            },
            methods:{
                
            }
          });
          Vue.component("todo-item", {
            props: {
              title: String,
              del: {
                type: Boolean,
                default: false
              }
            },
            template: `
                  <li>
                      <span v-if="!del">{{title}}</span>
                      <span v-else style="text-decoration:line-through">{{title}}</span>
                      <button v-show="!del" @click="handleClick">删除</button>
                  </li>`,
            data: function() {
              return {};
            },
            methods: {
                handleClick(){
                    console.log("点击删除按钮!");
                    this.$emit('delete',this.title);
                }
            }
          });
          var vm = new Vue({
            el: "#app",
            data: {
                list: [
                  {
                    title: "新课程1",
                    del: false
                  },
                  {
                    title: "新课程2",
                    del: true
                  },
                  {
                    title: "新课程3",
                    del: false
                  }
                ]
            },
            methods: {
                handleDelete(vtitle){
                    console.log("删除工程!",vtitle)
                }
            }
          });
        </script>
      </body>
    </html>
    

    效果和改造前是一模一样的。

    插槽的种类

    处理默认插槽外,还有具名插槽,作用域插槽等等。

    所谓的具名插槽就是指带有名称的插槽,解决的是一个组件中存在多个插槽的业务场景。比如有一个母版页组件,希望区分页头,页尾和页面主体。实现如下效果:

    <div class="container">
      <header>
        <!-- 我们希望把页头放这里 -->
      </header>
      <main>
        <!-- 我们希望把主要内容放这里 -->
      </main>
      <footer>
        <!-- 我们希望把页脚放这里 -->
      </footer>
    </div>
    

    那么这个组件应该这样编写

    <div class="container">
      <header>
        <slot name="header"></slot>
      </header>
      <main>
        <slot></slot>
      </main>
      <footer>
        <slot name="footer"></slot>
      </footer>
    </div>
    

    具体调用组件的位置,则有两种写法:

    一种是2.6之前的写法。

    <组件名>
    <p slot="header">头部段落</p>
    <p>主段落</p>
    <p slot="footer">尾部段落</p>
    </组件名>
    

    一种是2.6之后的写法

    <组件名>
    <template v-slot:header>
        <p>头部段落</p>
    </template>
    <p>主段落</p>
    <template v-slot:footer>
        <label>尾部段落</label>
    </template>
    </组件名>
    

    按照2.6之后的写法,我们尝试将todo-item组件中增加一个前置lable和后置lable

    • 在todo-item组件的template中的html中增加slot插槽,并标记名称
    • html页面的组件调用位置,使用template和v-slot的语法插入内容
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <meta http-equiv="X-UA-Compatible" content="ie=edge" />
        <title>Document</title>
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      </head>
      <body>
        <div id="app">
            <todo-list>
                <todo-item v-on:delete="handleDelete" v-for="item in list" data-wen="wen" :title="item.title" :del="item.del">
                    <template v-slot:pretext>
                        <label>前置文字</label>
                    </template>
                    <template v-slot:suftext>
                        <label>后置文字</label>
                    </template>
                </todo-item>
            </todo-list>
        </div>
    
        <script>
          Vue.component("todo-list", {
            template: `
                    <ul>
                        <slot></slot>
                    </ul>
                `,
            data: function() {
              return {
                
              };
            },
            methods:{
                
            }
          });
          Vue.component("todo-item", {
            props: {
              title: String,
              del: {
                type: Boolean,
                default: false
              }
            },
            template: `
                  <li>
                      <slot name="pretext"></slot>
                      <span v-if="!del">{{title}}</span>
                      <span v-else style="text-decoration:line-through">{{title}}</span>
                      <button v-show="!del" @click="handleClick">删除</button>
                      <slot name="suftext"></slot>
                  </li>`,
            data: function() {
              return {};
            },
            methods: {
                handleClick(){
                    console.log("点击删除按钮!");
                    this.$emit('delete',this.title);
                }
            }
          });
          var vm = new Vue({
            el: "#app",
            data: {
                list: [
                  {
                    title: "新课程1",
                    del: false
                  },
                  {
                    title: "新课程2",
                    del: true
                  },
                  {
                    title: "新课程3",
                    del: false
                  }
                ]
            },
            methods: {
                handleDelete(vtitle){
                    console.log("删除工程!",vtitle)
                }
            }
          });
        </script>
      </body>
    </html>
    

    作用域插槽:作用域插槽可以接收子组件传递的值,并根据不同的值显示不同的内容。如根据用户根据返回的值控制样式信息。

    作用域插槽示例:

    • 为todo-item的data属性增加返回值vRandom
    data: function() {
        return {
            vrandom:Math.random()
        };
    },
    
    • 在todo-item的template的html中通过v-bind绑定组件中的属性。
    template: `
        <li>
            <slot name="pretext" :val="vrandom"></slot>
            <span v-if="!del">{{title}}</span>
            <span v-else style="text-decoration:line-through">{{title}}</span>
            <button v-show="!del" @click="handleClick">删除</button>
            <slot name="suftext"></slot>
        </li>`,
    
    • 在使用组件时通过模板语法调用绑定的变量
        <div id="app">
            <todo-list>
                <todo-item v-on:delete="handleDelete" v-for="item in list" data-wen="wen" :title="item.title" :del="item.del">
                    <template v-slot:pretext="{val}">
                        <label>前置文字{{val}}</label>
                    </template>
                    <template v-slot:suftext>
                        <label>后置文字</label>
                    </template>
                </todo-item>
            </todo-list>
        </div>
    

    全部html代码为

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <meta http-equiv="X-UA-Compatible" content="ie=edge" />
        <title>Document</title>
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      </head>
      <body>
        <div id="app">
            <todo-list>
                <todo-item v-on:delete="handleDelete" v-for="item in list" data-wen="wen" :title="item.title" :del="item.del">
                    <template v-slot:pretext="{val}">
                        <label>前置文字{{val}}</label>
                    </template>
                    <template v-slot:suftext>
                        <label>后置文字</label>
                    </template>
                </todo-item>
            </todo-list>
        </div>
    
        <script>
          Vue.component("todo-list", {
            template: `
                    <ul>
                        <slot></slot>
                    </ul>
                `,
            data: function() {
              return {
                
              };
            },
            methods:{
                
            }
          });
          Vue.component("todo-item", {
            props: {
              title: String,
              del: {
                type: Boolean,
                default: false
              }
            },
            template: `
                  <li>
                      <slot name="pretext" :val="vrandom"></slot>
                      <span v-if="!del">{{title}}</span>
                      <span v-else style="text-decoration:line-through">{{title}}</span>
                      <button v-show="!del" @click="handleClick">删除</button>
                      <slot name="suftext"></slot>
                  </li>`,
            data: function() {
              return {
                  vrandom:Math.random()
              };
            },
            methods: {
                handleClick(){
                    console.log("点击删除按钮!");
                    this.$emit('delete',this.title);
                }
            }
          });
          var vm = new Vue({
            el: "#app",
            data: {
                list: [
                  {
                    title: "新课程1",
                    del: false
                  },
                  {
                    title: "新课程2",
                    del: true
                  },
                  {
                    title: "新课程3",
                    del: false
                  }
                ]
            },
            methods: {
                handleDelete(vtitle){
                    console.log("删除工程!",vtitle)
                }
            }
          });
        </script>
      </body>
    </html>
    

    组件的插槽还有一种带默认值的用法:在slot中增加默认内容

    template: `
        <li>
            <slot name="pretext" :val="vrandom"></slot>
            <span v-if="!del">{{title}}</span>
            <span v-else style="text-decoration:line-through">{{title}}</span>
            <button v-show="!del" @click="handleClick">删除</button>
            <slot name="suftext">默认尾部</slot>
        </li>`,
    

    如果调用组件时没有在插槽位置插入内容,则html展示以默认内容进行填充,如果有插内容则以插入值填充。

        <div id="app">
            <todo-list>
                <todo-item v-on:delete="handleDelete" v-for="item in list" data-wen="wen" :title="item.title" :del="item.del">
                    <template v-slot:pretext="{val}">
                        <label>前置文字{{val}}</label>
                    </template>
                    <template v-slot:suftext>
                        <label>后置文字</label>
                    </template>
                </todo-item>
            </todo-list>
        </div>
    

    效果
    image

        <div id="app">
            <todo-list>
                <todo-item v-on:delete="handleDelete" v-for="item in list" data-wen="wen" :title="item.title" :del="item.del">
                    <template v-slot:pretext="{val}">
                        <label>前置文字{{val}}</label>
                    </template>
                    <template v-slot:suftext>
                    </template>
                </todo-item>
            </todo-list>
        </div>
    

    或者

        <div id="app">
            <todo-list>
                <todo-item v-on:delete="handleDelete" v-for="item in list" data-wen="wen" :title="item.title" :del="item.del">
                    <template v-slot:pretext="{val}">
                        <label>前置文字{{val}}</label>
                    </template>
                </todo-item>
            </todo-list>
        </div>
    

    效果
    image

  • 相关阅读:
    《算法》第六章部分程序 part 5
    《算法》第六章部分程序 part 4
    《算法》第六章部分程序 part 3
    《算法》第六章部分程序 part 2
    《算法》第六章部分程序 part 1
    OpenGL Hello World
    《算法》第五章部分程序 part 3
    《算法》第五章部分程序 part 8
    《算法》第五章部分程序 part 7
    《算法》第五章部分程序 part 6
  • 原文地址:https://www.cnblogs.com/wenpeng/p/12274420.html
Copyright © 2020-2023  润新知