# 生命周期和数据共享
# 1.import路径优化插件Path Autocomplete
在set.json
中添加以下设置
"path-autocomplete.pathMappings": {
"@":"${folder}/src"
},
"path-autocomplete.extensionOnImport": true
这个插件的作用和webpack
配置项resolve.alias
的作用是一样的
resolve: {//配置模块解析
// 创建important或者require的别名,可以将特定的文件或者目录解析成别名,导入时只需导入key即可
alias: {
// 告诉webpack,程序员写的代码中,@表示src这一层目录
"@":resolve(__dirname, './src')
}
}
# 2.自定义属性props
自定义属性节点props:['属性名','属性名'...],设置组件的自定义属性,外部导入组件时可以设置不同的值,增加组件的复用性,props中的数据,可以直接在模版结构中被使用
注意:props是只读的,不要直接修改props的值,虽然可以修改成功,但是终端仍然会报错
//方式一,数组形式
props: ["init"],
//方式二, 若想进行更加精细化的设置,则需要设置成对象节点
props: {
// 自定义属性A:{属性配置内容}
// 自定义属性B:{属性配置内容}
// 自定义属性C:{属性配置内容}
init: {
// 默认值
default: 0,
//type限制自定义属性的值类型,类型不一致时会报错
type: Number,
//必填项校验,外部调用时若不指定,即使设置了默认值也会报错
required: true,
},
}
# 3.样式冲突
特别是在单页面程序中容易出现,因为所有组件的样式都会被渲染到同一个HTML页面中,这是组件中设置的样式就会变成全局样式
- scoped创建组件样式范围
<style lang="less" scoped>
// scoped会自动的给当前组件模板添加自定义属性data-v-...,从而防止样式冲突
// 当前组件中的样式也会自动使用对应的属性选择器[data-v-...]
h3 {
color: red;
}
</style>
- /deep/ 样式穿透
// h5[data-v-3c83f0b7]
// [data-v-3c83f0b7] h5
// 当使用第三方组件库的时候,如果有修改第三方组件默认样式的需求,需要用到 /deep/
// 样式穿透,本质上是限制属性的后代选择器
/deep/ h5 {
color: pink;
}
# 4.生命周期LifeCycle
创建阶段:
beforeCreate
、created
(重要)、beforeMount
、mounted
(重要)
运行阶段:
beforeUpdate
、Updated
(重要)
销毁阶段:
beforeDestroy
、destroyed
<template>
<div class="test-container">
<h3 id="myh3">Test.vue 组件 --- {{ books.length }} 本图书</h3>
<p id="pppp">message 的值是:{{ message }}</p>
<button @click="message += '~'">修改 message 的值</button>
</div>
</template>
<script>
export default {
props: ["info"],
data() {
return {
message: "hello vue.js",
books: [],
};
},
methods: {
show() {
console.log("调用了 Test 组件的 show 方法!");
},
initBookList() {
let xhr = new XMLHttpRequest();
xhr.open("GET", "http://www.liulongbin.top:3006/api/getbooks");
xhr.send();
xhr.addEventListener("load", () => {
const result = xhr.responseText;
// console.log(result);
this.books = JSON.parse(result).data;
});
},
},
// 创建阶段
beforeCreate() {
// 这个阶段只初始化了 事件 和 生命周期函数,所以vue组件的自定义属性、数据、方法等都不可用,
// 这个生命周期函数不常用
console.log(this.info); // Cannot read properties of undefined (reading 'info')"
console.log(this.message); //undefined
this.show(); //this.show is not a function"
},
created() {
// 这个阶段对组件的自定义属性props、数据data、方法methods等进行了初始化
// 一般在这个生命周期函数使用Ajax请求数据
// 很重要!很重要!很重要!
console.log(this.info); // 这是在外部定义的变量
console.log(this.message); //hello vue.js
this.show(); //调用了 Test 组件的 show 方法!
// 现在可以使用方法了,所以在这里调用Ajax
this.initBookList();
},
beforeMount() {
// 根据数据和模版,在内存中生成HTML结构,但是还没有渲染到浏览器当中,也不常用
console.log('beforeMount');
let dom = document.querySelector('.test-container');
console.log(dom); // null
console.log(this.$el); //undefined
},
mounted() {
// 用内存中编译生成的HTML结构替换掉 el属性 指定的dom元素
// 如果要操作当前组件渲染的DOM元素,也是在这一步操作,
// 很重要!很重要!很重要!
console.log('mounted');
console.log(this.$el); // <div data-v-dc87507c...
let dom = document.querySelector('.test-container');
console.log(dom); // <div data-v-dc87507c...
},
// 运行阶段
beforeUpdate() {
// 数据更新了,但是没有渲染到HTML页面
// 点击修改message的值
console.log('beforeUpdate');
console.log(this.message); // hello vue.js~
let dom = document.querySelector('#pppp');
console.log(dom); // <div> hello vue.js </div>
},
updated() {
// 根据最新的数据,完成HTML页面的渲染
// 当数据变化之后,为了能够操作到最新的 DOM 结构,必须把代码写到 updated 生命周期函数中
// 很重要!很重要!很重要!
// 点击修改message的值
console.log('updated');
console.log(this.message); // hello vue.js~
let dom = document.querySelector('#pppp');
console.log(dom); // <div> hello vue.js~ </div>
},
// 销毁阶段
beforeDestroy() {
//尚未销毁,所有数据都能操作,不常使用,不太重要
console.log('beforeDestroy');
this.message='111'
console.log(this.message); // 111
},
destroyed() {
// HTML中渲染的DOM已经被销毁,但是还能访问到组件的数据和方法,也不常用
console.log("destroyed");
this.message = "aaa";
console.log(this.message); // aaa
let dom = document.querySelector(".test-container");
console.log(dom); // null
this.show(); //调用了 Test 组件的 show 方法!
console.log(this.info); //这是在外部定义的变量
},
};
</script>
# 5.组件间的数据共享
# 父组件 -> 子组件
通过自定义属性props
,父组件的创建子组件的实例是可以通过v-bind
指令给自定义属性传递数据
// Parent.vue
<!-- 父组件给子组件传递数据,通过父组件给只读自定义属性props赋值 -->
<Left :msg='sendMsgForSon'></Left>
<script>
data(){
return {
sendMsgForSon:'this is from father\'s message'
}
}
</script>
// Son.vue
<p>msg 的值是:{{ msg }}</p>
<script>
props:['msg']
</script>
# 子组件 -> 父组件
通过$emit('事件名',事件对象e)
在子组件Son中触发自定义事件,然后附加参数 “事件对象e
” 会传给父组件中注册的自定义事件监听器的回调函数,如果直接把数据传过来的话,那么回调getCount(e)
中的e
就是对应的数据
// Parent.vue
<Son @changeCount='getCount'></Son>
<script>
data(){
return {
count:0
}
},
methods:{
getCount(e){
console.log('获得了来自子组件Right的数据!');
// 将e的值赋给这个组件的count
this.count = e;
}
}
</script>
// Son.vue
<script>
data() {
return {
count: 0
};
},
methods:{
add(){
this.count++;
// console.log('调用了自增方法');
// 触发自定义事件changeCount,将自增的值传给父组件App
this.$emit('changeCount',this.count);
}
}
</script>
其实vue
事件指令v-on
:所监听事件的触发,使用的也是这个原理,例如(下面的是伪代码,但是原理就是这样的):
this.$emit('click',{
clickX:'',
ClickY:'',
target: 对应的dom元素
})
# 兄弟组件/没有引用关系的组件间的数据传递
首先需要创建一个中转站componentBus.js
,命名随意
//componentBus.js
import Vue from 'vue';
// 作为信息中转站,只需要导出一个Vue实例即可
export default new Vue();
然后通过$emit('事件名',事件对象e)
在发送组件Send
中调用bus
模块的实例触发自定义事件
// Send.vue
// 导入中转站bus
import bus from '@/components/componentBus.js'
export default {
methods:{
send()
//调用bus模块的实例触发自定义事件
bus.$emit('share',this.sendMsgForBrother);
}
}
}
最后在接收组件Receive
中通过事件对象e
来接收,如果直接把数据传过来的话,那么回调getCount(e)
中的e
就是对应的数据
// Receive.js
// 导入中转bus
import bus from '@/components/componentBus.js'
// 在事件初始化之后接受来自Send的数据
export default {
data() {
return {
message:''
};
},
// 在created生命周期函数中注册该自定义事件监听器,获取相应数据
created(){
// 注意,这里一定要用箭头函数,因为this指向的问题,不用的话也需要在事件函数外部先声明this的值
bus.$on('share',(e)=>{
console.log('Send的分享方法被触发了');
// 给接收数据的变量赋值
this.message = e;
})
}
}
← 02侦听器和axios 04vuex笔记 →