使用组件的细节点
is属性:
有些html标签如table,ul,ol,select对哪些标签可以出现在其内部是有着严格的要求的。
因此当这些标签内部出现了自定义组件,有可能会被作为无效的内容提升到外部,导致页面渲染出错。
而是用is属性则可以解决这个问题,在子级标签中用is属性来使用自定义组件。
<table>
<tr is="模板名称"></tr>
</table>子组件中的data必须是一个函数,并且返回一个对象,当一个组件被多次使用的时候,组件间的数据不会相互影响。
Vue.component('row', {
data:function () {
return{
content:'this is row'
}
},
template:"<tr><td>{{content}}</td></tr>"
})
- 通过ref 获取dom节点
<div @click="handdle" ref="hello">
hello world
</div>
handdle:function(){
console.log(this.$refs.hello)
}
父子组件传值
- 父组件向子组件传值
父组件通过属性绑定将值绑定到子组件上,子组件通过 props 属性来接收,然后子组件就可以使用父组件中传递过来的数据了。props是一个数组。
- 子组件向父组件传值:
- 子组件通过this.$emit()方法向父组件传值;
- $emit("事件名",args)第一个参数是自定义事件名,第二个参数是需要传递的数据
- 父组件使用v-on监听子组件
- 单向数据流
父组件可以随意向子组件传递参数,子组件不可以改变父组件的数据,否则会报警告。
解决办法:要想改变父组件的参数,在子组件的data属性中拷贝一份父组件的数据,然后可以对数据进行操作。
<div id="app">
<counter :count="1" @change="handleAdd"></counter>
<counter :count="2" @change="handleAdd"></counter>
<div>{{total}}</div>
</div>
<script>
var counter = {
props:['count'],
data:function(){
return{
number:this.count
}
},
template:'<div @click="handdle">{{number}}</div>',
methods:{
handdle:function(){
this.number++;
this.$emit('change',1)
}
}
}
var app = new Vue({
el:'#app',
data:{
total:3
},
components:{
counter:counter
},
methods: {
handleAdd:function(step){
this.total+=step
}
}
})
</script>
组件参数校验与非props特性
- 简单校验:限定传入的值的类型,可以是单个类型,也可以是一个数组。
props:{
content: [String,Number]
}
- 复杂校验:
props:{
content:{
type: String,//数据类型
required: false,//是否是必传
default: 'default content',//如果没传值,默认值
validator: function(val){//自定义校验器,数据必须>5
return (val.length>5)
}
}
}
给组件绑定原生事件
- 在父组件上绑定事件(如:@click.native="handleClick")
- 在vue实例中的methods下定义事件函数。
<child @click.native="handleClick" ></child>
传统方法绑定事件:
- 在子组件上绑定事件
- 在子组件中的methods中设置相应的事件函数,并在函数中定义自定义事件函数,将自定义事件函数传给父组件(如 this.$emit('click'))
- 在父组件上绑定子组件methods函数中传来的自定义函数
- 在父组件methods中设置对应的事件函数
非父子组件间的传值
- vuex,
- 发布订阅模式(总线模式)
- 给 Vue 类加上原型属性 bus, 这样每个 Vue 实例都能访问到原型属性 bus
Vue.prototype.bus = new Vue()
- 利用 bus 的实例方法 $emit 触发事件
this.bus.$emit('触发事件', this.selfContent)
- 再利用生命周期方法(钩子) mounted 给 bus 绑定监听函数, 在事件触发时执行
this.bus.$on('eventName', cellback)
- 建议使用箭头函数做为回调函数,不会影响回调函数中this的指向问题
this.bus.$on('eventName',(msg) => {
this.selfContent = mag;
})
完整代码
<div id="app">
<child content="Dell"></child>
<child content="Lee"></child>
</div>
<script>
Vue.prototype.bus = new Vue()
Vue.component('child',{
data:function(){
return{
selfContent:this.content
}
},
props:{
content:{
type:String,
}
},
template:'<div @click="handClick">{{selfContent}}</div>',
methods: {
handClick:function () {
this.bus.$emit('change',this.selfContent)
}
},
mounted:function(){
var that = this;
this.bus.$on('change',function(msg){
that.selfContent = msg
})
}
})
var app = new Vue({
el:'#app',
})
</script>
vue中使用插槽
- 插槽:可以使父组件很容易向子组件传递DOM元素
- 匿名插槽:父组件内部的DOM元素,可以通过子组件的<slot></slot>标签渲染,slot标签中可以写默认的内容,如果父组件中不传递就显示默认内容
Vue.component('child',{
template:'<div>' +
'<slot>默认内容</slot>' +
'</div>',
})
- 具名插槽:有名字的插槽,父组件中为slot属性设置值,子组件slot中使用name属性接收父组件slot的属性值可以实现具名插槽。
<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',{
template:'<div>' +
'<slot name="header">默认</slot>' +
'<div class="content">content</div>' +
'<slot name = "footer"></slot>' +
'</div>'
})
var app = new Vue({
el:'#app',
})
</script>
- 作用域插槽
- 使用场景:当子组件做循环的数据和结构需要外部传入时
- 父组件中必须以
<template slot-scope='自定义'></template>
作为包裹的标签,slot-scope接受子组件传递过来的值
- 作用是:可以使父组件灵活的控制样式
<div id="app">
<child>
<template slot-scope="props">
<h1>{{props.item}}</h1>
</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></slot>" +
"</ul></div>"
})
var app = new Vue({
el:'#app',
})
</script>
动态组件与v-once指令
- 使用is与使用:is的区别:
- is:如果这里使用is,is=后面跟的是字符串,就是指将当前使用is替换为名为type的组件,
- :is:如果使用:is,其实,就是v-bind:is,:is=后面跟的就是一个JS表达式,表达式为type指向了type这个对象
- vue自带的动态标签
<component></component>
根据type的值变换为相应的组件
如果点击按钮前是type=“one”则会显示vue.component(“one”,{})这个组件
如果点击前按钮是type=“two”则会显示vue.component(“two”,{})这个组件
<div id="app">
<component :is="type"></component>
<button @click="handclick">点击</button>
</div>
<script>
Vue.component('child-one',{
template:'<div>one</div>'
})
Vue.component('child-two',{
template:'<div>two</div>'
})
var app = new Vue({
el:'#app',
data:{
type:'child-one'
},
methods:{
handclick:function(){
this.type = this.type =='child-one'?'child-two':'child-one'
}
}
})
- v-once只对内部渲染一次,如果模板发生变化,也不会理会