vue学习十二( v-model用于自定义组件、父子组件通信、组件绑定原生事件、具名插槽、插槽作用域、动态组件is和keep-alive)

自定义组件的 v-model

一个组件上的 v-model 默认会利用名为 value 的 prop 和名为 input 的事件,但是像单选框、复选框等类型的输入控件可能会将 value 特性用于不同的目的。model 选项可以用来避免这样的冲突

 <div id="lll">
        <base-checkbox v-model="lovingVue"></base-checkbox>
        <span>{{lovingVue}}</span>

    </div>

    <script>
        Vue.component('base-checkbox', {
            model: {
                prop: 'checked',
                event: 'change'
            },
            props: {
                checked: Boolean
            },
            template: `
    <input
      type="checkbox"
      v-bind:checked="checked"
      v-on:change="$emit('change', $event.target.checked)"
    >
  `
        })

        new Vue({
            el: "#lll",
            data: { lovingVue: true }
        })
    </script>

效果图:
vue学习十二( v-model用于自定义组件、父子组件通信、组件绑定原生事件、具名插槽、插槽作用域、动态组件is和keep-alive)
vue学习十二( v-model用于自定义组件、父子组件通信、组件绑定原生事件、具名插槽、插槽作用域、动态组件is和keep-alive)

子组件跟父组件通信

 <!-- 但子组件怎么跟父组件通信呢?这个时候 Vue 的自定义事件系统就派得上用场了。 -->

    <!--   使用 $on(eventName) 监听事件
          使用 $emit(eventName, optionalPayload) 触发事件 -->
    <!-- 父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。 -->
    <!-- 必须在模板里直接用 v-on绑定事件 -->
 <div id="div1">
        <p>{{total}}</p>
        <custom v-on:chufa="changeParent"></custom>
        <custom v-on:chufa="changeParent"></custom>
    </div>
    <script type="text/javascript">
        Vue.component("custom", {
            template: '<button v-on:click="m_click">{{data}}</button>',
            data: function () {
                return { data: 0 }
            },
            methods: {
                m_click: function () {
                    this.data += 1
                    this.$emit("chufa")
                }
            }
        })
        new Vue({
            el: "#div1",
            data: {
                total: 0
            },
            methods: {
                changeParent: function () {
                    this.total += 1
                }
            }
        })
    </script>

效果如下:
vue学习十二( v-model用于自定义组件、父子组件通信、组件绑定原生事件、具名插槽、插槽作用域、动态组件is和keep-alive)

将原生事件绑定到组件

你可能有很多次想要在一个组件的根元素上直接监听一个原生事件。这时,你可以使用 v-on 的 .native 修饰符:

   <div id="app">
        <my-comp @click.native="doThis"></my-comp>
        <div @click="doThis">我是元素</div>
    </div>
    <script>
        Vue.component('my-comp', {
            template: '<div>我是组件</div>'
        });
        new Vue({
            el: '#app',
            methods: {
                doThis: function () {
                    console.log('click');
                }
            }
        });
    </script>

单个插槽

<!-- 1、单个插槽 -->
    <div id="exp1">
        <my-com></my-com>
    </div>

    <script type="text/javascript">

        //子组件,备用内容在子组件的作用域内编译,并且只有在宿主元素为空时,且没有要插入的内容时才显示备用内容
        Vue.component('child-com', {
            template: '<div><h2>我是子组件的标题</h2>' +
                '<slot>只有在没有要分发的内容时才会显示</slot>' +
                '</div>'
        });
        //父组件
        Vue.component('my-com', {
            template: '<div><h1>我是父组件的标题</h1>' +
                '<child-com>' +
                '<p>这是一些初始内容</p>' +
                '<p>这是另外一些初始内容</p>' +
                '</child-com>' +
                '</div>'
        });
        var exp1 = new Vue({
            el: '#exp1'
        })
    </script>

输出如下:

我是父组件的标题
我是子组件的标题
这是一些初始内容

这是另外一些初始内容

插槽内容

到现在,我们知道了什么是插槽:

插槽就是Vue实现的一套内容分发的API,将元素作为承载分发内容的出口


    <div id="app">
        <child-component>哈哈{{a}}</child-component>

    </div>
    <script>
        Vue.component('child-component', {
            template: `
                        <div>Hello,World!
                                <slot></slot>
                        </div>
                    `
        })
        let vm = new Vue({
            el: '#app',
            data: {
                a: "haha",
            }
        })
    </script>

