先介绍一下什么是组件把:
建立组件的两种方式:html
// 组件就是vue的一个拓展实例 let component=Vue.extend({ data(){ return{ //与vue实例中的data不一样,子组件的data必须是一个方法,必须有返回值,且返回值是对象。 //这样作可使组件中的数据独立。 //须要共享数据时可把return的对象声明全局变量 } } template:'<div></div>'// 模板 这个组件的html元素 // }) //注册组件 Vue.component('hehe',component)
(简写)vue
Vue.component('组件名',{ template:''// 模板 })
new Vue({ el:'#app', data:{ test:11 }, components:{ one:{ template:'<h1>这里是局部组件 </h1>' } } })
须要注意的是子组件的命名没法识别驼峰命名法,当组件作为标签使用的时候须要用“-”和小写字母替换该大写字母。vuex
<div> <one-data></one-data> </div> new Vue({ el:'#app', data:{ test:11 }, components:{ oneData:{ template:'<h1>这里是局部组件 </h1>' } } })
一、父子属性传值
子组件不能直接使用父级data的内容,也不能直接修改父组件传递的值,但能够经过设置props属性来得到自身属性值。
原理:npm
代码实现:(实现过程当中踩过的坑)
1.template标签内必须有且只有一个根元素
2.子组件标签内要经过v-bind的方式绑定父级的data的值
3.子组件经过props定义的自身属性值(test)获取父组件的data中的内容(父组件:{{name}} ;子组件:{{test}})app
<!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>
(全局组件无固定父子关系,该组件标签放在哪一个标签内就是哪一个标签的子组件)异步
<!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>
二、子父事件传值
子组件不能直接修改父组件传递的值,可间接经过事件修改函数
原理ui
代码实现:(点击子组件按钮,父组件div显示和隐藏)
代码中有一些思路注释:this
<!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>
三、非父子传值spa
原理
(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的相关配置步骤:
npm install vuex --save-dev
Vue.use(Vuex)
var store=new Vuex.Store({ state:{ }, mutations:{ }, actions:{ }, getters:{ } })
new Vue({ el: '#app', router, store, components: { App}, template: '<App/>', })
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