组件使用细节点
is用于动态组件且基于 DOM 内模板的限制来工作。
<!-- 组件会在 `currentTabComponent` 改变时改变 -->
<component v-bind:is="currentView"></component>
<!-- `<my-row>` 放在一个`<table>` 内可能无效且被放置到外面 -->
<!-- 所以使用is 类似的有ul>li select>option -->
<table>
<tr is="my-row"></tr>
</table>
<ul>
<li is="my-row"></li>
</ul>
<select>
<option is="my-row"></option>
</select>
一个组件的 data
选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝
Vue.component('button-counter', {
data: function () {
return {
count: 0
}
},
template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
})
ref
被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的 $refs
对象上。
如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素
<p ref="p">hello</p>
如果用在子组件上,引用就指向组件实例
<child-component ref="child"></child-component>
计数example:
<div id="root">
<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++;
this.$emit('change');
}
}
})
var vm = new Vue({
el: '#root',
data: {
total: 0
},
methods: {
handleChange: function() {
this.total = this.$refs.one.number + this.$refs.two.number;
}
}
})
</script>
父子组件的数据传递
父组件通过属性的形式向子组件传值,子组件通过事件触发的形式向父组件传值。
父组件向子组件传递数据----props
单向数据流:父组件可以向子组件传递参数,但子组件不能直接修改父组件传递过来的参数。因为一旦修改的参数不是一个基础类型而是引用类型的数据时,有可能接收的引用类型的数据还被其他的子组件使用,改变传递过来的数据里的内容可能对其他的子组件造成影响。
<div id="root">
<!--传递-->
<!--加了冒号是数字(js表达式) 不加是字符串-->
<counter :count="0"></counter>
<counter :count="1"></counter>
</div>
<script>
var counter = {
props: ['count'], //接收
data: function() {
return {
number: this.count//把count复制一份放到子组件自己的data里 解决单向数据流
}
},
template: '<div @click="handleClick">{{number}}</div>',
methods: {
handleClick: function() {
this.number++;
}
}
}
var vm = new Vue({
el: "#root",
components: {
counter: counter
}
})
</script>
子组件向父组件传递数据----事件触发
<div id="root">
<!--2 @inc="handleInc 父组件在这里监听子组件传递的事件-->
<counter :count="0" @inc="handleInc"></counter>
<counter :count="1" @inc="handleInc"></counter>
<div>{{total}}</div>
</div>
<script>
var counter = {
props: ['count'],
data: function() {
return {
number: this.count
}
},
template: '<div @click="handleClick">{{number}}</div>',
methods: {
handleClick: function() {
this.number = this.number + 2;
//1 子组件向父组件通过事件触发的形式传递数据 inc后面可以携带多个参数
this.$emit('inc', 2);
}
}
}
var vm = new Vue({
el: "#root",
components: {
counter: counter
},
data: {
total: 1
},
methods: {
handleInc: function(step) { //step即子组件向父组件传递的参数 2
this.total += step;
}
}
})
</script>
组件参数校验
<div id="root">
<child content="helloo"></child>
</div>
<script>
Vue.component('child', {
// props: {
// content: [Number, String]
// },
props: {
content: {
type: String,//类型为string
required: false,//如果为true则一定要传content
default: 'default value',//如果没传content显示的默认值
validator: function(value) {//value为传入的字符串的内容
return (value.length > 5)
}
}
},
template:'<div>{{content}}</div>'
})
var vm = new Vue({
el: "#root",
})
给组件绑定原生事件
要在一个组件的根元素上直接监听一个原生事件,可以使用 v-on
的 .native
修饰符:
<base-input v-on:focus.native="onFocus"></base-input>
<div id="root">
<!--监听的是自定义事件 -->
<child @click="handleClick"></child>
</div>
<script>
Vue.component('child', {
template:'<div @click="handleChildClick">Child</div>',
methods: {
handleChildClick: function() {
alert('child click');
this.$emit('click');//触发自定义事件
}
}
})
var vm = new Vue({
el: "#root",
methods: {
handleClick: function() {
alert('click');
}
}
})
</script>
<div id="root">
<!--监听原生事件 -->
<child @click.native="handleClick"></child>
</div>
<script>
Vue.component('child', {
template:'<div>Child</div>',
})
var vm = new Vue({
el: "#root",
methods: {
handleClick: function() {
alert('click');
}
}
})
</script>
非父子组件间的数据传递(Bus/总线/发布订阅模式/观察则模式)
<div id="root">
<child content="a"></child>
<child content="b"></child>
</div>
<script>
Vue.prototype.bus = new Vue()//!
Vue.component('child', {
props:{
content: String
},
data: function() {
return {
selfContent: this.content
}
},
template:'<div @click="handleClick">{{selfContent}}</div>',
methods: {
handleClick: function() {
this.bus.$emit('change', this.selfContent)//!
}
},
//声明周期钩子 被挂载时触发
mounted: function() {
var this_ = this;
this.bus.$on('change', function(msg) {//!
this_.selfContent = msg
})
}
})
var vm = new Vue({
el: "#root",
})
</script>
插槽slot
更方便地向子组件传递DOM元素,子组件通过<slot></slot>使用内容
可以在slot里写一些默认的值——<slot>默认内容</slot>
<div id="root">
<child><p>dell</p></child>
</div>
<script>
Vue.component('child', {
props: ['content'],
template: '<div> <p>hello</p> <slot>默认内容</slot> </div>'
})
var vm = new Vue({
el: "#root",
})
具名插槽
<body>
<div id="root">
<child>
<div class="header" slot="header">header</div>
<div class="footer" slot="footer">footer</div>
</child>
</div>
<script>
Vue.component('child', {
props: ['content'],
template: '<div> <slot name="header"> </slot><slot name="header"></slot></div>'
})
var vm = new Vue({
el: "#root",
})
</script>
自 2.6.0 起有所更新。
<template v-slot:header>
<h1>Here might be a page title</h1>
</template>
作用域插槽
当子组件做循环或者某一部分结构应该由外部传递进来的时候就用作用域插槽
<div id="root">
<child>
<template slot-scope="props">
<li>{{props.item}}</li>
</template>
</child>
</div>
<script>
Vue.component('child', {
data: function() {
return {
list: [1,2,3,4]
}
},
template: '<div><ul><slot v-for="item of list" :item="item">{{item}}</slot></ul></div>'
})
var vm = new Vue({
el: "#root",
})
</script>
动态组件
<component v-bind:is="currentTabComponent"></component>
v-once指令
只渲染元素和组件一次。随后的重新渲染,元素/组件及其所有的子节点将被视为静态内容并跳过,可以用于优化更新性能。