vue组件详解

作者: JianQiang_Ye | 来源:发表于2019-03-28 21:42 被阅读0次

    使用组件的原因

    提高代码的复用性

    组件的使用方法

    1. 全局注册
    Vue.component('my-component',{
            template:'<div>我是组件的内容</div>'
        })
    

    占内存

    1. 局部注册
    var app = new Vue({
            el: '#app',
            data: {
    
            },
            components: {
                'app-component': {
                    template: '<div>app-component</div>'
        }
            }
        })
    
    1. 由于HTML标签的限制,如table中只能有trtdtbody,要想在table中使用组件就要用到is,这样一来,tbody在文档中就会被组件替换掉
    <table>
            <tbody is="app-component"></tbody>
    </table>
    

    我们也可以利用这个属性来干掉其他事,比如动态组件,也就是点一个按钮就切换一个组件

    组件使用的奇淫巧技

    1. 必须用连字符命名,如:my-compoent
    2. template中的内容必须要用DOM元素包裹
    // 正确写法
    template: '<div>app-component</div>'
    
    // 错误写法
    template: 'app-component'
    
    1. 组件的定义中,还可以有data,methods,computed
    2. data必须是一个方法
    components: {
                'plus-component': {
                    template: '<button @click="count111++">{{count111}}</button>',
                    data: function () {
                        return {
                            count111: 1
                        }
                    }
                }
            }
    

    使用props传递数据 父亲向儿子传递数据

    1. 在子组件上声明属性msg,然后在子组件处用props来接收
    <div id="app">
        我是爸爸
        <child-component :msg="fatherMsg"></child-component>
    </div>
    <script>
        var app = new Vue({
            el: '#app',
            components: {
                'child-component': {
                    // 从父组件和本身data传入的数据在methods、template中都可以使用
                    props: ['msg'],
                    data: function(){
                        return {
                            count:1
                        }
                    },
                    template: '<div id="child">{{msg}}</div>',
                }
            }
        })
    </script>
    
    1. 动态向子组件传入信息,则用v-model
    <div id="app">
        我是爸爸
        <input type="text" v-model="fatherMsg">
        <child-component :msg="fatherMsg"></child-component>
    </div>
    <script src="../vue.js"></script>
    <script>
        var app = new Vue({
            el: '#app',
            data: {
                count: 1,
                fatherMsg: 'hello'
            },
            methods: {
                plus: function () {
                    this.count++
                }
            },
            components: {
                'child-component': {
                    // 从父组件和本身data传入的数据在methods、template中都可以使用
                    props: ['msg'],
                    data: function(){
                        return {
                            count:1
                        }
                    },
                    template: '<div id="child">{{msg}}</div>',
                }
            }
        })
    </script>
    
    1. ==在props中定义的属性都可以在组件内使用,可以在template、computed、methods中使用==

    单向数据流

    只能父组件向子组件传递信息,子组件不能向父组件传递信息

    在组件中使用从props传来的数据可以直接用this.xxx来获取

     'child-component': {
                    props: ['msg'],
                    template: '<div id="child" >{{count}}</div>',
                    data:function(){
                        // 组件中的data要返回一个函数
                        return {
                            count: this.msg
                        }
                    }
                }
    
    1. 用v-bind来绑定style属性的时候可以使用对象语法,注意
    <div :style="xxx" id="div1"></div>
    computed:{
                xxx: function () {
                    return {
                        //这是用到了v-bind绑定style的对象语法
                        width: this.ccc + 'px',
                        'background-color': 'red',
                        height: 10 + 'px'
                    }
                }
            }
    

    数据验证

    在HTML中绝对不允许使用驼峰,因为HTML会把大写全部转化为小写。在props中可以用驼峰或短横线,在template和data、this.xxx中只能使用驼峰,这是因为在vue中短横线会被误认为减号,会报错。
    ==总结:在HTML中使用短横线,在vue中使用驼峰==

    1. 对传入的数据进行数据验证

    注意props不能再返回一个数组,而是一个对象

    <div id="app">
        <child-component :a="a" :b="b" :c="c" :d="d" :e="e" :f="f"></child-component>
    </div>
    <script src="../vue.js"></script>
    <script>
        var app = new Vue({
            el: '#app',
            data: {
                a: 'hello',
                b: 123,
                c: true,
                d: 123,
                e:[456],
                f: 15
            },
            components: {
                'child-component': {
                    props: {
                        a: String,     // 验证字符串,如果不是字符串页面会照常渲染但会报错
                        b: [String,Number], // 意思是传入的数据是String或是Number类型
                        c: {
                            type: Boolean,
                            default: false   // 默认值为false
                        },
                        d: {
                            type: Number,
                            required: true   // 表示d是必须要传入的值
                        },
                        e:{
                            // 如果是数组或对象,默认值要用函数来返回
                            type: Array,
                            default: function () {
                                return [789]
                            }
                        },
                        f:{
                            // 自定义一个验证函数
                            validator: function(value){
                                return value>10
                            }
                        }
                     },
                    template: '<div id="child" >{{a}}--{{b}}--{{c}}--{{d}}--{{e}}--{{f}}</div>',
                    data:function(){
                        // 组件中的data要返回一个函数
                        return {
                            count: this.msg
                        }
                    }
                }
            }
        })
    </script>
    

    组件之间的通信

    子组件给父组件传递信息

    实现一个功能,点击子组件的按钮,改变父组件的数据

    <div id="app">
        我的账户余额为:{{count}}
        <child-component @xxx="changeCount"></child-component>
    </div>
    <script src="../vue.js"></script>
    <script>
        var app = new Vue({
            el: '#app',
            data: {
                count: 2000
            },
            methods: {
                changeCount: function (value) {
                    this.count = value
                }
            },
            components: {
                'child-component': {
                    // 注意这里template一定要有DOM元素包裹
                    template: `<div>
                    <button @click="handleIncrease">+1000</button>
                    <button @click="handleReduce">-1000</button>
                    </div>
                    `,
                    data:function(){
                        return {
                            count: 2000
                        }
                    },
                    methods: {
                        handleIncrease: function () {
                            this.count += 1000    // 这里的this.count是组件里面的count
                            this.$emit('xxx',this.count)   // emit表示向父组件通信,第一个参数是自定义事件的名称,后面是要传入的值,可以写无限个
                        },
                        handleReduce: function () {
                            this.count -= 1000
                            this.$emit('xxx',this.count)
                        }
                    }
                }
            }
        })
    </script>
    

    子组件向父组件传递信息的步骤:

    1. 在父组件里写入自定义事件名,事件名后面跟着的是要执行的方法
    2. 子组件通过$emit向父组件传递信息,第一个参数是自定义的事件名,后面是要传递的参数,可以接无限个

    在组件中使用v-model

    v-model其实也是一个语法糖:

    1. 它等于先用v-bind绑定一个值
    2. 监听v-on了一个input事件
      上述代码又可以简化成
    <div id="app">
        我的账户余额为:{{total}}
        <child-component v-model="total"></child-component>
    </div>
    <script src="../vue.js"></script>
    <script>
        var app = new Vue({
            el: '#app',
            data: {
                total: 2000
            },
            components: {
                'child-component': {
                    template: `<div>
                    <button @click="handleIncrease">+1000</button>
                    <button @click="handleReduce">-1000</button>
                    </div>
                    `,
                    data:function(){
                        return {
                            count: 2000
                        }
                    },
                    methods: {
                        handleIncrease: function () {
                            this.count += 1000    // 这里的this.count是组件里面的count
                            this.$emit('input',this.count)   // emit表示向父组件通信,第一个参数是自定义事件的名称,后面是要传入的值,可以写无限个
                        },
                        handleReduce: function () {
                            this.count -= 1000
                            this.$emit('input',this.count)
                        }
                    }
                }
            }
        })
    </script>
    

    非父组件之间的通信

    非父组件之间的通信需要一个bus作为中介
    在父组件的data内新建一个bus: new Vue()对象。
    然后在A组件内用this.$parent.bus.$emit('事件名',参数)

    Vue.component('a-component',{
            template: `
                    <div>
                        <input type="text" v-model="text">
                    </div>`,
            data:function () {
                return {
                    text: '我是A组件'
                }
            },
            watch:{
                //watch的用法,key代表要监听的数据,后面接操作
                text: function () {
                    this.$root.bus.$emit('xxx',this.text)
                }
            }
        })
    

    在B组件内,在对应的钩子事件中用this.$parent.bus.$on('事件名',参数)

     Vue.component('b-component',{
            template: '<div>我是b组件---{{textb}}</div>',
            data:function () {
                return {
                    textb: 'bbbbb'
                }
            },
            created: function () {
                var _this = this
                this.$root.bus.$on('xxx',function (value) {
                    // alert('created')
                    _this.textb = value
                })
            }
        })
    
    1. 修改父组件的数据,父链
    this.$parent.xxxx
    
    1. 修改儿子组件的数据,子链
      在每个儿子组件上加上ref属性
        <a-component ref="a"></a-component>
        <b-component ref="b"></b-component>
        <c-component ref="c"></c-component>
    

    然后在父组件上使用:

    this.$refs.a.count = 'aaa' // 修改a组件的数据
    

    使用slot分发内容

    编译的作用域

    <div id="app">
    
        <child-component v-show="bool">
                {{message}}
        </child-component>
    </div>
    

    message属于父组件的作用域
    父组件模板内的内容在父组件内编译
    子组件模板内的内容在子组件内编译

    slot(插槽)的用法和作用

    在下面这段代码中

        <child-component v-show="bool">
                {{message}}
        </child-component>
    

    message其实是渲染不出来的,尽管message的作用域在父组件,但我们想让它子组件内的template中渲染出来,这时我们就要使用到了slot功能。

    slot的作用是混合父组件的内容和子组件的模板,从而弥补视图的不足

    <div id="app">
        <child-component >
                <p>hello world</p>
        </child-component>
    </div>
    ......
    Vue.component('child-component',{
            template: `
             <div style="border: 1px solid red;">
                    <slot>
                            如果父组件没有内容,我就是子组件的默认内容
                    </slot>
             </div>
    

    具名插槽

    在要插入数据的标签使用slot属性,在子组件的template处使用slot标签,并且写上对应的name

    <child-component >
                <h1 slot="header">我是标题</h1>
                <p>hello world</p>
    </child-component>
    ... ...
     Vue.component('child-component',{
            template: `
             <div style="border: 1px solid red;">
                 <div style="color: red;">
                 <slot name="header">
                        这里是header的默认内容
                    </slot>
                    </div>
    
                    <slot>
                            如果父组件没有内容,我就是子组件的默认内容
                    </slot>
             </div>
            `,
    

    作用域插槽

    作用域插槽是一个特殊的插槽,可以从子组件的插槽中获取数据。使用一个可以复用的模板来替换已经渲染的元素
    用法:先在子组件的slot标签上name属性和自定义的属性

    Vue.component('child-component',{
            template: `
             <div style="border: 1px solid red;">
                 <div style="color: red;">
                    <slot name="header" text="我是子组件的数据">
                        这里是header的默认内容
                    </slot>
                  </div>
             </div>
            `,
    

    然后在父组件上,用slot对应其中的name,用slot-scope对应的自定义名字来获取从子组件传来的数据

    <child-component >
            <template slot="header" slot-scope="props">
                {{props.text}}
            </template>
        </child-component>
    

    现在已经可以不用template,可以直接使用标签如<p>

    在子组件中访问自己的slot

    通过this.$slots.(NAME)来访问

    <div id="app">
        <child-component >
            <h1 slot="header">我是父组件的内容</h1>
        </child-component>
    </div>
    
    Vue.component('child-component',{
            template: `
             <div style="border: 1px solid red;">
                 <div style="color: red;">
                 <slot name="header">
                        这里是header的默认内容
                   </slot>
                   </div>
             </div>
            `,
            data:function () {
                return {
                    message: '我是子组件的内容',
                    bool: true
                }
            },
            mounted:function () {
                var header = this.$slots.header
                console.log(header)
                console.log(header[0].elm.innerText)
            }
        })
    

    组件的高级用法-动态组件

    所谓的动态组件就是通过is属性来动态切换组件

    <div id="app">
        <component-a :is="thisView"></component-a>
        <button @click="changeToA">第一句</button>
        <button @click="changeToB">第二句</button>
        <button @click="changeToC">第三句</button>
        <button @click="changeToD">第四句</button>
    </div>
    <script src="../vue.js"></script>
    <script>
        Vue.component('componentA',{
           template: `<div>离离原上草</div>`
        })
        Vue.component('componentB',{
           template: `<div>一岁一枯荣</div>`
        })
        Vue.component('componentC',{
           template: `<div>野火烧不尽</div>`
        })
        Vue.component('componentD',{
           template: `<div>春风吹又生</div>`
        })
        var app = new Vue({
            el: '#app',
            data: {
                thisView: 'componentA'
            },
            methods :{
                changeToA: function () {
                    this.thisView = 'componentA'
                },
                changeToB: function () {
                    this.thisView = 'componentB'
                },
                changeToC: function () {
                    this.thisView = 'componentC'
                },
                changeToD: function () {
                    this.thisView = 'componentD'
                }
            }
        })
    

    相关文章

      网友评论

        本文标题:vue组件详解

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