vue UI组件开发

1. 新建组件:

<script src="/public/javascripts/vue.js"></script>
<style>
    #app1{background-color: red}
    #app2{background-color: blue}
</style>
<body>
<div id="app1">
    <box-one></box-one>
    <box-two></box-two>
    <boxThree></boxThree>
</div>
<div id="app2">
    <box-one></box-one>
    <box-two></box-two>
</div>
<box-one></box-one>
<box-two></box-two>
<script>
Vue.component('box-one', {
    template: '<div class="box-one">box-one</div>'
});
var app1 = new Vue({
    el: '#app1',
    components: {
        'box-two': {
            template: '<div class="box-two">box-two</div>'
        },
        'boxThree': {
            template: '<div class="boxThree">boxThree</div>'
        }
    }
});
var app2 = new Vue({
    el: '#app2'
});
</script>
  • Vue.component 方法用于注册全局组件,new Vue({ components: {}}) 用于注册某个实例内使用的组件,所以 <box-two></box-two>#app2 中失效;
  • 由于浏览器渲染标签时会把标签全部转成小写,驼峰式组件名称会失效,如事例中的 <boxThree></boxThree>
  • 在实例以外无法使用任何组件;

2. 浏览器渲染网页标签的限制:

<script src="/public/javascripts/vue.js"></script>
<style>
    .red{background-color: red}
    .blue{background-color: blue}
</style>
<body>
<div id="app1">
    <table class="red">
        <box-one></box-one>
    </table>
    <select class="red">
        <box-two></box-two>
    </select>
    
    <table class="blue">
        <tr is="box-one"></tr>
    </table>
    <select class="blue">
        <option is="box-two"></option>
    </select>
</div>
<script>
Vue.component('box-one', {
    template: '<tr><td>box-one</td></tr>'
});
Vue.component('box-two', {
    template: '<option>option</option>'
});
var app1 = new Vue({
    el: '#app1'
});
</script>
  • 由于受到浏览器渲染标签的限制,例如 table 标签子元素只能是 tbodytrselect 标签子元素只能是 option ,类似的其他更多的标签,所以 vue 引入了 is 属性;
  • 如果使用的是组件文件 .vue 后缀的文件开发,则因为是字符串方式渲染的,所以不受限制;

3. 组件中的 data 数据集:

<script src="/public/javascripts/vue.js"></script>
<body>
<div id="app1">
    <done-button></done-button>
</div>
<script>
Vue.component('done-button', {
    template: '<button>{{text}}</button>',
    data: function (){
        return {
            text: 'ok'
        }
    }
});
var app1 = new Vue({
    el: '#app1'
});
</script>
  • 不同于 new Vue({}) 中的实例数据集,组件中的 data 数据集必须是一个函数,再使用函数返回一个对象集,否则会报错;

4. 实例给组件传值:

<script src="/public/javascripts/vue.js"></script>
<body>
<div id="app1">
    <done-button text="submit" textOne="submit1" text-two="submit2"></done-button>
</div>
<script>
Vue.component('done-button', {
    template: '<button :data-text="text" :data-text-one="textOne" :data-text-two="textTwo">{{text}}</button>',
    props: ['text', 'textOne', 'textTwo']
});
var app1 = new Vue({
    el: '#app1'
});
</script>
  • props 定义的字符串数组中的值,可以像 data 数据集一样在组件内自由调用;
  • props 定义的字符串数组中的值,会作为组件标签中的标签属性名,给实例赋值;
  • 受浏览器渲染标签属性的影响,标签属性的命名如果使用驼峰式,则使用时 vue 会自动生成对应的短横线隔开式属性名,如事例中的 text-two

5. 组件标签属性使用动态数据:

<script src="/public/javascripts/vue.js"></script>
<style>
    .appNumber{background-color: red}
</style>
<body>
<div id="app1">
    <done-button :number="appNumber"></done-button>
    <button class="appNumber" @click="appNumber++">{{appNumber}}</button>
