Vue (第14篇 组件通讯)

Vue:https://cn.vuejs.org/v2/guide/components-props.html

1、props  (父传子,props值可以是一个数组或者对象)

     *父子之间传值已经在Vue第二篇中介绍过:https://blog.csdn.net/qq_42540989/article/details/98481824

Vue.component('my-component', {
  props: {
    // 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证)
    propA: Number,
    // 多个可能的类型
    propB: [String, Number],
    // 必填的字符串
    propC: {
      type: String,
      required: true
    },
    // 带有默认值的数字
    propD: {
      type: Number,
      default: 100
    },
    // 带有默认值的对象
    propE: {
      type: Object,
      // 对象或数组默认值必须从一个工厂函数获取
      default: function () {
        return { message: 'hello' }
      }
    },
    // 自定义验证函数
    propF: {
      validator: function (value) {
        // 这个值必须匹配下列字符串中的一个
        return ['success', 'warning', 'danger'].indexOf(value) !== -1
      }
    }
  }
})

单向数据流:所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外改变父级组件的状态。每次父级组件发生更新时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你应该在一个子组件内部改变 prop。如果你这样做了,Vue 会在浏览器的控制台中发出警告。

禁用特性继承:

①如果你不希望组件的根元素继承特性,你可以在组件的选项中设置 inheritAttrs: false

Vue.component('my-component', {
  inheritAttrs: false,
  // ...
})

②配合实例的 $attrs 属性使用如下:

//该属性包含了传递给一个组件的特性名和特性值

{
  required: true,
  placeholder: 'Enter your username'
}
//有了 inheritAttrs: false 和 $attrs,你就可以手动决定这些特性会被赋予哪个元素

//inheritAttrs: false 选项不会影响 style 和 class 的绑定。

Vue.component('base-input', {

  inheritAttrs: false,

  props: ['label', 'value'],

  template: `

    <label>

      {{ label }}

      <input

        v-bind="$attrs"

        v-bind:value="value"

        v-on:input="$emit('input', $event.target.value)"

      >

    </label>

  `
})

2、$emit  (子组件触发父组件的自定义事件  ---子传父)

     vm.$emit( event, arg )
     $emit 绑定一个自定义事件event,当这个这个语句被执行到的时候,就会将参数arg传递给父组件,父组件通过@event监听并接收参数。

//子组件

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>子传父</title>
</head>
<body>
	<template>
		<div class="select-work">
			<h3>这是父组件传给子组件的值:{{sendWorkData}}</h3>
			<button @click='select('web前端')'>将‘web前端’传给父组件</button>
		</div>
	</template>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

<script type="module">
	export default{
		name:'select',
		props:['sendWorkData'],  //接收父组件传给子组件的值。
		methods:{
			select(value){
				let data = {
					workName:value
				};
				this.$emit('showWork',data); //点击事件select触发后,同时触发showWork
			}
		}
	}
</script>
</html>
//父组件
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>字传父</title>
</head>
<body>
	<template>
		<h3>我是父组件的值:{{workName}}</h3>
		<div @showWork = 'upWorkData' :sendWorkData = 'workName'></div>
	</template>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

<script>
	import select from "./select"; 
	export default{
		name:'index',
		components:{
			selectWorkName
		},
		data(){
			return{
				workName:"程序猿鼓励师"
			}
		},
		methods:{
			upWorkData(data){
				this.workName = data.workName;
			}
		}
	}
</script>
</html>

