5

文章内容由蚊子的前端博客进行发布,或许你想看看他其他的文章呢: http://www.xiabingbao.com

原文地址: https://www.xiabingbao.com/vue/2017/09/14/vue-component-tips.html

官网上已经有的内容,我就不再赘述了,直接在官网上查看即可,这里蚊子想换个角度来讲解下vue的组件。

组件,顾名思义,就是把一个相对独立,而且会多次使用的功能抽象出来,成为一个组件!如果我们要把某个功能抽象为一个组件时,要做到这个组件对其他人来说是个黑盒子,他们不用关心里面是怎么实现的,只需要根据约定的接口调用即可!

我用一张图稍微总结了下Vue中组件的构成:

Vue组件实现tips的总结

可以看到组件中包含的东西还是蛮多的,而且,还有很多的点没有列出来,这里面的每一个知识点能都展开讲很多。不过我们这里不讲原理,只讲使用。

我们以一个tips弹窗为例,来综合运用下组件的知识点。tips弹窗,几乎所有的框架或者类库,都会有弹窗这个组件,因为弹窗这个功能平时非常普遍,而且模块解耦度高!

我们先来看下demo: 【 https://www.xiabingbao.com/demo/vue-component/vue-tips.html 】。

1. 接口约定

我们这里实现的弹窗,能用到的知识点有:props, event, slot, ref等。这里我们也能看到各个知识点是怎么运用的。

/**
 * modal 模态接口参数
 * @param {string} modal.title 模态框标题
 * @param {string} modal.text 模态框内容
 * @param {boolean} modal.showbtn 是否显示按钮
 * @param {string} modal.btnText 按钮文字
 */

 Vue.component('tips', {
    props : ['tipsOptions'],
    template : '#tips',

    data(){
        return{
            show : false
        }
    },

    computed:{
        tips : {
            get() {
                let tips = this.tipsOptions || {};
                tips = {
                    title: tips.title || '提示',
                    text: tips.text || '',
                    showbtn : tips.showbtn || true,
                    btnText : tips.btnText || '确定'
                };
                // console.log(tips);
                return tips;
            }
        }
    }
})

2. modal组件的实现

tips组件相对来说实现的比较简单,仅用作提示用户的简单弹层。

模板:

<div class="tips" v-show="show" transition="fade">
    <div class="tips-close" @click="closeTips">x</div>
    <div class="tips-header">
        <slot name="header">
            <p class="title">{{tips.title}}</p>
        </slot>
    </div>
    <div class="tips-body">
        <slot name="body">
            <p class="notice">{{tips.text}}</p>
        </slot>
    </div>
    <div class="tips-footer">
        <a href="javascript:;" v-if="tips.showbtn" @click="yes" >{{tips.btnText}}</a>
    </div>
</div>

模板中将结构分成了三部分,标题、内容和操作区域。这里既可以使用props传递字符串,也可以使用slot进行定制。

tips样式:

.tips {
    position: fixed;
    left: 10px;
    bottom: 10px;
    z-index: 1001;
    -webkit-overflow-scrolling: touch;
    max-width: 690px;
    width: 260px;
    padding: 10px;
    background: #fff;
    box-shadow: 0 0 10px #888;
    border-radius: 4px;
}
.tips-close{
    position: absolute;
    top: 0;
    right: 0;
    width: 20px;
    height: 20px;
    line-height: 20px;
    text-align: center;
}
.tips-header{
    text-align: center;
    font-size: 25px;
}

组件内的方法:

methods:{
    closeTips(){
        this.show = false;
    },

    yes : function(){
        this.show = false;
        this.$emit('yes', {name:'wenzi', age:36}); // 触发yes事件
    },

    showTips(){
        var self = this;
        self.show = true;

        setTimeout(function(){
            // self.show = false;
        }, 2000)
    }
}

3. 调用tips组件

首先我们开始渲染组件:

<div class="app">
    <a href="javascript:;" @click="showtips">显示</a>
    <tips :tips-options="tipsOptions" ref="dialog" @yes="yes" v-cloak >
        <h3 slot="header">提示标题</h3>
        <div slot="body">
            <p>hello world</p>
            <p>wenzi</p>
        </div>
    </tips>
</div>

点击显示按钮后展示tips:

var app = new Vue({
    el : '.app',

    data : {
        tipsOptions : {
            title : 'tip'
        }
    }

    methods:{
        // 监听从组件内传递出来的事件
        yes(args){
            // console.log( args );
            alert( JSON.stringify(args) );
        },

        // 显示tips
        showtips(){
            // console.log( this.$refs );
            this.$refs.dialog.showTips();
        }
    }
})

4. 总结

在这个简单的tips组件里,我们实现了用props传递参数,用$emit向外传递参数,用slot插槽来定制内容。

需要注意的是:组件props是单向绑定,即父组件的属性发生变化时,子组件能接收到相应的数据变化,但是反过来就会出错。即不能在子组件中修改props传过来的数据,来达到修改父组件属性的目的。这是为了防止子组件无意修改了父组件的状态。

另外,每次父组件更新时,子组件的所有 prop 都会更新为最新值。这意味着你不应该在子组件内部改变 prop。如果你这么做了,Vue 会在控制台给出警告。如果真的需要在子组件里进行修改,可以用这两种方法应对:

定义一个局部变量,并用 prop 的值初始化它:

props: ['initialCounter'],
data: function () {
  return { counter: this.initialCounter }
}

定义一个计算属性,处理 prop 的值并返回。

props: ['size'],
computed: {
  normalizedSize: function () {
    return this.size.trim().toLowerCase()
  }
}

当然,这只是单页面中组件的实现,更复杂的组件后续我们也会实现。

文章内容由蚊子的前端博客进行发布,或许你想看看他其他的文章呢: http://www.xiabingbao.com

原文地址: https://www.xiabingbao.com/vu...


小蚊酱
5.3k 声望205 粉丝

爱生活,爱前端