1. props/$emit:
父组件A通过props向子组件B传数据,B向A传递数据通过在B中$emit触发A中的自定义事件,在B中v-on监听。
适用场景:父子通信。
代码实例: Parent.vue:
<template>
<div>
Parent
<h2>{{name}}</h2>
<children :name="name" v-on:ChildrenToParent="func1"></children>
</div>
</template>
<script>
import Children from './Children'
export default {
name: 'Parent',
components: {
Children
},
data () {
return {
name: 'Lily'
}
},
methods: {
func1 (name, age) {
this.name = name
console.log('父组件', name, age)
}
}
}
</script>
Children.vue:
<template>
<div>
Children
<button @click="btnClick1">打印父传到子的数据</button>
<button @click="btnClick2">子向父传数据</button>
</div>
</template>
<script>
export default {
name: 'Children',
props: {
name: String
},
methods: {
btnClick1 () {
console.log('子组件', this.name)
},
btnClick2 () {
this.$emit('ChildrenToParent', 'yue', 12)
}
}
}
</script>
2. $emit/$on:
通过一个空的Vue实例作为中央事件总线,用它来触发和监听事件,要通信的组件共用同一个事件机制。传递数据用emit,接受数据方用on。
适用场景:父子,兄弟,跨级通信。
代码实例:组件BrotherC接受兄弟组件BrotherA和兄弟组件BrotherB传递的数据。 emptyVue.js:
import Vue from "vue"
export default new Vue()
BrotherA.vue:
<template>
<div>
<button @click="send">按下按钮,A向C传数据</button>
</div>
</template>
<script>
import emptyVue from '../../util/emptyVue.js'
export default {
name: 'BrotherA',
data () {
return {
name: 'A组件'
}
},
methods: {
send () {
emptyVue.$emit('data-a', this.name)
}
}
}
</script>
BrotherB.vue:
<template>
<div>
<button @click="send">按下按钮,B向C传数据</button>
</div>
</template>
<script>
import emptyVue from '../../util/emptyVue.js'
export default {
name: 'BrotherB',
data () {
return {
name: 'B组件'
}
},
methods: {
send () {
emptyVue.$emit('data-b', this.name)
}
}
}
</script>
BrotherC.vue:
<template>
<div>
</div>
</template>
<script>
import emptyVue from '../../util/emptyVue.js'
export default {
name: 'BrotherC',
mounted () {
emptyVue.$on('data-a', (data) => {
console.log('C接收到A的数据:', data)
})
emptyVue.$on('data-b', (data) => {
console.log('C接收到B的数据:', data)
})
}
}
</script>
App.vue:
<template>
<div id="app">
<brother-a></brother-a>
<brother-b></brother-b>
<brother-c></brother-c>
</div>
</template>
<script>
import BrotherA from '@/components/emit和on/BrotherA'
import BrotherB from '@/components/emit和on/BrotherB'
import BrotherC from '@/components/emit和on/BrotherC'
export default {
name: 'App',
components:{
BrotherA,
BrotherB,
BrotherC
}
}
</script>
3.$attrs/$listeners
$attrs:包含父作用域中的不被认为是props的属性(class和style不为props属性),可以通过v-bind=’$attrs"传入其内部组件。 $listeners:包含父组件作用域中的(不包含.native修饰)v-on事件监听器,可以通过v-on="$listeners"传入内部组件,相当于子组件继承了父组件的事件。
适用场景:父子,跨级通信。组件嵌套层级深的不必用props,项目较小的不必用vuex,此时可以用$attrs/$listeners。
例子: Father.vue:
<template>
<div>
<son name="Lilt" age="12" @func1="func1" @func2="func2" class="id1"></son>
</div>
</template>
<script>
import Son from './Son'
export default {
name: 'Father',
components: {
Son
},
methods: {
func1 () {
console.log('执行func1')
},
func2 () {
console.log('执行func2')
}
}
}
</script>
Son.vue:
<template>
<div>
<grand-son height="1.7" weight="11" @func3="func3" v-bind='$attrs' v-on="$listeners"></grand-son>
</div>
</template>
<script>
import GrandSon from './GrandSon'
export default {
name: 'Son',
components: {
GrandSon
},
props: ['name'],
methods: {
func3 () {
console.log('执行func3')
}
},
created () {
console.log('Son', this.$attrs, this.$listeners)
}
}
</script>
GrandSon.vue:
<template>
<div></div>
</template>
<script>
export default {
name: 'GrandSon',
props: ['height'],
created () {
console.log('GrandSon', this.$attrs, this.$listeners)
this.$emit('func1')
}
}
</script>
4. $parent/$children/ref:
$parent/$children:访问父子实例。 ref:用在普通DOM元素,引用当前的DOM元素;用在子组件上,引用指向组件实例。 这三种都是直接得到组件实例,使用后可以直接调用组件的方法和数据。
适用场景:父子通信。
例如: Parent.vue:
<template>
<div>
<children ref="ref1"></children>
<button @click="btnClick">按钮</button>
</div>
</template>
<script>
import Children from './Children'
export default {
name: 'Parent',
components: {
Children
},
methods: {
btnClick () {
const ref1 = this.$refs.ref1
console.log(ref1.name)
ref1.func1()
console.log('this.$children', this.$children)
}
}
}
</script>
Children.vue:
<template>
<div>
Children
</div>
</template>
<script>
export default {
name: 'Children',
data () {
return {
name: 'Lily'
}
},
methods: {
func1 () {
console.log('执行func1')
console.log('this.$parent:', this.$parent)
}
}
}
</script>
5. provide和inject
祖先组件通过provider来提供变量,然后在子孙组件中通过inject来注入变量,非响应式。
适用场景:父子,跨级通信。
例如: Parent.vue:
<template>
<son></son>
</template>
<script>
import Son from './Son'
export default {
name: 'Parent',
components: {
Son
},
provide () {
return {
msg: '玛卡巴卡'
}
}
}
</script>
Son.vue:
<template>
<grand-son></grand-son>
</template>
<script>
import GrandSon from './GrandSon'
export default {
name: 'Son',
components: {
GrandSon
}
}
</script>
GrandSon.vue:
<template>
<div>
这是GrandSon
</div>
</template>
<script>
export default {
name: 'GrandSon',
inject: ['msg'],
mounted () {
console.log('GrandSon接收到来自Parent的msg:', this.msg)
}
}
</script>
6. vuex
vuex提出单一状态树的概念,如果我们的状态信息是保存到多个Store对象中的,那么之后的管理和维护等等都会变得特别困难,所以vuex推荐单一状态树来管理应用层级的全部状态,即只有一个Store实例。
在全局用一个State存放数据,当使用vuex数据的组件需要修改某些共享数据时,要通过Mutations来修改。(虽然Vue Components直接操作Vuex的State也是可以的,都是所有组件都这么直接改,出了bug不太容易定位到是哪个组件修改的。Devtools是一个浏览器插件,可以帮助我们记录那个组件修改的State,当前提是通过Mutations修改数据的)。 这里附上官网的vuex流程图: 异步操作时必须从经过Actions。
适用场景:均可。
代码实例: store/index.js:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
counter: 1000
},
mutations: {
additon (state) {
state.counter++
},
subtraction (state) {
state.counter--
}
}
})
export default store
TestCpn.vue:
<template>
<div>
<h2>{{$store.state.counter}}</h2>
<!-- <button @click="$store.state.counter++">按钮</button> -->
<button @click="add">+1</button>
<button @click="sub">-1</button>
</div>
</template>
<script>
export default {
methods: {
add () {
this.$store.commit('additon')
},
sub () {
this.$store.commit('subtraction')
}
}
}
</script>
main.js
import Vue from 'vue'
import App from './App'
import router from './router'
import store from './store'
Vue.config.productionTip = false
new Vue({
el: '#app',
router,
store,
components: { App },
template: '<App/>'
})
|