vue日记(六)(待续...)

vue笔记6

15.组件传值

  • 父组件向子组件传值:props

    • 父组件可以在调用子组件时,在标签上绑定属性,子组件在自身的props中注册该属性之后,就能将该属性作为数据使用。
    • 注意点:属性的用法和data中的数据用法一样,在子组件中只能使用该属性的值,不能进行修改(即使在子组件中修改了该属性的值,重新渲染时,依旧会被父组件传入的属性值重新覆盖),该属性名不要和data中的属性重名,否则会被data 中的属性覆盖。
    //父组件
    <template>
      <div id="app">
    	  <Box :title1="msg"></Box>
    	  <Box :title1="msg2"></Box>
    	  <Box3 :title="b3" :title2="b4" title3="父组件传的值" :title4="n"></Box3>
    	  <SinaBox  :data="arr[0]"></SinaBox>
      </div>
    </template>
    <script>
    import Box from "./Box.vue"
    import Box2 from "./Box2.vue"
    import Box3 from "./Box3.vue"
    export default {
    	data(){
    		return {
    			arr:[{text:"xxx",created:"123123"}],
    			msg:"父组件的数据",
    			msg2:"父组件的数据2",
    			b3:"100",//"hello",
    			b4:100,//"hello",
    			n:4//3//"hello66666"
    		}
    	},
       components:{
    	   Box,
    	   Box2,
    	   Box3
       }
      
    }
    </script>
    
    //子组件
    <template>
    	<div>
    		<h1>{{title}}--{{title2}}--{{title3}}--{{title4}}</h1>
    	</div>
    </template>
    
    <script>
    	export default {
    		//属性的类型验证
    		props:{
    			title:String,
    			title2:[String,Number],
    			title3:{
    				type:String,
    				default:"默认属性的值"
    			},
    			title4:{
    				validator:(v)=>{
    					return isNaN(v)?false:v%2==0
    				}
    			}
    		}
    	}
    </script>
    
    • props有简洁和详细两种写法:

      • props:[“msg1”,“msg2”];

      • props: {
        	propA: Number,		// 基础的类型检查 (`null` 匹配任何类型)
        	propB: [String, Number],	// 多个可能的类型
        	propC: {	
                type: String,
             	required: true	// 使用该子组件时propC为必传的属性,且类型为String
           	},
        	propD: {	
                	type: Number,
              		default: 100	// 带有默认值的数字
            	},
        	propE: {	
                type: Object,	// 带有默认值的对象
        		default: function () {	// 对象或数组默认值必须从一个工厂函数获取
                		return { message: 'hello' }
              		}
            	}
          }
        
  • 子组件向父组件传值:$emit

    • 在子组件中的生命周期或者方法中通过this.$emit("父组件的事件名fn1",传入父组件的参数)调用父组件中绑定的事件,传入参数,达到子组件向父组件传值的目的

    • 父组件中定义对应的方法:@父组件的事件名fn1="父组件自身的方法",父组件定义的方法中就可以接收到子组件传来的值

      //子组件
      <template>
      	<div>
      		<h1>box----{{n}}</h1>
      		<button @click="change1">box---修改</button>
      	</div>
      </template>
      <script>
      	export default {
      		props:["n"],
      		methods:{
      			change1(){
      				this.$emit("changebaba",this.n+1)
      			}
      			}
      		}
      </script>
      
      //父组件
      <template>
      	<div id="app">
      		<h1>app---{{count}}</h1>
      		<Box @changebaba="fn"  v-on:xx="eventmyself"  :n="count"></Box>
      		//changebaba是子组件的自定义方法,会通过this.$emit()调用
      		//fn是定义的父组件自身的方法
      		<button @click="change1">app--修改count</button>
      	</div>
      </template>
      <script>
      	import Box from "./Box.vue"
      	export default {
      		data() {
      			return {
      				count: 20
      			}
      		},
      		methods:{
      			change1(){
      				this.count+=1
      			},
      			fn(arg){
      				this.count=arg
      			}
      		},
      		components: {
      			Box
      		}
      	}
      </script>
      
  • 在父子组件上使用v-model双向绑定:

    • 在父组件中使用v-model="msg",绑定传入子组件的数据
    • 在子组件中注册value属性(只能是value属性),然后可以直接使用该属性
    • 本质上也是一个语法糖
    //父组件
    <template>
      <div id="app">
        <h1>app---{{count}}</h1>
          <Box v-model="count"></Box>     
      </div>
    </template>
    
    <script>
    import Box from './Box.vue'
    export default { 
      data(){
        return {
          count:20
        }
      },
      components: {
        Box
      },
      methods:{
          input1(v){
            console.log(v);
             this.count=v;
          },   
      },
    }
    </script>
    
    //子组件
    <template>
      <div >
        <h1>box---{{value}}</h1>
        <button type="button" @click='fn'>修改父组件</button>
      </div>
    </template>
    
    <script>
    
    export default {
      props:['value'],
        methods:{
            fn(){
            
                this.$emit('input',this.value+1)
            }
        }
    
    }
    </script>
    
  • 子组件添加原生事件:修饰符:.native

    • 在父组件中使用子组件时,在原生方法上加上该修饰符,可以将事件绑定到子组件的根标签上(只能用于原生事件,click等)
    <template>
    	<div>
           <Box @click.native="fn"></Box>
    	</div>
    </template>
    
    <script>
    	import Box from "./Box.vue"
    	export default {
            methods:{
    			fn(){
    				console.log(66666)
    			}
    		},
    		components:{
    			Box
    		}
    	}
    </script>
    
    
  • 通过.sync实现父子组件的双向绑定

    • 在父组件调用子组件时,在绑定的属性后加上修饰符.sync
    • 在子组件中使用this.$emit("update:属性名",传递的值)来实现子组件向父组件传值
    //子组件
    <template>
    	<div>
    		<h1>box----{{n}}</h1>
    		<button @click="fn">儿子修改爸爸</button>
    	</div>
    </template>
    
    <script>
    	export default {
    	  props:["n"],
    	  methods:{
    		  fn(){
    			  this.$emit("update:n",this.n+1)//n为子组件中注册的属性名
    		  }
    	  }
    	}
    </script>
    
    //父组件
    <template>
    	<div>
    		<h1>app----{{count}}</h1>
            <Box :n.sync="count"></Box>
    	</div>
    </template>
    
    <script>
    	import Box from "./Box.vue"
    	export default {
           data() {
           	return {
           		count: 20
           	}
           },
    	   components:{
    		   Box
    	   }
    	}
    </script>
    
  • 多层组件传值:$listeners/$attrs

    • $listeners:事件传递

    • $attrs:属性传递

    • 在中间层绑定v-on="$listeners"v-bind="$attrs"可以将上一层组件的数据和事件往下一层传递,也可以将下一层的this.$emit()往上一层传递

      //第一层  App层
      <template>
      	<div>
      		<h1>app----{{n}}</h1>
      		<Two @appchange1="change1" :count="n"></Two>
      	</div>
      </template>
      <script>
      	import Two from "./Two.vue"
      	export default {
      		data() {
      			return {
      				n: 20
      			}
      		},
      		components:{
      			Two
      		},
      		methods:{
      			change1(v){
      				this.n=v
      			}
      		}
      	}
      </script>
      
      //第二层  中间层
      <template>
      	<div>
      		<Three v-bind="$attrs" v-on="$listeners"></Three>
      	</div>
      </template>
      
      <script>
      	import Three from "./Three.vue"
      	export default {
      		components:{
      			Three
      		},
      	
      	}
      </script>
      
      //第三层  孙子层
      <template>
      	<div>
      		<h1>three----{{count}}</h1>
      		<button @click="change1">three修改数据</button>
      	</div>
      </template>
      
      <script>
      	export default {
      		props:["count"],
      		methods:{
      			change1(){
      				this.$emit("appchange1",this.count+1)
      				
      			}
      		}
      	}
      </script>
      
      
  • 使用$parent/$root/$children/$refs实现传值

    这些功能都有一定的缺陷,官方建议尽量避免使用

    • $root

      //$root:能够访问根组件vm对象,所有的实例都可以将这个实例对象作为一个全局变量来访问和使用
      
      <template>
      	<div>
      		<h1>three-----{{$root.name1}}</h1>
      		<button @click="change2">three-给根组件的name1设置数据</button>
      	</div>
      </template>
      
      <script>
      	export default {
      		methods:{
      			change2(){
      				this.$root.name1="three修改了跟组件的name1数据"
      			}
      		}
      	}
      </script>
      
    • $parent

      //$parent:访问父组件对象,可以直接操作到父组件的data数据和方法,但是容易造成数据混乱
      //根组件的父组件是undefined
      
      //子组件
      <template>
      	<div>
      		<p>two---{{msg}}</p>
      	    <button @click="getf">two--</button>
      	</div>
      </template>
      <script>
      	export default {	
      		props:["msg"],
      		data() {
      			return {
      				sonmsg: "儿子的数据"
      			}
      		},
      		methods:{
      			getf(){
      				this.$parent.msg="two直接访问到app组件了然后直接改了数据"
      			}
      		}
      	}
      </script>
      
      //父组件
      <template>
      	<div>
      	  <h1>app---{{msg}}</h1>
      		<Two :msg="msg"></Two>
      		<Two msg="9999"></Two>
      	  <button @click="look">lookSon</button>
      	</div>
      </template>
      
      <script>
      	import Two from "./Two.vue"
      	export default {
      		data() {
      			return {
      				msg:"666666"
      			}
      		},
      		methods:{
      			look(){
      				console.log(this.$children)
      			}
      		},
      		components:{
      			Two
      		},
      	}
      </script>
      
    • $children

      //$children:能够访问子组件对象数组,但是不能保证顺序,也不是响应式的。其返回的值是当前组件的所有直接子组件的数组。
      
      <template>
      	<div>
      		<Two msg="9999"></Two>
      	  <button @click="look">lookSon</button>
      	</div>
      </template>
      
      <script>
      	import Two from "./Two.vue"
      	export default {
      		data() {
      			return {
      				msg:"666666"
      			}
      		},
      		methods:{
      			look(){
      				console.log(this.$children)
      			}
      		},
      		components:{
      			Two
      		},
      	}
      </script>
      
      
    • $refs

       $refs:只会在组件渲染完成之后生效,并且它们不是响应式的。你应该避免在模板或计算属性中访问 $refs。
       
        //在组件或者原生元素绑定ref属性(类似于id):
       <myinput ref="myInput1"></myinput>
       <input ref="myInput2"></input>
       
       //在父组件中可以通过 this.$refs访问到它:
       methods: {
         focus: function () {
           this.$refs.myInput2.focus()
         }
       }
      
  • vue依赖注入 - provide/inject

    • vue在2.2.0之后,提供了provide/inject来实现多层组件传值

      //爷爷
      <template>
        <div>
          <p>{{ title }}</p>
          <son></son>
        </div>
      </template>
      <script>
        import Son from "./son"
        export default {
          name: 'Father',
          components: { Son },
          // provide选项提供变量
          provide: {
            message: 'provided by father'
          },
          data () {
            return {
              title: '父组件'
            }
          },
          methods: { ... }
        }
      </script>
      
      //爸爸
      <template>
        <div>
          <p>{{ title }}</p>
          <grand-son></grand-son>
        </div>
      </template>
      <script>
      import grandSon from "./grandSon "
      export default {
        name: "Son",
        components: { grandSon },
        data () {
          return {
            title: '子组件'
          }
        },
      };
      </script>
      //孙子
      <template>
        <div>
          <p>message:{{ message }}</p>
        </div>
      </template>
      <script>
      export default {
        name: "GrandSon",
        inject: [ "message" ],
        data () {
          return {
            title: '孙组件'
          }
        },
        methods: { ... }
      };
      </script>
      
  • 中央事件总线:

    • 创建一个新的vm对象,统一注册所有事件,将其放在Vue的原型上,使所有组件都可以调用访问。

    • vue提供的绑定事件的方式:this.$on,移除事件的方式:this.$off

      //vue-bus.js文件    单独创建一个vm对象,创建on/off方法
      import Vue from "vue"
      let bus=new Vue({
      	methods:{
      		on(eventname,cb){			
      			this.$on(eventname,cb)
      		},
      		emit(eventname){
      			this.$emit(eventname,...arguments)
      		},
      		off(eventname){
      			this.$off(eventname)
      		}
      	}	
      })
      export default bus;
      
      ################
        Vue.prototype.$bus=Bus;//由于这个新的vm放在与界面绑定的那个vm的原型上,因此页面上的所有组件都能通过this.$bus访问这个新vm对象
      
      
      //main.js文件
      
      //import VueBus from './vue-bus'
      //Vue.use(VueBus);
      
      import Vue from 'vue'
      import App from './App.vue'
      import $bus from "./bus.js"
      
      Vue.prototype.$bus=$bus //绑定到原型上
      
      // Vue.use($bus)
      // new Vue({
      // 	methods:{
      // 		on(eventname,cb){			
      // 			this.$on(eventname,cb)
      // 		},
      // 		emit(eventname){
      // 			this.$emit(eventname,...arguments)
      // 		},
      // 		off(eventname){
      // 			this.$off(eventname)
      // 		}
      // 	}	
      // })
      
      var vm=new Vue({
        render: h => h(App),
      }).$mount('#app')
      
      //组件文件中:
      任意业务中都可以通过调用来绑定事件,触发事件并传值,和销毁事件 
      this.$bus.on(event,callback) 
      this.$bus.off(event,callback) 
      this.$bus.emit(event, ...args)
      
      示例:
      组件1:
       this.$bus.on('changedFormObject',(val) =>{
      	        //接受并处理传过来的值:val
                  this.msg = val;
              });
      
      组件2:
      this.$bus.emit('changedFormObject',this.inputValue);//把组件2的data中的给inputValue值传给组件1
      
      
面试题
1.什么是单向数据流?
答:指的是父组件通过属性传值给子组件传入的数据是data中的变量,如果子组件修改了属性值,是不会修改data容器中的变量的,因此,数据在整个工程中,由父级组件通过props向子级组件流动,并且当父组件中的数据发生改变时,子组件会自动接收到改变后的数据,并且更新页面的内容。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值