Vue.js组件理解

Posted 言叶以上のBLOG

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Vue.js组件理解相关的知识,希望对你有一定的参考价值。

组件使用细节点

解决元素标签位置错误的问题:is 属性

<div id="app">
    <table>
        <tbody>
            <!--tbody里要用一个组件,但不能直接写组件名
                会导致位置错误问题,使用 is 属性将自定义组件row
                与 tr 标签绑定在一起
            -->
            <tr is=‘row‘></tr>
            <tr is=‘row‘></tr>
            <tr is=‘row‘></tr>
        </tbody>
    </table>
    
        <ul>
            <li is=‘row‘></li>
            <li is=‘row‘></li>
            <li is=‘row‘></li>
        </ul>
</div>

<script>
    
    Vue.component(‘row‘, {
        template: ‘<tr><td>this is a row</td></tr>‘
    });
    
    var vm = new Vue({
        el: "#app"
    });
    
</script>

组件data函数

在子组件中,data 必须是一个函数,有可能一个子组件会被调用很多次,每个子组件数据不能产生冲突,通过一个函数返回一个对象的目的,就是让每个子组件都拥有独立的数据存储。

Vue.component(‘row‘, {
    //在子组件中,data 必须是一个函数
    data: function(){
        return {
            content: ‘this is a row‘
        }
    },
    template: ‘<tr><td>{{content}}</td></tr>‘
});

ref的使用

<div id="app">
    <counter ref="one" @change="handleChange"></counter>
    <counter ref="two" @change="handleChange"></counter>
    <div>{{total}}</div>
</div>

<script>
    
    Vue.component(‘counter‘,{
        template: ‘<div @click="handleClick">{{number}}</div>‘,
        data: function(){
            return {
                number: 0
            }
        },
        methods: {
            handleClick: function() {
                this.number ++;
                // $emit() 自定义事件向父组件通信
                this.$emit(‘change‘);
            }
        }
    });
    
    var vm = new Vue({
        el: "#app",
        data: {
            total: 0
        },
        methods: {
            handleChange: function() {
                //可以使用自加一方法
                //this.total++;
                //也可以求二者之和
                // 通过 $refs 获取子组件的引用,再获取数据
                this.total = this.$refs.one.number + this.$refs.two.number;
            }
        }
    });

父子组件的数据传递

父组件通过属性的形式向子组件传递数据

Vue 中的单项数据流:父组件可以向子组件传递参数,该参数在父组件可随便修改,子组件绝对不能反过来去修改父组件传递过来的参数,只用不改

<div id="app">
    <!--父往子传递-->
    <!--父组件通过绑定属性的形式向子组件传递数据-->
    <counter :count="3" @inc="handleIncrease"></counter>
    <counter :count="2" @inc="handleIncrease"></counter>
    
    <!--子往父传递-->
    <!--子组件通过事件触发的形式向父组件传递数据-->
    <div>{{total}}</div>
</div>

<script>
    var counter = {
        props: [‘count‘],
        data: function() {
            return {
                //定义一个number 把获取来的数据克隆一个传进去
                number: this.count
            }
        },
        template: ‘<div @click="handleClick">{{number}}</div>‘,
        methods: {
            handleClick: function() {
                this.number += 2;
                //子组件通过点击将事件触发出去
                this.$emit(‘inc‘, 2)
            }
        }
    }
    var vm = new Vue({
        el: "#app",
        components: {
            counter: counter
        },
        data: {
            total: 5
        },
        methods: {
            // 父组件执行的函数里可以直接接收到 $emit()的参数
            handleIncrease: function(step) {
                this.total += step;
            }
        }
    });

组件参数校验与非props特性

<div id="app">
    <child :content="123"></child>
</div>

<script>
    
    Vue.component(‘child‘,{
        props: {
            //设定子组件接收的content 属性,
            //  要么是数字,要么是字符串
            content: [String, Number]
            /*
            也可以这样写:
            content: {
                //类型
                type: String,
                
                //设定这个属性是必须的
                required: true,
                
                //如果不给default 传数值,默认default
                default: ‘default value‘,
                
                //对传入 content属性 添加校验
                //规定长度必须大于5
                validator: function(value) {
                    return (value.length > 5)
                }
            }
            */
        },
        template: ‘<div>{{content}}</div>‘
    })
    
    var vm = new Vue({
        el: "#app"
    });
    

props 特性:
父组件传递了content 子组件又声明了一个content接收; 二者有一个对应关系。该属性不会在DOM中出现,子组件可直接通过插值表达式调用content内的内容。

非props 特性
父组件传递一个属性,但是子组件并没有props的内容,没有声明,无法获取父组件内容。该属性会在子组件DOM中出现

给组件绑定原生事件

<div id="app">
    <!--
        加native修饰符,监听原生点击事件,
        方法同子组件设置自定义事件向父组件触发
    -->
    <child @click.native=‘handleClick‘></child>
</div>

