目录
组件之间的数据共享
Vue 3 中的自定义事件
在vu3中使用使用自定义事相较vu2中多了一个 emits 节点声明:
vue 3中使用自定义事件:
在封装组件时:
1. 在`emits`节点声明自定义事件
2. `触发`监听事件
在使用组件时: 监听自定义事件
声明自定义事件:
// 子组件
<button @click="onBtnClick"> +1 </button>
<script>
export default {
// 自定义事件必须声明到 emits 节点中
emits: ['chage']
}
</script>
触发自定义事件:
// 子组件
<button @click="onBtnClick"> +1 </button>
<script>
export default {
// 自定义事件必须声明到 emits 节点中
emits: ['chage'],
data() {
// 子组件自己的数据,将来希望把 count 值传给父组件
return { count: 0 }
},
methods: {
onBtnClick() {
this.count t= 1
//修改数据时,通过 $emit()触发自定义事件
// 当点击 '+1' 按钮时 调用this.$emit 触发自定义的 numchange 事件
this.$emit( 'numchange')}
}
}
</script>
监听自定义事件:
// 父组件
// 使用 v-on 指令绑定监听事件
<Son @numchange="getNewCount"></Son>
methods : {
getNewCount(val) {
console.log('监听到了 count 值的变化', val)
},
组件上的 v-model
当需要维护组件内外数据的同步时,可以在组件上使用 v-model 指令。示意图:
父子组件数据共享
实现父子组件数据双向同步。
子组件向父组件共享数据:
父组件通过 v-bind 属性绑定向子组件共享数据,子组件使用 props接收数据。
父组件向子组件共享数据:
通过自定义事件 emits ,然后触发 $emit(), 子组件监听。
1在 v-bind: 指令之前添加 v-model 指令
2在子组件中声明 emits 自定义事件,格式为必须 update:xxx
3调用 $emit() 触发自定义事件,更新父组件中的数据
使 v-model 实现子→父组件共享数据好处:
在父组件中 不用再监听自定义事件了,也不用再额外声明事件处理函数。
父组件:
// 使用双向数据绑定指令
<my-son v-model:number="count"> </my-son>
data(){
return{
count: 0
}
}
子组件:
// 子组件
<button @click="add"> +1 </button>
<script>
export default {
prpos:['number']
emits:['update:number']
methods: {
add() {
this.$emit( 'update:number',this.num+1)}
}
}
</script>
后代关系组件之间的数据共享
指的是父节点的组件向其子孙组件共享数据。
使用步骤:
1 父节点通过 provide 方法,对子孙组件共享数据。
export default {
data() {
return {
color: 'red', // 1. 定义"父组件"要向"子孙组件"共享的数据
}
},
provide() { // provide函数 返回要共享的数据对象
return {
color: this.color,
count: 1,
}
},
}
2 子孙节点通过 inject 接收数据。
<template>
<h5>三级组件 --- {{ color }} --- {{ count }}</h5>
</template>
<script>
export default {
// 子孙组件,使用 inject 接收父节点共享的数据
inject: ['color', 'count'],
}
</script>
父节点对外共享响应式的数据
父节点使用 provide 向下共享数据时并非响应式,我们可以结合 computed 函数向下共享响应式的数据:
import { computed } from 'vue' // 1. 从vue中按需导入 computed 函数
export default {
data() {
return {
color: 'red',
}
},
provide() {
return {
// 2. 使用 computed 函数,把共享数据包装为"响应式"的数据
color: computed(() => this.color),
count: 1,
}
},
}
子孙节点使用响应式数据, 注意接收的响应式数据必须以 .value 的形式使用:
<template>
// 响应式数据,必须以.value 的形式进行使用
<h5>子孙组件 --- {{ color.value }} --- {{ count }}</h5>
</template>
<script>
export default {
// 子孙组件,使用 inject 接收父节点共享的数据
inject: ['color', 'count'],
}
</script>
全局数据共享
vuex 是终极的组件之间的数据共享方案。
- 解决大量、频繁的共享数据麻烦问题。
- vuex 就是用来管理组件中需要共享的数据。
数据共享总结
父子关系:
- 父 → 子 : 自定义属性
- 子 → 父 :自定义事件
- 父子组件数据共享 使用组件上的 v-model
兄弟关系: EvenBus
后代关系:provide & inject
全局数据共享: vuex
在vue3中全局配置 axios
import { createApp } from 'vue'
import './assets/css/bootstrap.css'
import './index.css'
import axios from 'axios'
// 创建一个单页面应用程序实例
const app = createApp(App)
// 配置全局请求根路径
axios.defaults.baseURL = 'https://www.escook.cn'
// 全局挂载到app 根路径中
// $http 是模仿 vue封装成员的方式
app.config.globalProperties.$http = axios
// 实现挂载
app.mount('#app')
在组件中使用:
methods: {
async getInfo() {
const { data: res } = await this.$http.get('/api/get', {
// get 请求必须通过 params 传参
params: {
name: 'ls',
age: 33,
},
})
console.log(res)
},
},
vue3 中创建路由
- vue3 中需要安装 4.x的版本
- 在 src 目录下创建 router.js 文件并配置
import { createRouter, createWebHashHistory } from 'vue-router'
import Login from './components/MyLogin.vue'
import Home from './components/Home.vue'
// 创建路由实例对象
const router = createRouter({
history: createWebHashHistory(), // 指定通过 hash 管理路由的切换
routes: [
{ path: '/home', redirect: '/login' },
{ path: '/login', component: Login, name: 'login' },
],
})
export default router //4. 向外共享路由对象
在 src/main.js 入口文件中,导入并挂载路由模块:
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
// 创建 app 实例
const app = createApp(App)
app.use(router)
// 挂载 app 实例
app.mount('#app')
事件:
// 父组件
// 使用 v-on 指令绑定监听事件
<Son @numchange="getNewCount"></Son>
methods : {
getNewCount(val) {
console.log('监听到了 count 值的变化', val)
},
ref 引用 操作DOM
不依赖于 jQuery 和调用 DOM API 的情况下,获取 DOM 元素
或组件的引用
。
每个 vue 的组件实例上,都包含一个 $refs 对象
,里面存储着对应的 DOM 元素或组件的引用。默认情况下,组件的 $refs 指向一个空对象。
使用 ref 引用 DOM 元素
<!--使用ref属性,为对应的DOM添加引用名称-->
<h3 ref="myh3">MyRef 组件</h3>
<button@click="getRef">获取$refs 引用</button>
methods:{
getRef(){
//通过this.$refs.引用的名称可以获取到DOM元素的引用
console.log(this.$refs.myh3)
//操作DOM元素,把文本颜色改为红色
this.$refs.myh3.style.color='red'
},
使用 ref 引用组件实例
需求: 在根组件控制子组件
<!--使用ref属性,为对应的“组件”添加引用名称-->
<my-counter ref="counterRef"> </my-counter>
<button @click="getRef"> 获取$refs 引用 </button>
methods:{
getRef(){
// 通过this.$refs.引用的名称可以引用组件的实例
console.log(this.$refs.counterRef)
// 引用到组件的实例之后,就可以调用 子组件上的 methods 方法
this.$refs.counterRef.add()
},
点击文本框自动获得焦点
添加 ref 引用,并调用原生 DOM 对象的.focus()
方法即可。
this.$nextTick(cb) 方法
$nextTick(cb)
保证 cb 回调函数可以操作到最新的 DOM 元素(推迟到下一个 DOM 更新周期之后执行)。
- 解决我们在页面没有渲染完成前使用 ref 操作DOM元素报错问题。
控制文本框和按钮的按需切换
点击按钮展示文本框,文本框输入时隐藏按钮:
<template>
<input type="text" v-if="inputVisible" ref="ipt">
<button v-else @click="showInput">展示input输入框</button>
</template>
<script>
export default{
data(){
return{
//控制文本框和按钮的按需切换
inputVisible:false,
},
methods:{
showInput(){
//切换布尔值,显示文本框
this.inputVisible=true
//获取文本框的DOM引用,并调用.focus()使其自动获得焦点
// this.$refs.ipt.focus() 错误,此时页面未渲染完毕,无法获取文本框
//把对input文本框的操作,推迟到下次DOM更新之后。否则页面上根本不存在文本框元素
this.$nextTick(() =>{
this.$refs.ipt.focus()
})
}
},
</script>