vue UI组件开发
2017-07-01 本文已影响210人
rayman_v
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
标签子元素只能是tbody
或tr
、select
标签子元素只能是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>

- 组件内无法直接与组件外数据集绑定,只能发送事件通知,组件内使用
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>

- 可以定义一个全局实例
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>

-
<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
中访问到组件的对象;