3、$ref

      如果ref用在子组件上,指向的是组件实例,可以理解为对子组件的索引,通过$ref可能获取到在子组件里定义的属性和方法。

      如果ref在普通的 DOM 元素上使用,引用指向的就是 DOM 元素,通过$ref可能获取到该DOM 的属性集合,轻松访问到DOM元素,作用与JQ选择器类似。(解释摘自简书:https://www.jianshu.com/p/91416e11f012)

通过ref='msg'可以将子组件son的实例指给$ref,并通过this.$refa.msg.getMessage()调用到子组件的getMessage方法,将参数传递给子组件

//父组件

<template>
  <div>
    <p style="color:red">-----我是grandfa组件的coo:{{coo}}-----</p>
    <son ref="msg"></son>
  </div>
</template>
<script>
import son from "./son.vue";
export default {
  name: "grandfa",
  data() {
    return {
      foo: "Hello, 我是父组件传到子组件的值",
      coo: "Hello,我是父组件的coo"
    };
  },
  components: { son },
  methods: {
    // reciveRocket(data) {
    //   this.coo = data.changeName;
    //   console.log("reciveRocket success");
    // }
  },
  mounted(){
      console.log( this.$refs.msg);
      this.$refs.msg.$el.style.color="blue";
      this.$refs.msg.getMessage('我是son组件')
  }

};
</script>

//子组件

<template>
  <div>
    <p>{{message}}</p>
    <!-- <p>我是son组件的foo:{{doo}}</p> -->
    <!-- <p>我是son组件的attrs:{{$attrs}}</p>
    <grandson v-bind="$attrs" v-on="$listeners" style="color:blue"></grandson> -->
  </div>
</template>

<script>
// import grandson from "./grandson.vue";
export default {
  name: "son",
  data(){
    return{
      message:''
    }
  },
    methods:{
      getMessage(m){
        this.message=m;
      }
    },
  // props: ["doo"], //doo作为props属性绑定
  // inheritAttrs: false,
  // components: {
  //   grandson
  // },
  created() {
    // console.log(this.$attrs); //{foo: "Hello, 我是父组件传到子组件的值", coo: "Hello,我是父组件的coo", eoo: "Hello,我是Java工程师"}
  }
};
</script>

<style>
</style>

 使用$refs获取子组件的数据:

//父组件

<template>
  <div>
    <p style="color:red">我是父组件获取到的子组件的数据:---{{message}}</p>
    <son ref="sonMsg"></son>
    <button @click="getSonCoo()">使用$refs获取子组件的数据</button>
  </div>
</template>
<script>
import son from "./son.vue";
export default {
  name: "grandfa",
  data() {
    return {
      foo: "Hello, 我是父组件传到子组件的值",
      coo: "Hello,我是父组件的coo",
      message:''
    };
  },
  components: { son },
  methods: {
    // reciveRocket(data) {
    //   this.coo = data.changeName;
    //   console.log("reciveRocket success");
    // }
    getSonCoo(){
      this.message = this.$refs.sonMsg.sonMessage
      console.log(this.message)
    }
  },
  mounted(){
      // console.log( this.$refs.msg);
      // this.$refs.msg.$el.style.color="blue";
      // this.$refs.msg.getMessage('我是son组件')
  }

};
</script>

 

//子组件

<template>
  <div>
    <p>我是子组件里边的message:---{{sonMessage}}</p>
    <!-- <p>我是son组件的foo:{{doo}}</p> -->
    <!-- <p>我是son组件的attrs:{{$attrs}}</p>
    <grandson v-bind="$attrs" v-on="$listeners" style="color:blue"></grandson> -->
  </div>
</template>

<script>
// import grandson from "./grandson.vue";
export default {
  name: "son",
  data(){
    return{
      sonMessage:'我是子组件里边的message,要改变父组件的值'
    }
  },
};
</script>

<style>
</style>

注意: $refs 它是非响应的,所以应该避免在模板或计算属性中使用 $refs ,它仅仅是一个直接操作子组件的应急方案; $refs不能在created生命周期中使用 因为在组件创建时候 该ref还没有绑定元素;当使用v-for的元素或组件,引用信息$refs将是包含DOM节点的或组件实例的数组,类似$children的使用;(注意事项摘自https://blog.csdn.net/zhouzuoluo/article/details/81097339

*prop和$ref的区别:

prop:着重于数据的传递,不能调用子组件里边的方法和属性。创建文章组件时,自定义标题、内容适合使用prop。

$ref:着重于索引,主要是用来调用子组件的方法和属性。ref用在获取dom元素的时候,能起到选择器的作用。上面父组件中设置 ref='msg'的颜色为blue,这个功能比作为索引更常用。

 

4、vuex  (vue的状态管理)

     *vuex的学习已另起一篇文章记录

  

5、*$attrs, $listeners   *已另起一篇文章记录

 

6、$parent、$children 

$parent :可以直接访问该组件的父实例或组件;获取之后可以使用它的属性和方法。当前组件树的根 Vue 实例。如果当前实例没有父实例,此实例将会是其自己。

$children:父组件可以通过this.$children 访问它所有子组件实例,返回的是一个数组。 $children 并不保证顺序,也不是响应式的。如果你发现自己正在尝试使用 $children 来进行数据绑定,考虑使用一个数组配合 v-for 来生成子组件,并且使用 Array 作为真正的来源。

父组件使用$children获取子组件的数据

//父组件

<template>
  <div>
    <p style="color:red">我是父组件获取到son子组件的数据:---{{message}}</p>
    <p style="color:green">我是父组件获取到grandson子组件的数据:---{{messageGrandSon}}</p>
    <son ref="sonMsg"></son>
    <grandson></grandson>
    <button @click="getSonCoo()">使用$children获取子组件的数据</button>
  </div>
</template>
<script>
import son from "./son.vue";
import grandson from "./grandson.vue";
export default {
  name: "grandfa",
  data() {
    return {
      foo: "Hello, 我是父组件传到子组件的值",
      coo: "Hello,我是父组件的coo",
      message:'',
      messageGrandSon:''
    };
  },
  components: { son,grandson },
  methods: {
    // reciveRocket(data) {
    //   this.coo = data.changeName;
    //   console.log("reciveRocket success");
    // }
    getSonCoo(){
      this.children = this.$children;
      console.log(this.children)   //array
      this.message = this.$children[0].sonMessage;
      this.messageGrandSon = this.$children[1].grandsonMessage
      console.log("son的message"+this.message)
      console.log("grandson的message"+this.messageGrandSon)
    }
  },
  mounted(){
      // console.log( this.$refs.msg);
      // this.$refs.msg.$el.style.color="blue";
      // this.$refs.msg.getMessage('我是son组件')
  }

};
</script>
// son子组件

<template>
  <div>
    <p>我是son子组件里边的message:---{{sonMessage}}</p>
    <!-- <p>我是son组件的foo:{{doo}}</p> -->
    <!-- <p>我是son组件的attrs:{{$attrs}}</p>
    <grandson v-bind="$attrs" v-on="$listeners" style="color:blue"></grandson> -->
  </div>
</template>

<script>
// import grandson from "./grandson.vue";
export default {
  name: "son",
  data(){
    return{
      sonMessage:'我是son子组件里边的message----web前端'
    }
  },
};
</script>

<style>
</style>
// grandson子组件

<template>
  <div>
    <p>我是grandson组件的sonMessage:{{grandsonMessage}}</p>
   
  </div>
</template>
<script>
export default {
  name: "grandson",
   data(){
    return{
      grandsonMessage:'我是grandson子组件里边的message---java'
    }
  },
 
};
</script>

<style>
</style>

 

 $children  返回的是一个数组:

$parent  子组件获取修改父组件的数据内容:

// 父组件

<template>
  <div>
    <son></son>
  </div>
</template>
<script>
import son from "./son.vue";
export default {
  name: "grandfa",
  data() {
    return {
      coo: "Hello,我是父组件的coo",
 
    };
  },
  components: { son },


};
</script>
//子组件

<template>
  <div>
    <p>我是子组件里边的message:---{{sonMessage}}</p> 
    <button @click="getGrandSonCoo()">使用$parent获取父组件的数据</button>

  </div>
</template>

<script>
// import grandson from "./grandson.vue";
export default {
  name: "son",
  data(){
    return{
      sonMessage:''
    }
  },
   methods: {
    getGrandSonCoo(){
      this.$parent.coo="子组件中可以修改父组件的内容---:hello,我是父组件的coo"
      this.sonMessage = this.$parent.coo;
       
    }
  },
};
</script>

<style>
</style>

 

 

7、$root  (设置全局属性)

// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router'
Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  data(){
    return{
     work:'Web前端'
    }
   },
  router,
  components: { App },
  template: '<App/>'
})
<template>
  <div>
    <son></son>
  </div>
