zoukankan      html  css  js  c++  java
  • Vue 插槽

    Vue 插槽

    什么是插槽

    slot翻译为插槽,在生活中有很多地方都有插槽,电脑的USB插槽,插板当中的电源插槽。

    插槽的目的是让我们原来的设备具有更多的拓展性。

    比如电脑的USB,我们可以接入U盘、硬盘、手机、音响、键盘、鼠标等等。

    组件的插槽

    组件的插槽也是为了让我们封装的组件更加具有拓展性。

    让使用者可以决定组件内部的一些内容到底展示什么。

    插槽就是在组件中预留的一个空间。可以自行选择在组件实例中插入哪些内容。

    例如存在如下需求:

    1、在页面中引入一组件,创建十个实例。每个实例都由自己的“个性”,1组件中使用a标签,2使用button,3使用input。。。

    2、移动网站中的导航栏,封装为一个导航栏,在导航栏中预留若干个位置,预留五个插槽,在插槽中放入具体的实现。

    如何封装这类组件?

    抽取共性、保留不同

    最好的封装方式就是将共性抽取到组件中,将不同暴露为插槽。

    一旦我们预留了插槽,就可以让使用者根据自己的需求。决定插槽中插入什么内容。

    是搜索框、是文字、还是菜单,由调用者自己来决定。

    slot插槽

    在子组件中,预留一对标签,就可以在父组件中创建子组件时,在其内填充自定义内容。

    子组件:

    <template>
        <div name='chidren'>
            <h1 v-text="title"></h1>
            <p v-text="info"></p>
            <input type="text" v-model="dparam" @input="valChange">
            <button @click="giao">发射属性到父组件</button>
            <button @click="btnClick">在子组件中获取父组件</button>
            <slot></slot>
        </div>
    </template>
    

    slot中也可以添加默认值。添加了默认值以后,即使没有在组件的内部添加新标签,也会默认加上默认值。

    添加默认值:

    <template>
        <div name='chidren'>
            <h1 v-text="title"></h1>
            <p v-text="info"></p>
            <input type="text" v-model="dparam" @input="valChange">
            <button @click="giao">发射属性到父组件</button>
            <button @click="btnClick">在子组件中获取父组件</button>
            <slot><button>我是默认值</button></slot>
        </div>
    </template>
    

    如果添加了默认值,但是父组件内进行了填充,那么默认值就不会生效。

    父组件:

    <template>
        <div name="parent">
            <h1 v-text="title"></h1>
            <input type="text" v-model="title">
            <button @click="btnClick">访问子组件中的方法</button>
            <Childred ref="child" @giao="giao" @title-change="titleChange" :title="title" :info="info">
                <h2>插槽中的具体内容</h2>
            </Childred>
        </div>
    </template>
    

    如果在一个插槽中,添加多个标签,那么这几个标签都会显示。

    具名插槽<2.6+已废除>

    如果在一个组件内,需要预留多个插槽,但是预留多个插槽在父组件内添加元素时,默认会将三个插槽的都替换。这就需要预留插槽的名称,在父组件内创建子组件实例的时候。指定其名称。直接指定slot的name属性即可。在替换时,需要指定slot="name"

    parent:

    <template>
        <div name='chidren'>
            <h1 v-text="title"></h1>
            <p v-text="info"></p>
            <input type="text" v-model="dparam" @input="valChange">
            <button @click="giao">发射属性到父组件</button>
            <button @click="btnClick">在子组件中获取父组件</button>
            <slot name="aa"><button>我是默认值</button></slot>
            <slot name="bb"><button>我是默认值</button></slot>
            <slot name="cc"><button>我是默认值</button></slot>
        </div>
    </template>
    

    childred:

    <template>
        <div name="parent">
            <h1 v-text="title"></h1>
            <input type="text" v-model="title">
            <button @click="btnClick">访问子组件中的方法</button>
            <Childred ref="child" @giao="giao" @title-change="titleChange" :title="title" :info="info">
                <h2 slot="bb">插槽中的具体内容</h2>
            </Childred>
        </div>
    </template>
    

    具名插槽2.6+ 版本推荐写法

    子组件的定义没有变化,父组件的引入修改为了以下的形式:

    //组件调用时
    <MyFooter v-red :age.sync="age">
      <template v-slot:footer>
      //这里v-slot:后边的值与组件内的slot的name属性对应,也就是插槽的名称。
          <div>list</div>
      </template>
    </MyFooter>
    //书写组件时
    <template>
        <div>
            {{age}}
            <div>
                <slot name='footer' />
                //这里name的值就是这个插槽的名称。
            </div>
        </div>
    </template>
    

    即,在组件内部创建一个template标签,使用v-slot:name,代替原来的slot="name"

    作用域插槽

    作用域的介绍

    真正的学习作用域插槽之前,我们需要先了解一个概念:编译作用域

    Vue官方的解释:父组件模板的所有数据都会在父级作用域内编译,子组件模板的所有东西都会在子组件作用域内编译。

    我理解的作用域就是 当父组件中使用子组件实例时,子组件中定义的data和父组件中的data的生效范围。何时会使用组件内部的data,何时会使用父组件中的data。

    子组件:

    <template>
        <div name='chidren'>
            <h1 v-text="title"></h1>
            <p v-text="info"></p>
            <input type="text" v-model="dparam" @input="valChange">
            <button @click="giao">发射属性到父组件</button>
            <button @click="btnClick">在子组件中获取父组件</button>
            <slot name="aa"><button>我是默认值aa</button></slot>
            <slot name="bb"><button>我是默认值bb</button></slot>
            <slot v-show="isShow" name="cc"><button>我是默认值cc</button></slot>
        </div>
    </template>
    
    <script>
    export default {
        name: 'chidren',
        props: {
            title: String,
            info: String
        },
        data(){
            return{
                param: 'GIAO',
                dparam: this.title,
                isShow: false
            }
        },
        methods:{
            showInfo: function(){
                alert(this.param);
            },
            giao: function(){
                this.$emit('giao',this.param);
            },
            valChange: function(event){
                let newVal = event.target.value;
                this.param = newVal;
                this.$emit('title-change',newVal);
            },
            btnClick: function(){
                console.log(this.$parent.title);
            }
        }/*,
        watch:{
            dparam(oldVal,newVal){
                this.param = newVal;
                this.$emit('title-change',newVal);
            }
        }*/
    }
    </script>
    
    <style>
    
    </style>
    

    父组件:

    <template>
        <div name="parent">
            <h1 v-text="title"></h1>
            <input type="text" v-model="title">
            <button @click="btnClick">访问子组件中的方法</button>
            <Childred v-show="isShow" ref="child" @giao="giao" @title-change="titleChange" :title="title" :info="info">
                <h2 slot="bb">插槽中的具体内容</h2>
            </Childred>
        </div>
    </template>
    
    <script>
    import Childred from './Chidren';
    export default {
        name: 'parent',
        data(){
            return {
                title: 'rayfoo',
                info: '真帅',
                isShow: true
            }
        },
        methods:{
            giao: function(param){
                alert(param);
            },
            titleChange: function(newVal){
                this.title = newVal;
            },
            btnClick: function(){
                console.log(this.$children[0].param);
                this.$children[0].showInfo();
                console.log(this.$refs.child.param);
            }
        },
        components:{
            Childred
        }
    }
    </script>
    
    <style>
    
    </style>
    

    此时,子组件和父组件中都有isShow,但是它们的作用范围却是不一样的

    2.6+中使用作用域插槽

    作用域插槽是slot中一个比较难以理解的点,且官方文档说的又有点不清晰。

    这里,我们用一句话对其做一个总结,然后我们在后续的案例中来体会:

    • 父组件替换插槽的标签,但是内容由子组件来提供

    需求:

    • 子组件中包括一组数据,比如clan['js','py','go']
    • 需要在多个界面中进行展示:
      • 某些界面以水平方向展示
      • 某些页面是以列表形式的
      • 某些是直接展示一个数组
    • 内容在子组件中,但是希望父组件告诉我们如何去展示,该怎么办呢?
      • 使用slot的作用域插槽即可。
    //组件调用
     <ul>
       <myli :title="val.title"
       >
       <template v-slot:footer="message">
           <div>{{message.aa}}</div>
       </template>
       </myli>
     </ul>
     //书写组件时
     <template>
        <li>
            <slot name='footer' :aa="title">
            </slot>
        </li>
    </template>
    
    

    此处的message是一个自定义的名称,其保存slot中的属性集合,通过message可以调用slot中的所有属性,简化了slot-scope的操作

    一句话概括就是v-slot :后边是插槽名称,=后边是组件内部绑定作用域值的映射。

    另一个具名插槽+作用域插槽的案例

    子组件:

        data(){
            return{
                hobby: ['抽烟','喝酒','烫头']
            }
        }
        <slot :hobby="hobby" name="cc"><button>我是默认值cc</button></slot>
    

    父组件:

            <Childred >
                <template v-slot:cc="prop">
                    <ul  v-for="(item,index) in prop.hobby" :key=index>
                        <li v-text="item"></li>
                    </ul>
                </template>
            </Childred>
    
  • 相关阅读:
    Return Largest Numbers in Arrays-freecodecamp算法题目
    Title Case a Sentence-freecodecamp算法题目
    Find the Longest Word in a String-freecodecamp算法题目
    Check for Palindromes-freecodecamp算法题目
    Factorialize a Number-freecodecamp算法题目
    Reverse a String-freecodecamp算法题目
    js拖动div
    Jquery $.ajax()方法详解
    jQuery中$.each()方法的使用
    echarts的pie图中,各区块颜色的调整
  • 原文地址:https://www.cnblogs.com/zhangruifeng/p/13539630.html
Copyright © 2011-2022 走看看