子组件
栗子:
需要注意的点都在代码中注释标出来了
<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <title></title> <style> .wrap { width: calc(200px * 4 + 80px); margin: 0 auto; user-select: none; } .box { width: 200px; height: 260px; /*border: 1px solid black;*/ background-color: rgba(10, 200, 30, 0.5); border-radius: 10px; float: left; margin: 10px; } .box img { width: 100%; /*height: 200px;*/ border-radius: 50%; } .box p { text-align: center; } </style> </head> <body> <div id="app"> <div class="wrap"> <tag></tag> <!-- 可以复用子组件 --> <tag></tag> <tag></tag> <tag></tag> </div> </div> </body> <script src="js/vue.js"></script> <script> //定义了一个子组件 let titleTag = { template: ` <p> <b> 这是一种纯二哈 </b> </p> `, }; let tag = { template: ` <div class="box"> <img src="img/001.jpg" alt=""> <title-tag /> <p @click="fn"> 锤它:<b>{{ num }}下</b> </p> </div> `, // 能被复用的组件(除了根组件),数据都要做局部化处理,因为复用组件后,组件的数据是相互独立的,也就是说每个子组件都有属于自己的数据,不共用。 // data的值为绑定的方法的返回值,返回值是存放数据的字典,和根组件的data方式不一样。 data () { return { num: 0 } }, methods: { fn() { this.num ++ } }, //子组件中还能放他的子组件,可以无限的放下去。 components: { titleTag, } }; new Vue({ el: '#app', components: { tag, } }); </script> </html>
组件标签不能添加系统事件,只能添加自定义事件,自定义事件在组件内部通过$emit主动触发,因为你只能给一个标签加点击事件,而组件标签里面是很多标签,所以不能给组件标签加系统事件,什么是系统事件,就是 @click ,但是你可以给他加上自定义事件,在后面的子组件给父组件传数据的时候会讲。
组件传参-父传子
<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <title>父传子</title> <style> .wrap { width: calc(200px * 4 + 80px); margin: 0 auto; user-select: none; } .box { width: 200px; height: 260px; /*border: 1px solid black;*/ background-color: rgba(10, 200, 30, 0.5); border-radius: 10px; float: left; margin: 10px; } .box img { /*width: 100%;*/ height: 160px; border-radius: 50%; margin: 0 auto; display: block; } .box p { text-align: center; } </style> </head> <body> <div id="app"> <div class="wrap"> <tag v-for="dog in dogs" v-bind:dog="dog" :a="1" :b="2" /> </div> </div> </body> <script src="js/vue.js"></script> <script> let dogs = [ { title: '二哈1号', img: 'img/1.jpg', }, { title: '二哈2号', img: 'img/2.jpg', }, { title: '二哈3号', img: 'img/3.jpg', }, { title: '二哈4号', img: 'img/4.jpg', }, { title: '二哈1号', img: 'img/1.jpg', }, { title: '二哈2号', img: 'img/2.jpg', }, { title: '二哈3号', img: 'img/3.jpg', }, { title: '二哈4号', img: 'img/4.jpg', }, ]; let tag = { // 在组件内部就可以通过设置的自定义属性,拿到外部选择子组件提供给属性的值 props: ['dog', 'a', 'b', 'z'], template: ` <div class="box"> <img :src="dog.img" alt=""> <p> <b> {{ dog.title }} </b> </p> <p @click="fn"> 锤它:<b>{{ num }}下</b> </p> </div> `, data () { return { num: 0, } }, methods: { fn() { this.num ++ } }, }; new Vue({ el: '#app', data: { dogs, }, components: { tag, } }); /** 总结 * 1.数据在父组件中产生 * 2.在父组件中渲染子组件,子组件绑定自定义属性,附上父组件中的数据 * 3.子组件自定义属性在子组件的props成员中进行声明(采用字符串发射机制) * 4.在子组件内部,就可以用props声明的属性(直接作为变量)来使用父组件中的数据 */ </script> </html>
因为这个dogs的数据是根组件的,要在子组件中被渲染出来,所以是父传子。
组件传参-子传父
<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <title>子传父</title> <style> ul { list-style: none; } .d-btn { font-size: 12px; width: 15px; display: inline-block; } .d-btn:hover { color: red; cursor: pointer; } </style> </head> <body> <div id="app"> <input type="text" v-model="msg"> <button @click="send_comment">留言</button> <ul> <tag v-for="(v, i) in comments" :msg="v" :index="i" @f1="deleteMsg"/> </ul> </div> </body> <script src="js/vue.js"></script> <script> let tag = { props: ['msg', 'index'], template: ` <li> <i class="d-btn" @click="fn">x</i> <b>{{ msg }}</b> </li> `, methods: { fn () { // 点击子集,要告诉父级删除第几条数据,因为comments在父级中 // 需要通知父级 // 只要一执行到这句,就会马上通知父级,然后父级就会调用deleteMsg,同时接受你传过去的index this.$emit('f1', this.index); } } }; new Vue({ el: '#app', data: { msg: '', //因为空的数组反序列化会报错,所以要在这里加判断。 comments: localStorage.comments ? JSON.parse(localStorage.comments) : [], }, components: { tag, }, methods: { send_comment() { if (this.msg) { this.comments.push(this.msg); this.msg = ''; localStorage.comments = JSON.stringify(this.comments); } }, deleteMsg(index) { this.comments.splice(index, 1); localStorage.comments = JSON.stringify(this.comments); } } }) </script> <script> // localStorage,sessionStorage不能直接存储数组和对象,需要序列化为json localStorage.arr = JSON.stringify([1, 2, 3]); let res = JSON.parse(localStorage.arr); console.log(res, res[2]); </script> </html>
vue模板
<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <div id="app"> <h1> {{ title }} </h1> <!-- 组件标签不能添加系统事件,只能添加自定义事件,自定义事件在组件内部通过$emit主动触发 --> <tag @self_action="changeTitle"/> </div> </body> <script src="js/vue.js"></script> <script> let tag = { template: ` <div> <input v-model="sub_title" /> </div> `, data() { return { sub_title: '' } }, watch: { sub_title() { // 将sub_title与父级的title建立关联 // 激活(触发)self_action自定义事件 this.$emit('self_action', this.sub_title) } } }; new Vue({ el: '#app', components: { tag, }, data: { title: '父级初始标题' }, methods: { changeTitle(sub_title) { this.title = sub_title ? sub_title : '父级初始标题'; } } }) </script> </html>
简述以上
子组件
let tag = { template: `...`, data() { return { // 数据... } } } // 在哪个组件模板中出现的属性变量和方法变量,都由当前所属组件自己提供
父传子
<div id="app"> <tag :sub_msg="msg" /> </div> <script> let tag = { props: ['sub_msg'] template: `<div>{{ sub_msg }}</div>`, } new Vue({ el: '#app', components: { tag, }, data: { msg: '父级数据' } }) </script>
子传父(了解)
<div id="app"> <h1> {{ title }} </h1> <!-- 组件标签不能添加系统事件,只能添加自定义事件,自定义事件在组件内部通过$emit主动触发 --> <tag @self_action="changeTitle"/> </div> <script> let tag = { template: ` <div> <input v-model="sub_title" /> </div> `, data() { return { sub_title: '' } }, watch: { // 监听sub_title属性,值一改变就会触发 sub_title() { // 将sub_title与父级的title建立关联 // 激活(触发)self_action自定义事件 this.$emit('self_action', this.sub_title) } } }; new Vue({ el: '#app', components: { tag, }, data: { title: '父级初始标题' }, methods: { changeTitle(sub_title) { this.title = sub_title ? sub_title : '父级初始标题'; } } }) </script>