</template>
<script>
import son from "./son.vue";
export default {
  name: "grandfa",
  data() {
    return {
      coo: "Hello,我是父组件的coo",
 
    };
  },
  components: { son },
  created(){
     console.log(this.$root.work)  //web前端
  }

};
</script>

 

 

 *root 和parent 的区别:

 ①都能够实现访问父组件的属性和方法。

 ② $root 属性访问根实例的属性和方法 ;$parent属性访问父组件实例的属性和方法。

  如果存在多级子组件,$root 访问到根父组件,$parent 访问到最近一级的父组件。

 

8、.sync 修饰符

// 父组件

<son :word.sync="wrd" ></son> 

 // 子组件 

子组件可以通过$emit 触发 update 方法改变 mounted(){ this.$emit("update:word", '这是新的word') }
//父组件

<template>
   <div class="hello">

    <!-- input实时改变wrd的值, 并且会实时改变son里的内容 -->
    <input type="text" v-model="wrd" placeholder="父组件的输入框">

    <son :word.sync="wrd" ></son>

  </div>
</template>
<script>
import son from "./son.vue";
export default {
  name: "grandfa",
  data() {
    return {
      coo: "Hello,我是父组件的coo",
      wrd:""
 
    };
  },
  components: { son },
  created(){
    //  console.log(this.$root.work)
  }

};
</script>
//子组件

<template>
    <div class="hello">
    <div class="ipt">
      <input type="text" v-model="str" placeholder="子组件的输入框">
    </div>

    <!-- word是父元素传过来的 -->
    <h2>{{ word }}</h2>

  </div>
