功能:任意组件间通信【父子 子父 爷孙 。。。 兄弟。。。】
1.School组件本质是一个名为VueComponent的构造函数,且不是程序员定义的,Vue.extend生成的。
2、我们只需要写` `或` `,Vue解析时公帮我们创建school组件的实例对象,即Vue帮我们执行的:new VueComponent(options)。
3、特别注意:每次调用Vue.extend,返回的都是一个全新的VueComponent !!!!
4、关于this指向:
(1) 组件配置中:
data函数、methods中的函数、watch中的函数、computed中的函数、它们的this均是【vuecomponent实例对象】
(2) new Vue(options)配置中:
data函数、methods中的函数、watch中的函数、computed中的函数它们的this均是【Vue实例对象】。
5.VueComponent的实例对象,以后简称vc(也可称之为:组件实例对象);Vue的实例对象,以后简称vm。
$on $off $emit 都可以使用 备注:$on $off $emit 都在Vue的原型对象中
import App from './App'
import Vue from 'vue'
Vue.config.productionTip = false
new Vue({
el: '#single',
render: h => h(App),
beforeCreate() {
// 所有组件可见 - 安装全局事件总线
Vue.prototype.$bus = this
}
})
App.vue
<template>
<div class="app">
<h1>{{ msg }}</h1>
<School/>
<Student/>
</div>
</template>
<script>
import School from "./components/School"
import Student from './components/Student'
export default {
name: "App",
components: {Student, School},
data() {
return {
msg: 'Hello-',
}
},
methods: {
},
mounted() {
},
}
</script>
<style scoped>
.app {
background-color: gray;
}
</style>
School.vue
<template>
<div class="sc">
<h2>学校名称:{{ name }}</h2>
<h2>学校地址:{{ address }}</h2>
</div>
</template>
<script>
export default {
name: `School`,
data() {
return {
name: '北京大学',
address: '北京'
}
},
methods: {},
mounted() {
this.$bus.$on('hello', (data) => {
console.log('i am school component, rev data', data)
})
},
// 销毁
beforeDestroy() {
this.$bus.$off('hello')
}
}
</script>
<style>
.sc {
background-color: aquamarine;
padding: 5px;
}
</style>
Student.vue
<template>
<div class="student">
<h2>学生名字:{{ name }}</h2>
<h2>学生性别:{{ sex }}</h2>
<button @click="sendStudentName">把学生名给school组件</button>
</div>
</template>
<script>
export default {
name: `Student`,
data() {
return {
name: 'zhaoshuai-lc',
sex: 'male'
}
},
methods: {
sendStudentName() {
this.$bus.$emit('hello', this.name)
}
}
}
</script>
<style>
.student {
background-color: pink;
padding: 5px;
}
</style>
1)对以下代码的理解:
const Demo = Vue.extend({})
const d = new Demo()
Vue.prototype.x = d
因为需要写了标签才能使用组件,然而不能在main.js中引用标签,所以这一行亲自new一个。
2)对以下代码的理解:
new Vue({
......
beforeCreate() {
Vue.prototype.$bus = this //安装全局事件总线
}
})
3)为什么bus需要销毁,自定义事件不用销毁?
举个例子,比如说Student组件被销毁了,那么整个vc都没有了,所以自定义事件就直接没有了。
但是bus不是这样的,就算Student组件被销毁了,bus也会一直在,所以bus用完了最好要销毁。
父亲给子传值【props的方式】
子给父亲传值【回调函数的方式】
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
new Vue({
// 将App组件放入容器中
render: h => h(App),
beforeCreate() {
Vue.prototype.$bus = this
}
}).$mount('#app')
<template>
<div class="todo-container">
<div class="todo-wrap">
<UserHeader @addTodo="addTodo"/>
<!-- <UserList :todoList="todoList" :checkTodo="checkTodo" :deleteTodo="deleteTodo"/>-->
<UserList :todoList="todoList"/>
<UserFooter :todoList="todoList" @checkAllTodo="checkAllTodo" @clearAllTodo="clearAllTodo"/>
</div>
</div>
</template>
<script>
import UserHeader from "@/components/UserHeader"
import UserFooter from "@/components/UserFooter"
import UserList from "@/components/UserList"
export default {
name: 'App',
data() {
return {
todoList: JSON.parse(localStorage.getItem('todoList')) || []
}
},
methods: {
addTodo(data) {
this.todoList.unshift(data)
},
checkTodo(id) {
this.todoList.forEach(todo => {
if (todo.id === id) {
todo.done = !todo.done
}
})
},
deleteTodo(id) {
this.todoList = this.todoList.filter(todo => {
return todo.id !== id
})
},
checkAllTodo(done) {
this.todoList.forEach(todo => {
todo.done = done
})
},
clearAllTodo() {
this.todoList = this.todoList.filter(todo => !todo.done)
}
},
watch: {
todoList: {
// 深度监视
deep: true,
handler(newValue, oldValue) {
localStorage.setItem('todoList', JSON.stringify(newValue))
}
},
},
components: {UserHeader, UserList, UserFooter},
mounted() {
this.$bus.$on('checkTodo', this.checkTodo)
this.$bus.$on('deleteTodo', this.deleteTodo)
},
beforeDestroy() {
this.$bus.$off('checkTodo')
this.$bus.$off('deleteTodo')
}
}
</script>
<style>
/* base */
body {
background-color: #fff;
}
.btn {
display: inline-block;
padding: 4px 12px;
margin-bottom: 0;
font-size: 14px;
line-height: 20px;
text-align: center;
vertical-align: middle;
cursor: pointer;
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
border-radius: 4px;
}
.btn-danger {
color: #fff;
background-color: #da4f49;
border: 1px solid #bd362f;
}
.btn-danger:hover {
color: #fff;
background-color: #bd362f;
}
.btn:focus {
outline: none;
}
.todo-container {
width: 600px;
margin: 0 auto;
}
.todo-container .todo-wrap {
padding: 10px;
border: 1px solid #ddd;
border-radius: 5px;
}
</style>
<template>
<ul class="todo-main">
<!-- <UserItem
v-for="todo in todoList"
:key="todo.id" :todo="todo"
:checkTodo="checkTodo"
:deleteTodo="deleteTodo"></UserItem>-->
<UserItem
v-for="todo in todoList"
:key="todo.id" :todo="todo"></UserItem>
</ul>
</template>
<script>
import UserItem from "@/components/UserItem";
export default {
name: `UserList`,
components: {UserItem},
data() {
return {}
},
// props: ['todoList', 'checkTodo', 'deleteTodo']
props: ['todoList']
}
</script>
<style scoped>
/* main */
.todo-main {
margin-left: 0px;
border: 1px solid #ddd;
border-radius: 2px;
padding: 0px;
}
.todo-empty {
height: 40px;
line-height: 40px;
border: 1px solid #ddd;
border-radius: 2px;
padding-left: 5px;
margin-top: 10px;
}
</style>
<template>
<li>
<label>
<!-- <input type="checkbox" :checked="todo.done" @click="handleCheck(todo.id)"/>-->
<input type="checkbox" :checked="todo.done" @change="handleCheck(todo.id)"/>
<span>{{ todo.title }}</span>
</label>
<button class="btn btn-danger" @click="handleDelete(todo.id)">删除</button>
</li>
</template>
<script>
export default {
name: `UserItem`,
// 声明接受todo
// props: ['todo', 'checkTodo', 'deleteTodo'],
props: ['todo'],
methods: {
handleCheck(id) {
// 通知App组件将对应的todo 的 done 取反
// this.checkTodo(id)
this.$bus.$emit('checkTodo', id)
},
handleDelete(id) {
if (confirm('确定删除吗?')) {
// this.deleteTodo(id)
this.$bus.$emit('deleteTodo', id)
}
}
}
}
</script>
<style scoped>
/* item */
li {
list-style: none;
height: 36px;
line-height: 36px;
padding: 0 5px;
border-bottom: 1px solid #ddd;
}
li label {
float: left;
cursor: pointer;
}
li label li input {
vertical-align: middle;
margin-right: 6px;
position: relative;
top: -1px;
}
li button {
float: right;
display: none;
margin-top: 3px;
}
li:before {
content: initial;
}
li:last-child {
border-bottom: none;
}
li:hover {
background-color: #ddd;
}
li:hover button {
display: block;
}
</style>