美文网首页Vue
第4章 深入理解Vue组件

第4章 深入理解Vue组件

作者: 读书的鱼 | 来源:发表于2019-05-21 11:49 被阅读71次
    4-1 使用组件细节点

    1.is的使用
    当我们写循环组件的时候,经常给
    table中的tr
    select中的option
    ul中的li或者ol中的li
    等等定义组件的时候,我们经常用is来定义组件的名称,为了让浏览器成功的渲染正确的dom结构

    <div id="root">
        <table>
            <tbody>
            <tr is="row"></tr>
            <tr is="row"></tr>
            <tr is="row"></tr>
            </tbody>
        </table>
        <select name="" id="">
            <option is="selectOption"></option>
            <option is="selectOption"></option>
            <option is="selectOption"></option>
        </select>
        <ul>
            <li is="ulLi"></li>
            <li is="ulLi"></li>
            <li is="ulLi"></li>
        </ul>
    </div>
    <script>
        Vue.component('row', {
            template: '<tr><td>this is a row</td></tr>'
        });
        Vue.component('selectOption',{
            template: '<option>this is option</option>'
        });
        Vue.component('ulLi',{
            template: '<li>this is li</li>'
        });
        var app = new Vue({
            el: '#root',
            data: {},
        })
    </script>
    

    2.在子组件定义data的时候,必须是一个函数,而不能是一个对象,返回一个对象是为了每个子组件都能拥有一个独立的数据存储。这样子组件之间的数据不会互相影响
    而在根组件中,data可以是一个对象。

    <div id="root">
        <table>
            <tbody>
            <tr is="row"></tr>
            <tr is="row"></tr>
            <tr is="row"></tr>
            </tbody>
        </table>
    </div>
    <script>
        Vue.component('row', {
            data: function () {//返回的是一个函数
                return {
                    content: 'this is row'
                }
            },
            template: '<tr><td>{{content}}</td></tr>'
        });
        var app = new Vue({
            el: '#root',
            data: {}
        })
    </script>
    

    3.有时候我们在开发过程中,因为一些业务的需求,少不了对dom的操作,那么我们就可以借助ref来实现

    //实例一
    <div id="root">
        <div ref="hello" @click="handleClick">hello world</div>
    </div>
    <script>
        var app = new Vue({
            el: '#root',
            data: {},
            methods: {
                handleClick: function () {
                    console.log(this.$refs.hello.innerHTML);//通过refs属性 获取当前节点的文本
                }
            }
        });
    </script>
    
    
    //案例二 counter求和
    <div id="root">
        <counter ref="one" @change="handleChange"></counter>
        <counter ref="two" @change="handleChange"></counter>
        <div>{{total}}</div>
    </div>
    <script>
        Vue.component('counter', {
            data: function () {
                return {
                    number: 0
                }
            },
            template: '<div @click="handleClick">{{number}}</div>',
            methods: {
                handleClick: function () {
                    this.number++;
                    this.$emit('change');//触发一个监听器
                }
            }
        });
        var app = new Vue({
            el: '#root',
            data: {
                total: 0
            },
            methods: {
                handleChange: function () {
                    this.total = this.$refs.one.number + this.$refs.two.number //通过refs 来回去组件的值
                }
            }
        });
    </script>
    
    4-2父子组件之间的数据传递

    父组件向子组件传值:是通过属性的方式
    子组件向父组件传值:可以通过$emit来触发一个事件

    vue数据传递遵循的是单向数据流,
    所以在下面的案例中我们并没有对content数据直接进行数据的累加,而是把content数据赋值给了number,对number进行数据的累加操作。

    <div id="root">
        <counter :content="1" @inc="handleInc"></counter><!--父组件通过属性向子组件传值-->
        <counter :content="3" @inc="handleInc"></counter>
        <div>{{total}}</div>
    </div>
    <script>
        Vue.component('counter', {
            props: ['content'],
            data: function () {
                return {
                    number: this.content //遵循单向数据流
                }
            },
            template: '<div @click="handleClick">{{number}}</div>',
            methods: {
                handleClick: function () {
                    this.number += 2;
                    //子组件通过方法向父组件传值
                    this.$emit('inc', 2);
                }
            }
        });
        var app = new Vue({
            el: '#root',
            data: {
                total: 4
            },
            methods: {
                handleInc: function (step) {
                    this.total += step
                }
            }
        })
    </script>
    
    4-3组件参数校验和非props特性

    1.组件的的参数校验

    <div id="root">
        <child content="hello"></child>
    </div>
    <script>
        Vue.component('child', {
            props: {
                content: {
                    type: String,
                    required: true,
                    default: 'default Value',
                    validator: function (value) {
                        return (value.length > 5)
                    }
                }
            },
            template: '<div>{{content}}</div>'
        });
        var app = new Vue({
            el: '#root',
        })
    </script>
    

    2.props特性和非props特性的对比
    props特性:
    父组件传递属性,子组件要接受该属性
    props属性不会显示在dom的标签之中
    非props特性:
    父组件传递属性,子组件没有去接受,而是直接调用
    props属性会显示在dom的标签之中

    4-4给组件绑定原生事件

    通过.native属性来绑定原生事件

    <div id="root">
        <child @click.native="handleClick"></child>
    </div>
    <script>
        Vue.component('child', {
            template: '<div>child</div>'
        })
        var app = new Vue({
            el: '#root',
            methods: {
                handleClick: function () {
                    console.log('click');
                }
            }
        })
    </script>
    
    4-5 非父子组件间的传值
    非父子组件间的传值

    1.通过vuex
    2.通过发布订阅模式(Bus/总线/发布订阅模式/观察者模式/)

    <div id="root">
        <child content="sunny"></child>
        <child content="fan"></child>
    </div>
    <script>
        Vue.prototype.bus = new Vue();//定义bus
        Vue.component('child', {
            data: function () {
                return {
                    newContent: this.content //保证单向数据流
                }
            },
            props: {
                content: String
            },
            template: '<div @click="handleClick">{{newContent}}</div>',
            methods: {
                handleClick: function () {
                    this.bus.$emit('change', this.newContent); //在bus上发布一个事件,并且传值
                }
            },
            mounted: function () {//通过这个钩子,来监听change的变化,通过回调拿到相对应的的值
                var that = this;
                this.bus.$on('change', function (msg) {
                    console.log(msg)
                    that.newContent = msg//this 指向发生变更,所以上面要从新获取一下this的指向
                })
            }
        });
        var app = new Vue({
            el: '#root'
        })
    
    
    4-6 在vue中使用插槽

    插槽只能有一个
    而剧名插槽可以有多个

      <div id="root">
        <body-content>
          <p slot="header">this is header</p>
          <p slot="footer">this is footer</p>
        </body-content>
      </div>
      <script>
        Vue.component('body-content',{
          template:
          `<div>
            <slot name="header">default header</slot> //设置默认值
            <p>this is content</p>
            <slot name="footer"></slot>
          </div>`
        })
        var app = new Vue({
          el:'#root'
        })
      </script>
    
    4-7作用域插槽

    父组件调用子组件的时候,给子组件传了一个插槽,这个插槽是一个作用域的插槽,这个插槽必须是一个<template slot-scope="props">{{props.item}}</template>
    那什么时候使用作用插槽呢?
    1.当子组件做循环
    2.或者当子组件的dom结构由外部传递进来,或者有外部决定的时候

    <div id="root">
        <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></slot>
            </ul>
          </div>`
        })
        var app = new Vue({
          el: '#root'
        })
      </script>
    
    
    4-8 动态组件和v-once 指令
    <div id="root">
        <component :is="type"></component> <!--这就是动态组件-->
        <child-one v-if="type==='child-one'"></child-one>
        <child-two v-if="type==='child-two'"></child-two>
        <button @click="hanleBtnClick">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: '#root',
          data: {
            type: 'child-one'
          },
          methods: {
            hanleBtnClick: function () {
              this.type = this.type === 'child-one' ? 'child-two' : 'child-one'
            }
          }
        })
      </script>
    

    更多

    上一篇:第3章 Vue 基础精讲
    下一篇:第5章 Vue 表单
    全篇文章:Vue学习总结
    所有章节目录:Vue学习目录

    相关文章

      网友评论

        本文标题:第4章 深入理解Vue组件

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