我们今天来聊一下关于vue组件的问题。
1.is的使用
假设有个这样的场景.我希望写一个table表格
常规的HTML结构
<div id="root">
<table>
<tbody>
<tr>
<td>1</td>
</tr>
<tr>
<td>2</td>
</tr>
<tr>
<td>3</td>
</tr>
</tbody>
</table>
</div>
那么现在我们希望能通过,vue组件的方式,那么我们看下以下的代码
<div id="root">
<table>
<tbody>
<row></row>
<row></row>
<row></row>
</tbody>
</table>
</div>
Vue.component("row",{
template:"<tr><td>1</td></tr>"
})
new Vue({
el:"#root"
})
打开浏览器你会发现好像和原来的表格没有多大的区别,但是我们打开控制台查看DOM元素就会发现,我们的tr在在table的外面,这是不符合我们W3C编码的标准的。那么怎么解决这个问题呢?
在vue中,它为这种情况提供了一个解决方法,我们来看下怎么解决这个问题。
<div id="root">
<table>
<tbody>
<tr is="row"></tr>
<tr is="row"></tr>
<tr is="row"></tr>
</tbody>
</table>
</div>
<script>
Vue.component("row",{
template:"<tr><td>1</td></tr>"
})
new Vue({
el:"#root"
})
</script>
这个时候我们打开控制台,就会发现它的结构就已经符合我们W3C的编码标准了。其实呢,像这种符合标签还有很多例如,,这个标签下面是要添加option的,那么我们来看下以下代码,
<div id="root">
<select>
<row></row>
<row></row>
<row></row>
<row></row>
</select>
</div>
<script>
Vue.component("row",{
template:"<option>1</option>"
})
new Vue({
el:"#root"
})
</script>
我们查看DOM的时候,一样会发现是没有option标签的,我们也只能使用vue中的is属性
<div id="root">
<select>
<option is="row"></option>
<option is="row"></option>
<option is="row"></option>
<option is="row"></option>
</select>
</div>
<script>
Vue.component("row",{
template:"<option>1</option>"
})
new Vue({
el:"#root"
})
</script>
2.关于组件中的data
<div id="root">
<table>
<tbody>
<tr is="row"></tr>
<tr is="row"></tr>
<tr is="row"></tr>
</tbody>
</table>
</div>
<script>
Vue.component("row",{
data:{
message:"这是一个表格"
},
template:"<tr>{{message}}</tr>"
})
new Vue({
el:"#root"
})
</script>
这个时候,我们就会发现,页面无法出现数据,而且还报错了,这是什么原因呢?
一个组件的 data 选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝
也就是说,要是想在组件里面使用data选项,不能够直接写成对象形式,而是一个函数
<div id="root">
<table>
<tbody>
<tr is="row"></tr>
<tr is="row"></tr>
<tr is="row"></tr>
</tbody>
</table>
</div>
<script>
Vue.component("row",{
data:{
message:"这是一个表格"
},
template:"<tr>{{message}}</tr>"
})
new Vue({
el:"#root"
})
</script>
这样子写组件才能正确的显示数据.千万要注意这个问题。
3.关于组件中的 ref
我们来看下vue是怎么操作的页面的DOM元素。vue中操作DOM元素是通过ref这个属性来操作的。
<div id="root">
<div ref="hello" @click="hand">
hello
</div>
</div>
<script>
new Vue({
el:"#root",
methods:{
hand:function(){
console.log(this.$refs.hello)
}
}
})
</script>
以上的代码是可以输出div这个DOM元素的,但是这和组件中使用ref有关系吗?我们假设这个div标签是个组件呢?我们来做两个组件相加数值相加的一个功能。
<div id="root">
<item @change="handC" ref="one"></item>
<item @change="handC" ref="two"></item>
<div>{{total}}</div>
</div>
<script>
Vue.component("item",{
data:function(){
return {
num:0
}
},
template:"<div @click='hand'>{{num}}</div>",
methods:{
hand:function(){
this.num++
this.$emit("change",this.num)
}
}
})
new Vue({
el:"#root",
data:{
total:0
},
methods:{
handC:function(res){
this.total = this.$refs.one.num+this.$refs.two.num
}
}
})
</script>
4.父组件向子组件传值
所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解。
父组件通过属性的方式来向子组件传递值,子组件用props来进行接收
<div id="root">
<item :count="0"></item>
<item :count="1"></item>
</div>
<script>
var item = {
props:["count"],
template:"<div>{{count}}</div>"
}
new Vue({
el:"#root",
components:{
item:item
}
})
</script>
那么我们来进行一个组件的计算,那么就很自然写以下的代码,
<div id="root">
<item :count="0"></item>
<item :count="1"></item>
</div>
<script>
var item = {
props:["count"],
template:"<div @click='hand'>{{count}}</div>",
methods:{
hand:function(){
this.count++
}
}
}
new Vue({
el:"#root",
components:{
item:item
}
})
</script>
这个时候,我们的确是可以点击上面的某个组件让值进行计算,但是我们打开控制台就会发现,就会有报错.为什么呢?因为我们违背vue中”单向数据流”的概念。子组件是不可以直接修改父组件传递过来的值,但有些时候,我们必须要进行修改,怎么办呢?
<div id="root">
<item :count="0"></item>
<item :count="1"></item>
</div>
<script>
var item = {
props:["count"],
data:function(){
return {
num:this.count
}
},
template:"<div @click='hand'>{{num}}</div>",
methods:{
hand:function(){
this.num++
}
}
}
new Vue({
el:"#root",
components:{
item:item
}
})
</script>
我们在以上的代码中,在组件中自定义了一个num一个属性,让它等于父组件传递过来的count,那么我们自己修改组件中值是完全没有问题的。
5.子组件向父组件传值
子组件要想向父组件传值,那么就要通过$emit的方法向父组件传值
<div id="root">
<item :count="0" @change="hanC"></item>
<item :count="1" @change="hanC"></item>
<div>{{total}}</div>
</div>
<script>
var item = {
props:["count"],
data:function(){
return {
num:this.count
}
},
template:"<div @click='hand'>{{num}}</div>",
methods:{
hand:function(){
this.num++
this.$emit("change",1)
}
}
}
new Vue({
el:"#root",
data:{
total:1
},
components:{
item:item
},
methods:{
hanC:function(res){
this.total += res
}
}
})
</script>