父组件能够将一条数据传递给子组件,这条数据能够是动态的,父组件的数据更改的时候,子组件接收的也会变化。前端
子组件被动的接收父组件的数据,子组件不要再更改这条数据了。vue
组件实例的做用域是孤立的,父组件不能直接使用子组件的数据,子组件也不能直接使用父组件的数据。
父组件在调用子组件的时候给子组件传递数据:vuex
<template id="father"> <div class="father"> <p>我是父组件,这是个人fMsg:{{fMsg}}</p> <input type = "text" v-model = "fMsg"> <hr> <son msg = "你好"></son> </div> </template>
父组件给子组件传递数据的时候,子组件须要利用props的属性来肯定本身的预期数据,若是儿子没有经过props属性接受传递过来的数据,则数据会以自定义属性的方式,放在儿子最外层的根元素上面。api
子组件经过props来接受父组件传递过来的数据,而且经过{{msg}}使用数组
components:{ son:{ template:"<div>我是son子组件!这是父组件传递给个人msg:{{msg}}</div>", //接收父组件传递来的属性 msg props:["msg"] } }
咱们能够用 v-bind 来动态地将 prop 绑定到父组件的数据。每当父组件的数据变化时,该变化也会传导给子组件。app
<template id="father"> <div class="father"> <p>我是父组件,这是个人fMsg:{{fMsg}}</p> <input type = "text" v-model = "fMsg"> <hr> <!-- <son msg = "你好"></son> --> <son :msg = "fMsg"></son> </div> </template>
若是若是父组件传递属性给子组件的时候键名有'-'dom
<son :f-msg = "fMsg"></son>
子组件接收、使用的时候写成小驼峰的模式函数
components:{ son:{ template:"<div>我是son子组件!这是父组件传递给个人msg:{{fMsg}}</div>", //接收父组件传递来的属性 msg props:["fMsg"] } }
咱们能够为组件的 prop 指定验证规则。若是传入的数据不符合要求,Vue 会发出警告。这对于开发给他人使用的组件很是有用
验证主要分为:类型验证、必传验证、默认值设置、自定义验证工具
// 类型验证 // num:Number //父组件传递过来的num必须是Number类型 // 添加多个类型 num: [Number,String],
规定传递过来的数值类型必须是number,不然系统会报错ui
规定父组件必须给子组件传递该值
//必传验证 // num:{ // required: true // }
当父组件不给子组件传递该值的时候,给子组件设定一个默认值
// 默认值设置 // num:{ // default:100 // }
//自定义验证 num:{ validator(val){ return val > 100 } }
规定传递过来的数值必需要大于100,不然系统会报错
单向数据流
Prop 是单向绑定的:当父组件的属性变化时,将传递给子组件,可是反过来不会。这是为了防止子组件无心间修改了父组件的状态,来避免应用的数据流变得难以理解。
<template id="father"> <div class="father"> <input type = "text" v-model = "message"> <hr> <son :message = "message"></son> </div> </template> <template id = "son"> <div> <p>这是子组件</p> <input type = "text" v-model = "message"></input> </div> </template>
另外,每次父组件更新时,子组件的全部 prop 都会更新为最新值。这意味着你不该该在子组件内部改变 prop。若是你这么作了,Vue 会在控制台给出警告。
因此若是咱们想实现父子间的数据共享,依靠的就是应用类型的地址传递,应将message写成对象的形式,传递的时候将对象传递给子组件,子组件引用的时候使用对象的value值。
<template id="father"> <div class="father"> <input type = "text" v-model = "message.value"> <hr> <!-- 传递的时候将对象传递给子组件 --> <son :message = "message"></son> </div> </template> <template id = "son"> <div> <p>这是子组件</p> <!-- 引用的时候使用对象的value值 --> <input type = "text" v-model = "message.value"></input> </div> </template>
这时候更改父组件的value值,子组件的数据同步更改,子组件修改value值的时候也同步修改了父组件的数据。这是由于不论是子组件仍是父组件,咱们操做的都是同一个对象,父组件直接把引用类型的地址传递给子组件,子组件没有直接修改对象,只是更改了里面的属性值。
父组件若是将一个引用类型的动态数据传递给子组件的时候,数据会变成双向控制的,子组件改数据的时候父组件也能接收到数据变化,由于子组件改的时候不是在改数据(地址),而是在改数据里的内容,也就是说引用类型数据的地址始终没有变化,不算改父组件数据。
注意:在 JavaScript 中对象和数组是引用类型,指向同一个内存空间,若是 prop 是一个对象或数组,在子组件内部改变它会影响父组件的状态。 message:{val:""}
$父子间数据共享(双向控制),基本不会使用,违背了单向数据流(父=》子)$
在组件间能够用过ref造成ref链,组件还拥有一个关系链($parent),经过这两种链;理论来讲,任意的两个组件均可以互相访问,互相进行通讯。
$parent:父组件
$children:子组件
$root:根组件
当子组件在set方法中修改父组件传递过来的值时,系统会报错,由于子组件不能修改父组件的数据。
Vue.component("bbb",{ template:"#bbb", props:["msg"], computed:{ /* ownMessage(){ return this.msg; } */ ownMessage:{ get(){ return this.msg; }, set(val){ this.msg = val //系统报错:子组件不能更改父组件传递的数据 } } } })
因此这时候要使用$parent,让父组件本身更改本身的数据
set(val){ // this.msg = val //系统报错:子组件不能更改父组件传递的数据 // console.log(this) // 至关于父组件本身更改了msg数据 this.$parent.msg = val; }
父组件在调用子组件的时候使用ref作标记
<template id="aaa"> <div> <button @click = "get">点击获取bbb数据</button> <!-- 组件间不只能够用过$root/$parent/$children来获取对应关系的组件,父组件还能够主动的经过ref为子组件作标记 --> <bbb ref = "b"></bbb> </div> </template>
父组件的this属性上有$refs标记,经过refs标记拿到子组件
// 经过ref标记更改子组件的数据 // this.$refs.b.message = "哈哈"
组件间不只能够用过$parent/children/root来获取对应关系的组件,父组件还能够主动的经过ref为子组件作标记 也能够给dom作标记,也会造成ref链,也能够交互.
<button ref="btn" @click="get">get</button> <bbb ref="b></bbb>
注意多个子组件标记的是同一个键名,获取到的应该是一个数组
<bbb ref = "b" v-for = "(item,index) in 3" :key = "index"></bbb>
// 经过下标修改对应的数值 this.$refs.b[0].message = "哈哈"
运行效果:
父组件能够将更改自身数据的方法传递给子组件,子组件调用这个方法的时候,就能够给父组件传递数据,父组件被动的接收子组件的数据。
子组件声明一条自身的msg
Vue.component("son",{ template:"#son", // 子组件接收父组件传递过来的方法 props:["change"], data(){ return{ msg:"我是子组件" } } })
父组件先声明一条本身的数据
data(){ return{ // 父组件先声明一条本身的数据 parentMsg:"" } }
再写一个能够更改自身数据的方法
methods:{ // 写一个能够更改自身数据的方法 change(msg){ this.parentMsg = msg } }
将写好的change方法传递给子组件
<template id="father"> <div> <p>这是父组件</p> <p>子组件传递过来的值是:{{parentMsg}}</p> <hr> <!-- 调用子组件的时候,将更改自身数据的方法传递给子组件 --> <son :change = "change"></son> </div> </template>
子组件经过props接收父组件传递过来的change方法
props:["change"]
给p标签添加点击事件,点击即触发change方法,同时将自身的msg传递给父组件,至关于父组件的change方法被执行。
<template id="son"> <div> <p>子组件说:{{msg}}</p> <p @click = "change(msg)">点击我触发父亲的change方法</p> </div> </template>
父组件能够在页面中渲染子组件传递过来的数据
<p>子组件传递过来的值是:{{parentMsg}}</p>
运行效果:
每个组件或者实例都会有自定义事件,和触发事件的能力,父组件给子组件绑定一个自定义事件,这个事件的处理程序倒是父组件的一个方法,当子组件触发这个事件的时候,至关于父组件的方法被执行。
父组件想获取子组件的数据时,在调用子组件的时候给子组件绑定一个自定义事件change-event
<template id="father"> <div> <p>这是父组件</p> <p>子组件传递过来的值是:{{parentMsg}}</p> <hr> <!-- 给子组件绑定一个自定义事件 --> <son @change-event = "change"></son> </div> </template>
在子组件中定义一个点击事件,点击p标签执行changeWord方法
<p @click = "changeWord">点击我触发父亲的change方法</p>
在方法中编写changeWord方法,经过this.$emit来触发绑定在本身身上的自定义事件,第一个参数为事件名称change-event,第二个参数为触发这个函数的时候给他传递的数值:自身的msg。
methods:{ changeWord(){ //触发自身绑定的change事件 this.$emit("change-event",this.msg)//第一个参数为触发事件的名字,第二个参数为触发这个函数的时候给他传递的数值 } }
一旦触发绑定在自身上的自定义事件,至关于父组件的change方法被执行。
定义哥哥组件,给哥哥组件添加一个点击事件,点击触发hitLittle方法
<template id = "big-brother"> <div> <p>我是哥哥</p> <button @click = "hitLittle">打弟弟</button> </div> </template>
定义弟弟组件,给弟弟组件添加一个p标签,由crying数据控制其显示与隐藏
<template id="little-brother"> <div> <p>我是弟弟</p> <p v-if = "crying">呜呜呜</p> </div> </template>
在弟弟组件的data中声明crying数据,默认为false
Vue.component("little-brother",{ template:"#little-brother", data(){ return{ crying:false } } })
在哥哥组件的methods中定义hitLittle方法,经过viewmodel关系链更改弟弟组件中的crying方法
Vue.component("big-brother",{ template:"#big-brother", methods:{ hitLittle(){ //在兄弟组件之间的通讯,能够采用关系链和ref链去使用,解决兄弟之间通讯问题。 this.$parent.$children[1].crying = true;//让littel改变自身的crying状态 } } })
运行效果:
在弟弟组件中添加ref标记
<little-brother ref = "little"></little-brother>
在哥哥组件的hitLittle方法中经过viewmodel和ref链配合使用更改弟弟组件中的crying数据
hitLittle(){ //在兄弟组件之间的通讯,能够采用关系链和ref链去使用,解决兄弟之间通讯问题。 // this.$parent.$children[1].crying = true;//让littel改变自身的crying状态 //viewmodel链和ref链配合使用 this.$parent.$refs.little.crying = true; }
建立一个空的实例
var angle = new Vue();
弟弟组件本身定义一个更改自身状态的方法
methods:{ cry(){ this.crying = true } }
在mounted生命周期函数中绑定一个自定义事件,第一个参数为自定义事件名,第二个函数为须要处理的函数
mounted(){ // 绑定一个自定义事件,第一个参数为自定义事件名,第二个函数为须要处理的函数 angle.$on("hit-little",this.cry) }
在哥哥组件中触发自定义事件
hitLittle(){ //触发little-brother组件的hit-little事件 angle.$emit("hit-little") }
vuex是vue提供的一个全局的状态管理工具,主要处理项目中多组件间状态共享。
Vuex是vue官方的一款状态管理工具,什么是状态呢?咱们在前端开发中有一个概念:数据驱动,页面中任意的显示不一样,都应该有一条数据来控制,而这条数据又叫作state,状态。
在vue中。组件间进行数据传递、通讯很频繁,而父子组件和非父子组件的通讯功能也比较完善,可是,惟一困难的就是多组件间的数据共享,这个问题由vuex来处理
(1)建立store
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex)
(2)设置state
state就是一个纯对象,上面有一些状态挂载
state: { num:0, name:"list" }
(3)在根实例里配置store
这样,咱们就能够在任意的组件中经过this.$store来使用关于store的api
import store from './store/index' Vue.config.productionTip = false new Vue({ router, store, render: h => h(App) }).$mount('#app')
(4)在Home组件中使用state
computed:{ ...mapState({ num:state=>state.num }) },
(5)使用mutations更改state
mutations也是一个纯对象,里面包含不少更改state 的方法,这些方法的形参接收到state,在函数体里更改,这时,组件用到的数据也会更改,实现响应式。
mutations: { changeNum(state){ state.num++ } }
(6)在组件中调用mutations方法,更改组件中的state。
//使用vuex提供的mapMutations帮助咱们在组件中调用mutations方法 ...mapMutations(["changeNum"]), //给按钮添加点击事件 <button @click = "changeNum">点击更改num值</button>
运行效果: