zoukankan      html  css  js  c++  java
  • Vue 组件化开发之插槽

    插槽的作用

       相信看过前一篇组件化开发后,你对组件化开发有了新的认识。

       插槽是干什么的呢?它其实是配合组件一起使用的,让一个组件能够更加的灵活多变,如下图所示,你可以将组件当作一块电脑主板,将插槽当作主板上的插槽,你可以随意的更换该主板上的零件。

      image-20201120214135847

       常见的应用场景,如淘宝的导航条:

      image-20201120214406472

      image-20201120214447581

      image-20201120214507606

       其实他们大体框架都是一样的,只是内容不同罢了。我们就可以将这个导航条定义为一个组件,而内容不同的地方都定义为一个插槽,到了不同的场景更换不同插槽即可。

    匿名插槽

       使用<slot>定义插槽,当父组件模板中引用子组件时,可向该插槽插入内容,如下所示:

    1. 一个组件中最多只能拥有一个匿名插槽,它其实也叫默认插槽
    2. 每个插槽都可以有默认值

      image-20201120222008958

    <body>
    
    <div id="app">
        <navigation>
            <span>这是导航</span>
        </navigation>
    </div>
    
    <template id="navigation">
        <main>
            <slot>没有内容时显示我</slot>
        </main>
    </template>
    
    <script src="./vue.js"></script>
    <script>
    
        Vue.component("navigation", {
            template: "#navigation",
        })
    
        const app = new Vue({
            el: "#app",
        })
    </script>
    
    </body>
    

    具名插槽

       实际开发中使用最多的还是具名插槽,给每个<slot>添加一个name属性。

       在插入内容时,指定slot属性为<slot>name属性进行一一插入即可。

       如下所示,定义了三种不同的搜索框,都是用的同一个组件:

      image-20201120225132419

    <style>
        @font-face {
            font-family: 'iconfont';  /* project id 1953712 */
            src: url('//at.alicdn.com/t/font_1953712_uiyayrse2ul.eot');
            src: url('//at.alicdn.com/t/font_1953712_uiyayrse2ul.eot?#iefix') format('embedded-opentype'),
            url('//at.alicdn.com/t/font_1953712_uiyayrse2ul.woff2') format('woff2'),
            url('//at.alicdn.com/t/font_1953712_uiyayrse2ul.woff') format('woff'),
            url('//at.alicdn.com/t/font_1953712_uiyayrse2ul.ttf') format('truetype'),
            url('//at.alicdn.com/t/font_1953712_uiyayrse2ul.svg#iconfont') format('svg');
        }
    
        .iconfont {
            font-family: "iconfont";
            font-size: 16px;
            font-style: normal;
        }
    
        i {
            flex-grow: 2;
            text-align: center;
        }
    
        * {
            padding: 0;
            margin: 0;
            box-sizing: border-box;
        }
    
    
        nav {
             100%;
            background-color: rgba(255, 162, 109, 0.8);
            padding: 10px;
            margin-bottom: 20px;
        }
    
        .navigation {
            display: inline-flex;
            justify-content: space-around;
            align-items: center;
             100%;
        }
    
        input {
            flex-grow: 6;
            border-radius: 3rem;
            text-align: center;
            outline: none;
        }
    
    </style>
    <body>
    
    <div id="app">
    	<!-- 第一个个导航条,中间用默认的input框 -->
        <nav>
            <navigation class="navigation">
            	<!-- 插入时,指定slot属性 -->
                <i class="iconfont" slot="left" :style="{fontSize:'2rem'}">&#xe628;</i>
                <i class="iconfont" slot="right" :style="{fontSize:'2rem'}">&#xe662;</i>
            </navigation>
        </nav>
    
    	<!-- 第二个导航条,不需要默认的input框,所以用div填充 -->
        <nav style="background-color: aliceblue">
            <navigation class="navigation">
                <i class="iconfont" slot="left" :style="{fontSize:'2rem'}">&#xe737;</i>
                <div slot="mid" style=" 70%;text-align: center">双十一狂欢夜</div>
                <i class="iconfont" slot="right" :style="{fontSize:'2rem'}">&#xe600;</i>
            </navigation>
        </nav>
    
    	<!-- 第三个导航条,不需要默认的input框,所以用div填充 -->
        <nav style="background-color: #ffaad8">
            <navigation class="navigation">
                <i class="iconfont" slot="left" :style="{fontSize:'2rem'}">&#xe61a;</i>
                <div slot="mid" style=" 70%;text-align: center">我的资料</div>
                <i class="iconfont" slot="right" :style="{fontSize:'2rem'}">&#xe654;</i>
            </navigation>
        </nav>
    
    </div>
    
    <template id="navigation">
        <main>
        	<!-- 给插槽取名 name属性-->
            <slot name="left"></slot>
            <slot name="mid"><input type="text" placeholder="输入你的搜索项" :style="{height:'2rem'}"></slot>
            <slot name="right"></slot>
        </main>
    </template>
    
    <script src="./vue.js"></script>
    <script>
    
        Vue.component("navigation", {
            template: "#navigation",
        })
    
        const app = new Vue({
            el: "#app",
        })
    </script>
    
    </body>
    
    

    编译作用域

       编译作用域的意思是,在那个组件的模板中,渲染时的数据就查找那个组件。

       如下所示,父组件和子组件都有一个变量show,同时子组件中拥有一个插槽,将插槽插入子组件时用了v-show指令,那么这个被插入的元素会去找子组件的show还是找父组件的show呢?

       答案是父组件,因为插入插槽的元素是书写在父组件中的。

      image-20201120225818345

    <body>
    
    <div id="app">
        <cpn>
            <span slot="cpn-slot" v-show="show">引用父组件的show</span>
        </cpn>
    </div>
    
    <!-- 子组件模板 -->
    <template id="cpn-template">
        <div>
            <span v-show="show">引用子组件的show</span>
            <slot name="cpn-slot"></slot>
        </div>
    </template>
    
    <script src="./vue.js"></script>
    <script>
        var cpn = {
            template: "#cpn-template",
            data() {
                return {
                    show: false,
                }
            }
        }
        const app = new Vue({
            el: "#app",
            data: {
                show: true,
            },
            components: {  // Vue实例内部进行注册
                cpn,
            },
        })
    </script>
    </body>
    

    作用域插槽

       作用域插槽使用较少,它核心理念就是用父组件来渲染子组件。

       如下代码中出现一个问题,我们如果直接进行渲染,就把代码写死了,要想改变样式那么所有引用该子组件的地方样式都会改变:

      image-20201115192237216

    <body>
    <div id="app">
        <cpn :user-msg="msg"></cpn>
    </div>
    
    <!-- 子组件模板 -->
    <template id="cpn-template">
        <div>
            <ul>
                <li v-for="row in userMsg">{{row}}</li>
            </ul>
        </div>
    </template>
    
    <script src="./vue.js"></script>
    <script>
        var cpn = {
            template: "#cpn-template",
            props: ["userMsg",],
        }
    
        const app = new Vue({
            el: "#app",
            data: {
                msg: {
                    id: 1,
                    name: "yunya",
                    age: 18,
                }
            },
            components: {
                cpn,
            }
        })
    </script>
    </body>
    

       此时就可以使用作用域插槽,由父组件来渲染子组件。

       使用作用域插槽遵循三个点:

      1.必须使用DOM不识别的标签,如template进行接收子组件插槽属性

      2.接收子组件插槽属性的属性是scope

      3.scope是一个对象

       以下是渲染结果,由父组件渲染子组件,给他加粗:

      image-20201115192834871

    <body>
    <div id="app">
        <cpn :user-msg="msg">
            <template slot="message" scope="v">
                <ul>
                    <li><b>{{v.field}}</b></li>
                </ul>
            </template>
        </cpn>
    </div>
    
    <!-- 子组件模板 -->
    <template id="cpn-template">
        <div>
            <slot name="message" v-for="row in userMsg" :field="row"></slot>
        </div>
    </template>
    
    <script src="./vue.js"></script>
    <script>
        var cpn = {
            template: "#cpn-template",
            props: ["userMsg",],
        }
    
        const app = new Vue({
            el: "#app",
            data: {
                msg: {
                    id: 1,
                    name: "yunya",
                    age: 18,
                }
            },
            components: {
                cpn,
            }
        })
    </script>
    </body>
    

      再配一张图吧,看看每次的v是长什么样子:

      image-20201115193235010

  • 相关阅读:
    2019-2020-1 20175311 20175324 20175330 实验四 外设驱动程序设计
    2019-2020-1 20175311 《信息安全系统设计基础》第十一周学习总结
    2019-2020-1《信息安全系统设计》20175311 20175324 20175330 实验三实时系统
    【2019-2020-1】20175330 20175324 20175311 实验二 固件程序设计
    2018-2019-1 20175311 20175324 20175330 实验一 开发环境的熟悉
    2019-2020-1 20175311胡济栋 《信息安全系统设计基础》第五周学习总结教材学习
    恶意代码分析
    免杀进阶
    Android的安装
    免杀原理与实践
  • 原文地址:https://www.cnblogs.com/Yunya-Cnblogs/p/14013464.html
Copyright © 2011-2022 走看看