</div>
<script>
Vue.component('done-button', {
    template: '<button @click="number++">{{number}}</button>',
    props: ['number']
});
new Vue({
    el: '#app1',
    data: {
        appNumber: 0
    }
});
</script>
  • 实例中的 appNumber 变化时,组件中的 number 会跟着变化;
  • 组件中的 number 变化时,实例中的 appNumber 并不会变化;
  • 实例中的 appNumber 的值,会覆盖组件内 number 的值;
  • 但如果 appNumber 的值是数组或对象,由于是引用类型,则双方都会互相影响;

6. 自定义组件属性的值的规则:

<script src="/public/javascripts/vue.js"></script>
<body>
<div id="app1">
    <done-button number1="a" number2="1" :number3="1" ></done-button>
</div>
<script>
Vue.component('done-button', {
    template: '<button :num1="number1" :num2="number2" :num3="number3">{{number1}}</button>',
    props: {
        number1: {
            type: Number
        },
        number2: {
            type: Number
        },
        number3: {
            type: Number
        }
    }
});
new Vue({
    el: '#app1'
});
</script>
  • props 允许接受一个对象作为参数,每个参数作为一个元素属性,type 为属性的值期待的类型;
  • 如果条件不符合,vue 的开发版下会在 console 打印出错误信息,但功能还是能正常传值的;
  • 事例中 number2 传递的其实是 String 类型的 '1',而只有 :number3 这种赋值才能传递数值类型的 1
  • 可选项:
{
   // 属性类型: String、Number、Boolean、Function、Object、Array,null-任意类型,
   // 可以使用数组多选
   type: null,
   
   // 是否必须被赋值:true、false
   required: false,
   
   // 默认值:可以是一般任意值或有返回值的函数
   default: '',
   
   // 自定义判断函数:参数 value 为调用时传入的值,
   // 返回 true、false 来通知 vue 机制是否报错
   validator: function(value){ return true } 
}

7. 组件内给实例发送通知:

<script src="/public/javascripts/vue.js"></script>
<body>
<div id="app1">
    <done-button v-on:child="father" ></done-button>
</div>
<script>
Vue.component('done-button', {
    template: '<button v-on:click="add()">增加</button>',
    methods: {
        add: function () {
            this.$emit('child', 11);
        }
    }
});
new Vue({
    el: '#app1',
    methods: {
        father: function(number) {
            console.log('father' + number);
        }
    }
});
</script>
vue-component-2.gif
  • 组件内无法直接与组件外数据集绑定,只能发送事件通知,组件内使用 this.$emit('child', 11) 告诉实例,该调用 child 事件了,后面的参数会变成 child 的调用参数传递;
  • 实例在初始化组件时,定义 v-on:child="father" 元素属性,来监听 child 事件收到通知时应该执行什么处理,通过 father 的形参,可以直接访问 child 的调用参数;

8. 组件之间通信:

<script src="/public/javascripts/vue.js"></script>
<body>
<div id="app1">
    <done-button ></done-button>
    <cancel-button></cancel-button>
</div>
<script>
var bus = new Vue();
Vue.component('done-button', {
    template: '<button v-on:click="send()">发送</button>',
    methods: {
        send: function () {
            bus.$emit('done-emit', 11);
        }
    }
});
Vue.component('cancel-button', {
    template: '<p>{{text}}</p>',
    data: function (){
        return {
            text: '00'
        }
    },
    mounted: function() {
        var _this = this;
        bus.$on('done-emit', function(number) {
            _this.text = number;
        });
    }
});
new Vue({
    el: '#app1',
    methods: {
        call: function(value) {
            console.log('father:' + value);
        }
    }
});
</script>
vue-component-3.gif
  • 可以定义一个全局实例 bus ,在不同组件内使用 bus.$emit 发送通知,使用 bus.$on 监听通知;

9. 组件内容节点的分发:

<script src="/public/javascripts/vue.js"></script>
<body>
<div id="app1">
    <box></box>
    <box>
        <h4>box1</h4>
    </box>
    <box>{{box2Text}}</box>
