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参数拼接在后面,容易泄露信息。