Vue组件通信(传值)

vue

先介绍一下什么是组件把:

创建组件的两种方式:

  • 全局组件

// 组件就是vue的一个拓展实例

let component=Vue.extend({

data(){

return{

//与vue实例中的data不同,子组件的data必须是一个方法,必须有返回值,且返回值是对象。

//这样做可以使组件中的数据独立。

//需要共享数据时可把return的对象声明全局变量

}

}

template:'<div></div>'// 模板 这个组件的html元素

// })

//注册组件

Vue.component('hehe',component)

(简写)

Vue.component('组件名',{

template:''// 模板

})

  • 局部组件

new Vue({

el:'#app',

data:{

test:11

},

components:{

one:{

template:'<h1>这里是局部组件 </h1>'

}

}

})

需要注意的是子组件的命名无法识别驼峰命名法,当组件做为标签使用的时候需要用“-”和小写字母替换该大写字母。

<div>

<one-data></one-data>

</div>

new Vue({

el:'#app',

data:{

test:11

},

components:{

oneData:{

template:'<h1>这里是局部组件 </h1>'

}

}

})

1、父子属性传值

子组件不能直接使用父级data的内容,也不能直接修改父组件传递的值,但可以通过设置props属性来获得自身属性值。
原理:

  • 通过子组件的props抛出一个组件标签属性
  • 父组件通过该标签属性将参数传递给子组件
  • 子组件内部通过该标签属性获取值

代码实现:(实现过程中踩过的坑)

1.template标签内必须有且只有一个根元素

2.子组件标签内要通过v-bind的方式绑定父级的data的值

3.子组件通过props定义的自身属性值(test)获取父组件的data中的内容(父组件:{{name}} ;子组件:{{test}})

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="UTF-8">

<meta name="viewport" content="width=device-width, initial-scale=1.0">

<meta http-equiv="X-UA-Compatible" content="ie=edge">

<title>Document</title>

<script src="base/vue.js"></script>

</head>

<body>

<div>

{{name}}

<son :test='name'></son>

</div>

<!--实现功能较复杂时,会单独写个template标签,通过id与子组件中的template相关联,否则字符串拼接会很麻烦-->

<template>

<div>{{test}}</div>

</template>

</body>

<script>

new Vue({

el:'#myApp',

data:{

name:'加油鸭!'

},

components:{

son:{

template:'#tp',//类似于 el

props:['test']

}

}

})

</script>

</html>

  • 再用全局组件写一个父子属性传值,实现点击父组件按钮,子组件div显示和隐藏

(全局组件无固定父子关系,该组件标签放在哪个标签内就是哪个标签的子组件)

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="UTF-8">

<meta name="viewport" content="width=device-width, initial-scale=1.0">

<meta http-equiv="X-UA-Compatible" content="ie=edge">

<title>父向子传值</title>

<script src="base/vue.js"></script>

</head>

<body>

<div>

<!--c1就是myApp的子组件-->

<c1></c1>

</div>

<template>

<div>

<h4>我是c1,是父级</h4>

<button @click="change">点我c2变</button>

{{state}}

<hr>

<!--写在c1的template内,就是c1的子组件-->

<c2 :changed='state'></c2>

</div>

</template>

<template>

<div>

我是c2,是子级

<div v-show='changed'><h1>我是div</h1></div>

</div>

</template>

</body>

<script>

Vue.component("c1",{

template:'#tp1',

data(){

return {

state:true

}

},

methods:{

change(){

this.state=!this.state

}

}

})

Vue.component("c2",{

template:'#tp2',

props:['changed']

})

let vm=new Vue({

el:'#myApp'

})

</script>

</html>

2、子父事件传值

子组件不能直接修改父组件传递的值,可间接通过事件修改

原理

  • 子组件创建自定义事件
  • 自定义事件的处理函数是父组件的函数
  • 子组件通过$emit触发属于自己的自定义事件

代码实现:(点击子组件按钮,父组件div显示和隐藏)

代码中有一些思路注释:

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="UTF-8">

<meta name="viewport" content="width=device-width, initial-scale=1.0">

<meta http-equiv="X-UA-Compatible" content="ie=edge">

<title>子向父传值</title>

<script src="base/vue.js"></script>

</head>

<body>

<div>

<c1></c1>

</div>

<template>

<div>

<h4>我是c1,是父级</h4>

<div v-show='state'><h1>我是div</h1></div>

<hr>

<!--c2自定义了一个changed事件处理父组件的函数change-->

<c2 @changed='change'></c2>

</div>

</template>

<template>

<div>

我是c2,是子级

<!--子组件点击按钮,父组件显示隐藏,当然有点击事件啦,

所以给button加点击事件触发一个函数,发现c2没有设置methods,

所以去c2的实例中加一个methods并设置函数sclick,

再通过sclick函数把其自定义事件changed抛出,

changed里面就是c1的处理函数-->

<button @click="sclick">点我c1变</button>

</div>

</template>

</body>

<script>

Vue.component("c1",{

template:'#tp1',

data(){

return {

state:true

}

},

methods:{

change(){

this.state=!this.state

}

}

})

Vue.component("c2",{

template:'#tp2',

methods:{

sclick(){

this.$emit('changed')

}

}

})

let vm=new Vue({

el:'#myApp'

})

</script>

</html>

3、非父子传值

原理

  • 创建公共汽车实例
  • 实例上注册事件,事件的处理函数就是要改变数据的处理函数
  • 触发事件

(1)公有的父元素作为桥接-----结合父子属性传值和子父事件传值来实现(适用于亲兄弟)

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="UTF-8">

<meta name="viewport" content="width=device-width, initial-scale=1.0">

<meta http-equiv="X-UA-Compatible" content="ie=edge">

<title>兄弟传值</title>

<script src="base/vue.js"></script>

</head>

<body>

<div>

我是父级

{{state}}

<hr>

<!--c1和c2都是div的子组件-->

<!--子父事件传值-->

<c1 @emit='change'></c1>

<hr>

<!--父子属性传值-->

<c2 :test='state'></c2>

</div>

<template>

<div>

我是c1,是c2的兄弟

<!--间接通过父级改变了兄弟级的值-->

<button @click='emit'>点我我的兄弟和父级都会发生改变</button>

</div>

</template>

<template>

<div>我是c2,是c1的兄弟

<p>{{test}}</p>

</div>

</template>

</body>

<script>

Vue.component('c1',{

template:'#tp1',

methods:{

emit(){

this.$emit('emit')

}

}

})

Vue.component('c2',{

template:'#tp2',

props:["test"]

})

new Vue({

el:'#myApp',

data:{

state:false

},

methods:{

change(){

this.state=!this.state

}

}

})

</script>

</html>

(2)公共汽车传值(声明一个公共实例作为过滤)

修改谁的值就去触发谁的方法

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="UTF-8">

<meta name="viewport" content="width=device-width, initial-scale=1.0">

<meta http-equiv="X-UA-Compatible" content="ie=edge">

<title>兄弟之间通过公共汽车传值</title>

<script src="base/vue.js"></script>

</head>

<body>

<div>

<father></father>

</div>

<template>

<div>我是父组件

<hr>

<son1></son1>

<hr>

<son2></son2>

</div>

</template>

<template>

<div>{{name}}

<!--点击事件触发一下sclick函数,相当于把抛出的change函数触发了-->

<button @click='sclick'>点我</button>

</div>

</template>

<template>

<div>{{name}}</div>

</template>

</body>

<script>

let Bus=new Vue();

new Vue({

el:'#myApp',

components:{

father:{

template:'#father',

components:{

son1:{

template:'#son1',

data(){

return{

name:'我是子组件1'

}

},

methods:{

sclick(){

//触发test事件,再传一个参数給change函数中的val

//name值就从“我是子组件2”通过点击事件变成了"加油鸭!!!!"

Bus.$emit('test',"加油鸭!!!!")

}

}

},

son2:{

template:'#son2',

data(){

return{

name:'我是子组件2'

}

},

methods:{

change(val){

this.name=val

}

},

mounted(){

//只要mounted执行了,说明组件已经准备就绪

//注册一个函数,函数名叫test,处理函数就是methods中的change函数

//简单来说,只要想办法触发test事件就相当于执行了change函数

Bus.$on('test',this.change)

}

}

}

}

}

})

</script>

</html>

(3)vuex(集中式的数据状态管理器)

简单来说,就是用来管理全局变量的,不管哪里进行修改,页面都会随之变化。比如我们手机端的选择所在区域,假设你选了北京,跳到其他页面还是显示的北京就可以用vuex来实现。

解决的问题:

帮助我们管理共享状态。

vuex的相关配置步骤:

  1. npm install vuex --save-dev
  2. 引入:`import Vuex from ‘vuex’
  3. 使用:Vue.use(Vuex)

  4. 设置vuex

var store=new Vuex.Store({

state:{

},

mutations:{

},

actions:{

},

getters:{

}

})

  1. 将数据放入到实例中

new Vue({

el: '#app',

router,

store,

components: { App},

template: '<App/>',

})

vuex中的模块:

  1. state:存储状态,可通过this.$store.state获取我们在vuex中声明的全局变量的值

import Vuex from 'vuex'

Vue.use(Vuex)

let store=new Vuex.Store({

state:{

name:1,

}

})

export default store;

//一般我们会新建一个store文件夹,

//在该文件夹的js文件中通过暴露出store,

//再通过在main.js中引入该文件的方式来使用vuex

在组件中我们只需要通过{{this.$store.state.name}}就可以渲染name的值

写一个组件:

<template>

<div>

{{msg}}

{{this.$store.state.name}}

<hr>

</div>

</template>

<script>

export default {

name:'List',

data(){

return {

msg:'list',

}

}

}

</script>

<style>

#list div{

width: 50px;

height: 50px;

background: red;

}

</style>


有木有觉得{{this.$store.state.name}}太长了,可不可以直接写{{name}}:

<template>

<div>

{{msg}}

{{name}}

<hr>

</div>

</template>

<script>

export default {

name:'List',

data(){

return {

msg:'list',

}

},

computed:{

name(){

return this.$store.state.name

}

}

}

</script>

<style>

#list div{

width: 50px;

height: 50px;

background: red;

}

</style>

有小伙伴会说了,这样也不简单呀,那这样呢?

<template>

<div>

{{msg}}

{{name}}

<hr>

</div>

</template>

<script>

import {mapState} from 'vuex'

export default {

name:'List',

data(){

return {

msg:'list',

}

},

//可不可以不用拓展操作符?可以呀

//computed:mapState(['name'])

//可是这样你如果还有其他的方法要在computed中操作就没法操作了

computed:{

...mapState(['name'])

}

}

</script>

<style>

#list div{

width: 50px;

height: 50px;

background: red;

}

</style>

如果遇到需要改名的情况,可通过对象的形式:

{{_name}} //改后的名字进行页面渲染

...mapState({_name:"name"})

后面的方法基本思路一样,接下来就都用简写形式啦!

2. mutations:修改状态

import Vuex from 'vuex'

Vue.use(Vuex)

let store=new Vuex.Store({

state:{

name:1,

},

mutations:{

CHANGE_NUM(state,name){

state.name=name

}

},

})

export default store;

我们来做一个小效果,点击按钮改变状态值从1变为888

<template>

<div>

<div @click='CHANGE_NUM(888)'>change</div>

{{msg}}

{{_name}}

<hr>

</div>

</template>

<script>

import {mapState,mapMutations} from 'vuex'

export default {

name:'List',

data(){

return {

msg:'list',

}

},

methods:{

//非简写形式,点击事件的调用方法换为getName

//getName(){

// this.$store.commit('CHANGE_NUM',888)

// }

...mapMutations(['CHANGE_NUM']),

},

computed:{

...mapState({_name:'name'})

}

}

</script>

<style>

#list div{

width: 50px;

height: 50px;

background: red;

}

</style>



3. actions:专门用来做异步操作

通过计时器模拟一个异步操作,并通过commit触发mutations

import Vuex from 'vuex'

Vue.use(Vuex)

let store=new Vuex.Store({

state:{

name:1,

},

mutations:{

CHANGE_NUM(state,name){

state.name=name

}

},

actions:{

//逻辑处理及异步请求

getNumApi({commit},params){

setTimeout(()=>{

commit('CHANGE_NUM',params)

},2000)

}

}

})

export default store;

再来实现一个点击按钮改变值的效果:

<template>

<div>

<div @click='getNumApi("xixi")'>change</div>

{{msg}}

{{_name}}

<hr>

</div>

</template>

<script>

import {mapState,mapActions} from 'vuex'

export default {

name:'List',

data(){

return {

msg:'list',

}

},

methods:{

//非简写的写法:(通过dispatch触发相应的action)

//emitActions(params){

// this.$store.dispatch('getNumApi',params)

// }

...mapActions(['getNumApi'])

},

computed:{

...mapState({_name:'name'})

}

}

</script>

<style>

#list div{

width: 50px;

height: 50px;

background: red;

}

</style>

2秒后name值改变了

4. getters:类似于计算属性computed,里面进行一些计算操作

import Vue from 'vue'

import Vuex from 'vuex'

Vue.use(Vuex)

let store=new Vuex.Store({

state:{

name:1

},

mutations:{

CHANGE_NUM(state,name){

state.name=name

}

},

getters:{

double(state){

return state.name*2

}

},

actions:{

//逻辑处理及异步请求

getNumApi({commit},params){

setTimeout(()=>{

commit('CHANGE_NUM',params)

},2000)

}

}

})

export default store;

再来做点击事件:

<template>

<div>

<div @click='getNumApi("xixi")'>change</div>

{{msg}}

{{_name}}

{{double}}

<hr>

</div>

</template>

<script>

import {mapState,mapMutations,mapActions,mapGetters} from 'vuex'

export default {

name:'List',

data(){

return {

msg:'list',

}

},

methods:{

...mapActions(['getNumApi'])

},

computed:{

...mapState({_name:'name'}),

...mapGetters(['double'])

}

}

</script>

<style>

#list div{

width: 50px;

height: 50px;

background: red;

}

</style>

由于字符串不能进行乘法操作,所以打印结果是NaN

5. modules:模块

在实际开发中,我们会把以上四个模块,分别写在四个js文件中,在通过引入、暴露的形式写在一个index.js文件下。

import actions from './actions'

import state from './state'

import mutations from './mutations'

import getters from './getters'

export default {

state,

mutations,

getters,

actions

}

再把这5个文件放在store文件夹下的shopcar文件夹下(名字随意),在再store文件夹下,新建一个index.js文件,并通过modules的形式展现:

import Vue from 'vue'

import Vuex from 'vuex'

Vue.use(Vuex)

import shopcar from './shopcar'

let store=new Vuex.Store({

modules:{

shopcar:shopcar

}

})

export default store

来源:https://blog.csdn.net/weixin_43747906/article/details/84981199

以上是 Vue组件通信(传值) 的全部内容, 来源链接: utcz.com/z/379127.html

回到顶部