</div>
<script>
Vue.component('box', {
    template: '<p><slot>默认</slot></p>'
});
new Vue({
    el: '#app1',
    data: {
        box2Text: 'box2'
    }
});
</script>
  • vue 默认在组件内定义了 <slot> 标签,用于获取组件被使用时的内容节点;
  • <slot> 标签的内容为组件的默认内容节点;
  • 内容节点也可使用动态数据;

10. 多个 <slot> 标签之间的使用:

<script src="/public/javascripts/vue.js"></script>
<body>
<div id="app1">
    <box>
        <p>ppppp</p>
        
        <p slot="h4">h4</p>
        <h4 slot="h4">h4</h4>
        
        <p slot="h5">h5</p>
        <h5 slot="h5">h5</h5>
    </box>
</div>
</div>
<script>
Vue.component('box', {
    template: [
        '<div id="box">',
            '<div class="default">',
                '<slot></slot>',
            '</div>',
            '<div class="h4">',
                '<slot name="h4"></slot>',
            '</div>',
            '<div class="h5">',
                '<slot name="h5"></slot>',,
            '</div>',
        '</div>',
    ].join('')
});
new Vue({
    el: '#app1'
});
</script>
  • 没有声明 name 属性的 <slot> 标签,是为组件的内容节点中没有声明 slot 属性的标签而占位;
  • 声明了 name 属性的 <slot> 标签,是为组件的内容节点中与之相等 slot 属性的标签而占位;
  • 多个标签应用了相同的 slot 属性也会有效;

11. <slot> 标签回传数据给内容节点:

<script src="/public/javascripts/vue.js"></script>
<body>
<div id="app1">
    <box >
        <template scope="props">
            <span>{{props.text}}</span>
        </template>
    </box>
</div>
</div>
<script>
Vue.component('box', {
    template: '<div id="box"><slot v-for="i in items" :text="i"></slot></div>',
    data: function (){
        return {
            items: [0,1,2,3,4]
        }
    }
});
new Vue({
    el: '#app1'
});
</script>
  • 首先,数据是组件内提供的,但数据的布局方式由实例调用组件时决定;
  • 在组件的内容节点内,必须使用 <template> 标签包含着要渲染的子元素,并且定义 scope="props" 属性,而 <template> 标签内则是 props 对象的作用域上下文;
  • props 内自动含有 <slot> 标签中的属性,例如事例中的 text 属性,则可直接使用 props.text 访问到 text 属性的值;
  • 当然,也可以结合 <slot name="header"> 使用,而 <template slot="header"> 即可;
  • <template> 标签为 vue 保留的标签,实际只是个占位符;

12. 动态切换组件:

<script src="/public/javascripts/vue.js"></script>
<body>
<div id="app1">
    <component :is="view"></component>
    <button @click="view = 'inlinebox'">change</button>
</div>
</div>
<script>
Vue.component('box', {
    template: '<div id="box">box</div>',
});
Vue.component('inlinebox', {
    template: '<div id="inlinebox">inlinebox</div>'
});
new Vue({
    el: '#app1',
    data: {
        view: 'box'
    }
});
</script>
vue-component-4.gif
  • <component> 标签为 vue 保留的标签,实际只是个占位符;
  • is 属性可指定组件标签名,也可绑定动态变量;

13. 在实例中访问子元素对象:

<script src="/public/javascripts/vue.js"></script>
<body>
<div id="app1">
    <box ref="box1"></box>
</div>
</div>
<script>
Vue.component('box', {
    template: '<div id="box">box</div>',
});
new Vue({
    el: '#app1',
    mounted: function() {
        console.log(this.$refs);
    }
});
</script>
  • 只要为组件指定 ref 属性,实例中则会在 $refs 中访问到组件的对象;
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,236评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,867评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,715评论 0 340
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,899评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,895评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,733评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,085评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,722评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,025评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,696评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,816评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,447评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,057评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,254评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,204评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,561评论 2 343

推荐阅读更多精彩内容