1.table中使用组件
我们写一个表格table代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <script src="./vue.js"></script> <title>Document</title> </head> <body> <div id="app"> <table> <tbody> <row></row> <row></row> <row></row> </tbody> </table> </div> </body> <script> Vue.component('row',{ template:"<tr><td>this is a row</td></tr>" }) var vm=new Vue({ el:"#app", }) </script> </html>
渲染效果如下:
看似没有问题,但是当我们将控制台打开,就能发现有不对的地方了
tr和table居然在同级,这违反了HTML5的规范。要解决这个问题,我们可以使用“is”,来指定组件。
如下修改:
<table> <tbody> <tr is="row"></tr> <tr is="row"></tr> <tr is="row"></tr> </tbody> </table>
意思是tobody中的tr是row组件,这样既可以使用我们的组件,又可以符合HTML5的规范。控制台中的结构也是正确的。
同理,ul、ol、select这些元素在直接嵌入组件也可能会出现上面的Bug。
2.组子件中的data
在前面代码的基础上,我们将row组件内容修改一下,如下:
Vue.component('row',{ data:{ content:"this is row" }, template:"<tr><td>{{content}}</td></tr>" }) var vm=new Vue({ el:"#app", })
主要就是将文本内容抽出来做数据。
然后发现这种做法会报错,内容如下图:
这是因为,在非根组件的组件中使用data,需要用一个函数来返回data的内容,内容是一个对象,修改如下:
Vue.component('row',{ data:function(){//一个函数 return { content:'this is content' } }, template:"<tr><td>{{content}}</td></tr>" })
这样设计的目的就是为了子组件在复用的时候,data内的数据不会相互影响,所以通过函数返回的方式,保证每一个子组件有独立的数据存储。
完整代码如下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <script src="./vue.js"></script> <title>Document</title> </head> <body> <div id="app"> <table> <tbody> <tr is="row"></tr> <tr is="row"></tr> <tr is="row"></tr> </tbody> </table> </div> </body> <script> Vue.component('row',{ data:function(){ return { content:'this is content' } }, template:"<tr><td>{{content}}</td></tr>" }) var vm=new Vue({ el:"#app", }) </script> </html>
3.组件使用ref
有些时候我们会写比较复杂的动画,操作DOM的行为就可能无法避免了,我们可以使用ref来获取dom,如下:
<div id="app"> <div ref='hello' @click="handleClick" > hello! </div>
var vm=new Vue({ el:"#app", methods:{ handleClick:function(){ //this.$ref是所有ref的集合 console.log(this.$refs.hello) alert('hello') } } })
我们通过给div标签设置ref,并取名为hello,然后通过this.$refs.hello就可以获取到这个div的dom
但是如果ref设置在一个组件上呢?
比如我们现在需要做两个计数器,点击一下就会加1,然后还有一个求和,如下:
<body> <div id="app"> <counter></counter> <counter></counter> <div>{{total}}</div> </div> </body>
Vue.component('counter',{ template:'<div @click="handleClick">{{number}}</div>', data:function(){ return { number:0 } }, methods:{ handleClick:function(){ this.number++; } } }) var vm=new Vue({ el:"#app", data:{ total:0 } })
现在实现的功能还只能计数,不能求和。我们也可以使用ref来获取组件中的值
<div id="app"> <!-- 子组件触发change,父组件监听,触发handleChange方法 --> <counter ref="one" @change="handleChange"></counter> <counter ref="two" @change="handleChange"></counter> <div>{{total}}</div> </div>
Vue.component('counter',{ template:'<div @click="handleClick">{{number}}</div>', data:function(){ return { number:0 } }, methods:{ handleClick:function(){ this.number++; //触发change方法 this.$emit('change') } } }) var vm=new Vue({ el:"#app", data:{ total:0 }, methods:{ handleChange:function(){ //this.$refs.one、this.$refs.two获取到的是组件的引用 console.log(this.$refs.one); console.log(this.$refs.two); this.total=this.$refs.one.number+this.$refs.two.number; } } })
打印结果如下
this.$refs.one、this.$refs.two获取到的是组件的引用,而不是dom
渲染出来的结果:
完整代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <script src="./vue.js"></script> <title>Document</title> </head> <body> <div id="app"> <!-- 子组件触发change,父组件监听,触发handleChange方法 --> <counter ref="one" @change="handleChange"></counter> <counter ref="two" @change="handleChange"></counter> <div>{{total}}</div> </div> </body> <script> Vue.component('counter',{ template:'<div @click="handleClick">{{number}}</div>', data:function(){ return { number:0 } }, methods:{ handleClick:function(){ this.number++; //触发change方法 this.$emit('change') } } }) var vm=new Vue({ el:"#app", data:{ total:0 }, methods:{ handleChange:function(){ //this.$refs.one、this.$refs.two获取到的是组件的引用 console.log(this.$refs.one); console.log(this.$refs.two); this.total=this.$refs.one.number+this.$refs.two.number; } } }) </script> </html>