<script>
    Vue.component(‘child‘,{
        template: ‘<div>child</div>‘
    })
    var vm = new Vue({
        el: "#app",
        methods: {
            handleClick: function() {
                alert(‘click‘)
            }
        }
    });
</script>

非父子组件间的传值

  1. 借助官方的数据框架 vuex解决
  2. 发布订阅模式 总线机制 Bus 观察者模式
<!--非父子组件传值
    Bus / 总线 / 发布订阅模式 / 观察者模式
-->
<div id="app">
    <!--点击一个,另一个变成相同的-->
    <child content=‘anqw‘></child>
    <child content=‘joe‘></child>
</div>

<script>
    //每一个Vue 实例都会有bus 属性
    Vue.prototype.bus = new Vue()
    
    Vue.component(‘child‘,{
        data: function() {
            return {
                //父组件传过来的数据只能用不能改,
                //所以需要拷贝一份
                selfContent: this.content
            }
        },
        props: {
            content: String
        },
        template: ‘<div @click="handleClick">{{selfContent}}</div>‘,
        methods: {
            handleClick: function() {
                //实例上挂载的bus ,这个bus 又是Vue 实例,
                //所以会有$emit()方法,同时把内容传进参数
                this.bus.$emit(‘change‘,this.selfContent);
            }
        },
        //借助生命周期钩子,被挂载时执行
        //$on 方法监听自定义事件
        mounted: function() {
            //固定this的指向
            var this_ = this;
            this.bus.$on(‘change‘, function(msg) {
                this_.selfContent = msg
            })
        }
    })
    var vm = new Vue({
        el: "#app"
    });

在Vue中使用插槽 slot

<div id="app">
    <child>
        <!--插槽-->
        <!--如果不传标签会显示默认内容-->
        <h1>Anqw</h1>
    </child>
</div>

<script>
    Vue.component(‘child‘,{
        //slot插槽中显示的是父组件插入的标签
        template: ‘<div><p>hello</p><slot>默认内容</slot></div>‘
    })
    var vm = new Vue({
        el: "#app"
    });
    
</script>

将多个插槽一一对应

<div id="app">
    <body-content>
        <div class="header" slot=‘header‘>header</div>
        <div class="footer" slot=‘footer‘>footer</div>
    </body-content>
</div>

<script>
    Vue.component(‘body-content‘,{
        //将插槽一一对应,用slot 与 name 属性绑定
        template: `<div>
                        <slot name=‘header‘></slot>
                        <div class="content">
                            content
                        </div>
                        <slot name=‘footer‘></slot>
                    </div>`
    });
    var vm = new Vue({
        el: "#app"
    });
    
</script>
<!--
    显示结果:
    header
    content
    footer
-->

Vue 中的作用域插槽

<div id="app">
    <child>
        <!--首先父组件内传了一个插槽,
            作用域插槽,必须用 template 标签包裹,
            同时声明从子组件接收的数据都放在props中,
            slot-scope 对应的属性名接收到数据后,
            以li的形式进行展示.
        -->
        <template slot-scope="props">
            <!--由父组件传递循环对应的模板-->
            <li>{{props.item}} - hello</li>
        </template>
    </child>
</div>

<script>
    Vue.component(‘child‘,{
        data: function() {
            return {
                list: [1,2,3,4]
            }
        },
        //当子组件做循环,DOM结构需要由外部传递时
        template: `<div>
                        <ul>
                            <slot 
                                v-for="item of list" 
                                :item="item">
                            </slot>
                        </ul>
                    </div>`
    });
    var vm = new Vue({
        el: "#app"
    });
    
</script>

动态组件与v-once指令

<div id="app">
    <!--动态组件-->
    <!--会根据 is 中数据的变化去加载不同的组件-->
    <!--<component :is="type"></component>-->
    
    <child-one v-if="type === ‘child-one‘"></child-one>
    <child-two v-if="type === ‘child-two‘"></child-two>
    
    <button @click="handleClick">change</button>
    
    <!--当点击button时 两个组件 toggle显示-->
</div>

<script>
    Vue.component(‘child-one‘,{
        // v-once 可以把组件暂时放到内存里,
        //  点击之后直接从内存里取出就行,提高了性能
        template: ‘<div v-once>child-one</div>‘
    });
    Vue.component(‘child-two‘,{
        template: ‘<div v-once>child-two</div>‘
    });
    var vm = new Vue({
        el: "#app",
        data: {
            type: ‘child-one‘
        },
        methods: {
            handleClick: function() {
                this.type = (this.type === ‘child-one‘?
                    ‘child-two‘: ‘child-one‘);
            }
        }
    });
</script>


以上是关于Vue.js组件理解的主要内容,如果未能解决你的问题,请参考以下文章

Vue组件之全局组件与局部组件

Vue组件之全局组件与局部组件

如何理解vue.js组件的作用域是独立的

Vue.js 组件编码规范

Vue.js 组件编码规范

Vue.js 组件 component