</template>

<script>
// import grandson from "./grandson.vue";
export default {
  name: "son",
  data(){
    return{
      str:''
    }
  },
  props:["word"],
  watch:{
    str:function(){
         this.$emit("update:word","我是新的数据:java工程师")
    }
     
  },
};
</script>

<style>
</style>

9、v-slot 

.匿名插槽(也叫默认插槽): 没有命名,有且只有一个;v-slot:default。

具名插槽:组件中可以使用<template v-slot:header="slotProps"></template>标签,当没有指定插槽name时,默认出口会带有隐含的名字“default”。

④作用域插槽: 子组件内数据可以被父页面拿到(解决了数据只能从父页面传递给子组件)。

③根组件可以利用v-slot:header="slotProps"接受组件中的消息,组件中只需要在<slot name="header" :header="header"></slot>就可以了。

//父组件

<template>
  <div class="hello">
    <son>
      <template v-slot:header="slotProps">
        <h1>{{slotProps.header + ' ' + coo}}</h1>
      </template>
      <template v-slot:footer="slotProps">
        <h1>{{slotProps.footer + ' ' + coo}}</h1>
      </template>
    </son>
  </div>
</template>
<script>
import son from "./son.vue";
export default {
  name: "grandfa",
  data() {
    return {
      coo: "---Hello,我是父组件的coo"
    };
  },
  components: { son },
  created() {
    //  console.log(this.$root.work)
  }
};
</script>
//子组件

<template>
  <div class="hello">
    <header>
      <slot name="header" :header="msg"></slot>
    </header>
    <footer>
      <slot name="footer" :footer="footerMsg"></slot>
    </footer>
  </div>
</template>

<script>
// import grandson from "./grandson.vue";
export default {
  name: "son",
  data() {
    return {
      msg: "我是子组件:msg",
      footerMsg: "我是子组件:Web开发"
    };
  },
  methods: {}
};
</script>

<style>
</style>

 

 10、EventBus :声明一个全局Vue实例变量 EventBus , 把所有的通信数据,事件监听都存储到这个变量上;类似于 Vuex。但这种方式只适用于极小的项目 3;原理就是利用emit 并实例化一个全局 vue 实现数据共享。

//在main.js 中

Vue.prototype.$eventBus = new Vue();
//父组件

<template>
  <div class="hello">
    <son>
    </son>
  </div>
</template>
<script>
import son from "./son.vue";
export default {
  name: "grandfa",
  data() {
    return {
      coo: "---Hello,我是父组件的coo"
    };
  },
  components: { son },
  mounted() {
    console.log("我在父组件")
    this.$eventBus.$emit('eventTarget','前端开发工程师');
  }
};
</script>
//子组件

<template>
  <div class="hello">

  </div>
</template>

<script>
// import grandson from "./grandson.vue";
export default {
  name: "son",
  data() {
    return {
      msg: "我是子组件:msg",
      footerMsg: "我是子组件:Web开发"
    };
  },
  mounted() {
     console.log("我在子组件")
    this.$eventBus.$on("eventTarget", function(params){
     
      console.log(params); //这是eventTarget传过来的值   前端开发工程师
    });
  },
  methods: {}
};
</script>

<style>
</style>

 

 

11、路由传参

//场景1

//父组件

<template>
  <div class="hello">
    <button @click="goSon()">点我跳转传参</button>
    <!-- <son></son> -->
  </div>
</template>
<script>
// import son from "./son.vue";
export default {
  name: "grandfa",
  data() {
    return {
      coo: "---Hello,我是父组件的coo"
    };
  },
  // components: { son },
  mounted() {
    // this.goSon()
  },
  methods: {
    goSon() {
      this.$router.push({
        name: "son",
        params: {
          cooData: "我是跳转传的值"
        }
      });
    }
  }
};
</script>

//子组件

<template>
  <div class="hello"></div>
</template>

<script>
// import grandson from "./grandson.vue";
export default {
  name: "son",
  data() {
    return {
      msg: "我是子组件:msg",
      footerMsg: "我是子组件:Web开发"
    };
  },
  mounted() {
    console.log(this.$route.params.cooData);
  },
  methods: {}
};
</script>

<style>
</style>

 

//场景二

//父组件

  methods: {
    goSon() {
      this.$router.push({
        name: "son",
        query: {
          cooData: "我是跳转传的值"
        }
      });
    }
  }
//子组件

console.log(this.$route.query.cooData);

 

 

*两种场景对比 场景1参数不会拼接在路由后面,页面刷新参数会丢失 场景2参数拼接在后面,容易泄露信息。

 

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值