# Vue3 万字基础 (知识点补充)

# 1.props 父传子通过传一个带参函数也可以实现子传父

1
2
3
4
5
6
7
8
9
10
11
12
13
14
父:<Child info="我是曹操" :money="money" :mySon="mySon"></Child>
function mySon(value: string) {
console.log(value, '收到了来自儿子的值')
}



子:let props = defineProps(['info', 'money', 'mySon']) //数组|对象写法都可以
//按钮点击的回调
const updateProps = () => {
// props.money+=10; props:只读的
alert(props.info)
props.mySon('lai')
}

# 2. 自定义事件

  1. vue2 中只要是写在组件上的事件触发就都是自定义事件,

  2. 在 vue3 中如果父组件上定义了 @click 原生 dom 事件只要子组件不使用 defineEmits (['xxx']) 接收他就是原始 Dom 事件

  3. 如果使用了 defineEmits (['click']) 接收就是自定义事件,可以用来实现子传父,但是不建议使用原生 dom 事件定义自定义事件

# 3. 全局事件总线 vue2 里面的 $bus,vue3 里面使用 mitt

src/bus/index.js

1
2
3
4
5
6
7
8
npm i mitt

import mitt from 'mitt'
//为了不让大家看起来迷糊所以这里我还是用$bus来接收这个函数
const $bus=mitt()


export default $bus

事件发送

1
$bus.emit('定义的方法名',参数1,{34},[5])

事件接收需要放到 onMounted 钩子里面

1
2
3
4
5
onMounted(()=>{
$bus.on('定义的事件名',(...val)=>{
cl(...val)
})
})

还有一些附带事件 off,all,$bus.all.clear () 等

# 4.v-model 父子组件数据同步

在前面已经记录,但是在这里还是要补充一下

原理就是 v-model 绑定数据,v-bind,defineProps 父传子,通过 defineEmits 子传父事件回调原理实现双向数据绑定

# 1. 首先在父组件上使用 v-model:自定义名称 =' 要传的数据'

1
<Children v-model:newsval='pages'/>

# 2. 在子组件中使用 defineProps 接收传过来的数据

1
defineProps(['newsval'])

# 3. 使用 defineEmits 的更新事件更新数据

1
2
3
4
5
const emits=defineEmits(['update:newsval','update:其他'])

emits('update:newsval',props.newsval+1)


注意:如果直接是通过 v-model 传输的没有加:自定义名称,默认就是 update:modelValue, 可以通过 defineProps (["modelValue"]); defineEmits (["modelValue"]);emits ('update:modelValue',props.modelValue+1)

# 5.useAttrs

引入

1
import {useAttrs} from 'vue'

父组件传过来的没有被 props 接受的就都存在了 useAttrs 里面这时候我们可以使用

1
const $attrs=useAttrs()

补充:在父组件的子组件标签上用的属性都可以直接传到 attrs 身上

1
2
3
4
5
6
7
8
9
10
11
<div>
<el-tooltip :content="$attrs.content" :placement="$attrs.top">
<el-button>Dark</el-button>
</el-tooltip>
</div>
</template>

<script lang="ts" setup name="Toptip">
import { useAttrs, type HtmlHTMLAttributes } from 'vue'
const $attrs = useAttrs()
console.log($attrs)

# 6.ref 和 parent

(严格的来说就是 ref 是子组件暴露父组件取值(子传父)parent 就是父组件暴露数据,子组件获取数据,父传子)

在子组件身上添加 ref,就可以获取到子组件的实例,但是子组件的数据需要使用 defineExpose 来向外暴露,组件才能获取到值。

1
2
3
4
5
6
 <Son ref="son"></Son>
//获取子组件的实例
const son=ref()


son.value.money-=10;

parent 的使用原理也是一样的,父组件使用 defineExpose 向外暴露数据,在子组件中使用 parent 就可以获取到父组件的实例,修改父组件的数据直接在事件中使用 parent

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
defineExpose({name})







@click='cl($parent)'




cl(val){

val.name='son'
}

# 7.provide&inject (后代传值)

在祖组件中使用 provide 定义要传给共享给后代的数据

1
2
3
4
import {provide} from 'vue'
let car = ref("发送的数据");

provide('定义发送过去的参数名',要发送的数据)

后代组件上使用 inject 接收值可以通过 Token.value='' 修改值并且会跟随父组件一起更新

1
2
import { inject } from 'vue'
let Token = inject('TOKEN')

# 8.pinia

vuex 集中式管理状态的状态容器,可以实现任意组件之间通信!!!

核心概念:state、mutations、actions、getters、modules

1
通过dispatch去提交一个actions, actions接收到这个事件之后,在actions中可以执行一些异步|同步操作,根据不同的情况去分发给不同的mutations,actions通过commit去触发mutations,mutations去更新state数据,state更新之后,就会通知vue进行渲染

pinia: 集中式管理状态的容器,可以实现任意组件之间通信!

核心概念:state、actions、getters

选项式 API

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//defineStore用于定义小仓库
import { defineStore } from 'pinia'
import { ref } from 'vue'

//第一个参数是小仓库的名字,第二个是小仓库的配置对象
//defineStore会返回一个函数,可以让组件看到仓库的数据
let useInfoStore = defineStore('info', {
//存储数据:state
state: () => {
return {
count: ref(100),
arr: [1, 2, 3, 4, 5, 6, 7, 8, 9]
}
},
actions: {
updateNum(a: number, b: number) {
this.count += a + b
}
},
getters: {
arrSum() {
let result: any = this.arr.reduce((previousValue, currentValue) => {
return currentValue + previousValue
}, 0)
return result
}
}

})

//对外暴露
export default useInfoStore

组合式 API

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import { defineStore } from 'pinia'
import { ref, computed } from 'vue';
//组合式API
// 创建小仓库,第一个仓库名,第二个是箭头函数
let useCombinationStore = defineStore('cmStore', () => {
let todos = ref([{ id: 1845, title: '生活' }, { id: 1847, title: '书简' }, { id: 1745, title: '吃饭' }])
let arr = ref([1, 2, 3, 2, 2, 2, 2, 2, 2, 2,])
function updateTodos() {
todos.value.unshift({ id: 451, title: '开车' })
}
//计算属性
const subSum = computed(() => {
return arr.value.reduce((pre: number, next: number) => pre + next, 0);
})
//返回对象属性和方法
return {
todos,
updateTodos,
subSum
}
})


export default useCombinationStore

# slot

难点:slot 子传父

这里可以把 template 看作 slot 标签,就是 slot 上带有 row 和 index 两个值,只需要在 template 标签上使用该属性接收即可

更新于 阅读次数

请我喝[茶]~( ̄▽ ̄)~*

Xiao Yang Guo 微信支付

微信支付

Xiao Yang Guo 支付宝

支付宝

Xiao Yang Guo 贝宝

贝宝