我们今天来聊一下关于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>