我们现在给组件增加一个插槽
我们在内写的"你好"起作用了!!!

效果如下:

Hello,World! 哈哈haha

具名插槽


        <div id="app">
                <child-component>
                    <template slot="girl">
                        漂亮、美丽、购物、逛街
                    </template>
                    <template slot="boy">
                        帅气、才实
                    </template>
                    <div>
                        我是一类人,
                        我是默认的插槽
                    </div>
                </child-component>
            </div>
            <script>
                Vue.component('child-component',{
                    template:`
                        <div>
                        <h4>这个世界不仅有男人和女人</h4>
            
                        <slot name="girl"></slot>
            
                        <div style="height:1px;background-color:red;"></div>
            
                        <slot name="boy"></slot>
            
                        <div style="height:1px;background-color:red;"></div>
            
                        <slot></slot>
                        </div>
                    `
                })
                let vm = new Vue({
                    el:'#app',
                    data:{
            
                    }
                })
            </script>

效果如下:
vue学习十二( v-model用于自定义组件、父子组件通信、组件绑定原生事件、具名插槽、插槽作用域、动态组件is和keep-alive)

作用域插槽

先看一个最简单的例子!!

我们给元素上定义一个属性say(随便定义的!),接下来在使用组件child,然后在template元素上添加属性slot-scope!!随便起个名字a

我们把a打印一下发现是 {“say” : “你好”},也就是slot上面的属性和值组成的键值对!!!

这就是作用域插槽

我可以把组件上的属性/值,在组件元素上使用!

  <div id="app">
        <child>
            <template slot-scope="ab">
                {{ab}}
            </template>
        </child>
    </div>
    <script>
        Vue.component('child', {
            template: `
                        <div>
                            <slot say="你好"></slot>
                        </div>
                    `
        })

        let vm = new Vue({
            el: '#app',
            data: {

            }
        })
    </script>

效果如下:

{ "say": "你好" }

is 特性实现动态组件

我们在一个多标签的界面中使用 is 特性来切换不同的组件
当在这些组件之间切换的时候,你有时会想保持这些组件的状态,以避免反复重渲染导致的性能问题。


    <div id="example">
        <button @click="change">切换页面</button>
        <component :is="currentView"></component>
    </div>

    <script>
        var home = { template: '<div>我是主页</div>' };
        var post = { template: '<div>我是提交页</div>' };
        var archive = { template: '<div>我是存档页</div>' };
        new Vue({
            el: '#example',
            components: {
                home,
                post,
                archive,
            },
            data: {
                index: 0,
                arr: ['home', 'post', 'archive'],
            },
            computed: {
                currentView() {
                    return this.arr[this.index];
                }
            },
            methods: {
                change() {
                    this.index = (++this.index) % 3;
                }
            }
        })
    </script>

动态组件使用 keep-alive

我们之前曾经在一个多标签的界面中使用 is 特性来切换不同的组件:

<component v-bind:is="currentTabComponent"></component>

当在这些组件之间切换的时候,你有时会想保持这些组件的状态,以避免反复重渲染导致的性能问题。例如我们来展开说一说这个多标签界面:
vue学习十二( v-model用于自定义组件、父子组件通信、组件绑定原生事件、具名插槽、插槽作用域、动态组件is和keep-alive)

你会注意到,如果你选择了一篇文章,切换到 Archive 标签,然后再切换回 Posts,是不会继续展示你之前选择的文章的。这是因为你每次切换新标签的时候,Vue 都创建了一个新的 currentTabComponent 实例。

重新创建动态组件的行为通常是非常有用的,但是在这个案例中,我们更希望那些标签的组件实例能够被在它们第一次被创建的时候缓存下来。为了解决这个问题,我们可以用一个 元素将其动态组件包裹起来。

我们来看一个例子

<div id="example3">
        <button @click="change">切换页面</button>
        <keep-alive>
            <component :is="currentView"></component>
        </keep-alive>
    </div>

    <script>
        new Vue({
            el: '#example3',
            data: {
                index: 0,
                arr: [
                    { template: `<div>我是主页</div>` },
                    { template: `<div>我是提交页</div>` },
                    { template: `<div>我是存档页</div>` }
                ],
            },
            computed: {
                currentView() {
                    return this.arr[this.index];
                }
            },
            methods: {
                change() {
                    let len = this.arr.length;
                    this.index = (++this.index) % len;
                }
            }
        })
    </script>