美文网首页Vue.js
Vue.js第3课-深入理解Vue组件(part03)

Vue.js第3课-深入理解Vue组件(part03)

作者: e20a12f8855d | 来源:发表于2019-05-16 11:41 被阅读30次

    七、Vue 中的作用域插槽

    接着上一章的内容,这一节来讲 Vue 中的作用域插槽。

    先创建一个名字叫做 child 的子组件,添加模板,然后在父组件中使用这个子组件,然后打开页面,显示 Child 没有问题。

    <div id="app">
        <child></child>
    </div>
    <script>
        Vue.component("child", {
            template: "<div>Child</div>"
        })
        var app = new Vue({
            el: "#app"
        })
    </script>
    

    那什么是作用域插槽呢?下面举一个具体的例子:Child 这个子组件要实现一个功能,去循环显示一个列表,那么就在子组件里定义一组数据,在 template 中使用 v-for 循环显示一个列表。

    <div id="app">
        <child></child>
    </div>
    <script>
        Vue.component("child", {
            data: function () {
                return {
                    list: [1, 2, 3, 4]
                }
            },
            template: `
                <div>
                    <ul>
                        <li v-for="item of list">{{item}}</li>
                    </ul>
                </div>
            `
        })
        var app = new Vue({
            el: "#app"
        })
    </script>
    

    打开页面,可以看到1、2、3、4被正常的显示了。

    接下来,我有一个需求,child 这个组件有可能在很多的地方被调用,我希望在不同的地方调用 child 组件的时候,这个列表到底怎么循环,这个样式不是我这个 child 组件所控制的,而是外部告诉我们这个组件选项应该如何渲染,也就是我们的代码要把这个 li 标签去掉,取而代之写一个 slot,然后通过 v-for 做一个循环,然后传一个内容进去,传一个 item 进去,等于 item,这段代码的意思是,我这个 child 组件去做一个列表的循环,但是列表项中的每一项怎么显示,我并不关心,具体怎么显示,由外部你来告诉我怎么显示。

    很显然,是外部的这个 child 调用的他,那么你就需要往子组件传递一个 slot,告诉子组件你该怎么显示列表的每一项。首先,一定要在外层套一个 template,这是一个固定的写法,同事同时要写一个 slot-scope="",引号里的属性值可以随便定义,例如写 props,它的意义是,当子组件用 slot 的时候,会往 slot 里传递一个 item 这样一个数据,那么我们在上面用 child 的时候,就可以用这个 item 数据,item 就写在 slot-scope 后跟的设个属性中,在 li 标签中通过插值表达式的形式渲染。看下边代码:

    <div id="app">
        <child>
            <template slot-scope="props">
                <li>{{props.item}}</li>
            </template>
        </child>
    </div>
    <script>
        Vue.component("child", {
            data: function () {
                return {
                    list: [1, 2, 3, 4]
                }
            },
            template: `
                    <div>
                        <ul>
                            <slot v-for="item of list" :item=item>{{item}}</slot>
                        </ul>
                    </div>
                `
        })
        var app = new Vue({
            el: "#app"
        })
    </script>
    

    打开页面,没有任何问题,1、2、3、4正常的渲染到页面上。这样,每一项显示什么就不是由子组件决定了,而是父组件调子组件的时候给子组件传递对应的模板,这就是作用域插槽的一个使用。

    从头看一下这段代码,首先父组件调用子组件的时候给他传了一个插槽,这个插槽叫做作用域插槽,作用域插槽必须是一个 template 开头和结尾的一个内容,同时这个插槽要声明子组件接受的数据都放在哪(例子中放到了 props 里),同时还要告诉子组件一个模板的信息,接收到 props 应该如何展示。

    什么时候使用作用域插槽呢?当子组件做循环,它的 dom 结构应该由外部传递进来的时候,这个时候我们去用作用域插槽。使用作用域插槽,子组件可以向父组件的插槽里面传数据,父组件传递过来的这个插槽如果想接收数据,必须在外层使用一个 template,同时通过 slot-scope 对应的属性的名字来接收传递过来的数据。上面代码,我传递一个 item 过来,在父组件的作用域插槽里面就可以接收到这个 item。

    八、动态组件与 v-once 指令

    1、动态组件

    先创建两个组件 child-one 和 child-two,然后在父组件中使用它们,然后再加一个 button,我希望当点击 button 的时候,一会 child-one 显示,一会儿 child-two 显示,也就是他俩做一个 toggle 的效果,我们可以通过如下方式实现:

    <div id="app">
        <child-one v-if="show === 'child-one'"></child-one>
        <child-two v-if="show === 'child-two'"></child-two>
        <button @click="clickFun">change</button>
    </div>
    <script>
        Vue.component("child-one", {
            template: "<div>child-one</div>"
        })
        Vue.component("child-two", {
            template: "<div>child-two</div>"
        })
        var app = new Vue({
            el: "#app",
            data: {
                show: 'child-one'
            },
            methods: {
                clickFun: function () {
                    this.show = this.show === 'child-one' ? 'child-two' : 'child-one'
                }
            }
        })
    </script>
    

    上面是一种写法,当然除了这种写法,通过动态组件的形式来编写这段代码,可以将两个组件 child-one 和 child-two 去掉,然后写一个 component 这样的一个标签,这个标签是 Vue 中自带的一个标签,他指的就是有个动态组件,然后他有一个属性叫做 is,我让 is 绑定绑定一个数据,这个数据就是 show。

    <div id="app">
        <component :is="show"></component>
        <button @click="clickFun">change</button>
    </div>
    <script>
        Vue.component("child-one", {
            template: "<div>child-one</div>"
        })
        Vue.component("child-two", {
            template: "<div>child-two</div>"
        })
        var app = new Vue({
            el: "#app",
            data: {
                show: 'child-one'
            },
            methods: {
                clickFun: function () {
                    this.show = this.show === 'child-one' ? 'child-two' : 'child-one'
                }
            }
        })
    </script>
    

    打开页面,可以看到效果和上一段代码一样。动态组件的意思就是,他会根据 is 里面数据的变化自动的加载不同的组件,比如一开始进来,show 的值是 child-one,他就会显示 child-one 这个组件,当点击按钮了,child-one 变成了 child-two,这个时候,动态组件发现 is 里的数据变成了 child-two,那他就会自动的吧 child-one 销毁掉,去显示 child-two 这个组件,这就叫做 Vue 中的动态组件。

    接下来再讲一个知识点,v-once 指令。

    2、v-once 指令

    依然看上一段代码,我们每一次切换的时候,实际上 Vue 的底层会判断这个组件这个组件现在已经不用了,取而代之我要用另一个组件,然后他就会把第一个组件销毁,再创建第二个组件,假设第二个组件要隐藏,第一个组件又显示的话,这个时候再把第二个组价销毁掉再创建一个第一个组件,也就是每一次切换,底层都需要销毁一个组件,再创建一个组件,这种操作其实耗费了一定的性能的,那如果,我们的组件内容每次都一样,可以在子组件上面加一个 v-once 指令,这样的话,有一个好处,当 child-one 这个组件第一次被渲染的时候,因为这个组件上有一个 v-once 指令,所以他直接就放到内存里了,当点击切换,child-two 第一次展示到页面上,他也会被放到内存里,当再点击切换的时候,并不需要重新创建一个组件,而是从内存里直接拿出以前的组件就可以了,它的性能更高一些,所以在 Vue 之中,通过 v-once 指令可以有效的提高一些静态内容的展示效率。

    <div id="app">
        <child-one v-if="show === 'child-one'"></child-one>
        <child-two v-if="show === 'child-two'"></child-two>
        <button @click="clickFun">change</button>
    </div>
    <script>
        Vue.component("child-one", {
            template: "<div v-once>child-one</div>"
        })
        Vue.component("child-two", {
            template: "<div v-once>child-two</div>"
        })
        var app = new Vue({
            el: "#app",
            data: {
                show: 'child-one'
            },
            methods: {
                clickFun: function () {
                    this.show = this.show === 'child-one' ? 'child-two' : 'child-one'
                }
            }
        })
    </script>
    

    长得好看的都会关注我的 o(≧v≦)o~~

    相关文章

      网友评论

        本文标题:Vue.js第3课-深入理解Vue组件(part03)

        本文链接:https://www.haomeiwen.com/subject/gxnbaqtx.html