vue3组件通信(vite)
garvin 10/10/2022 vue3
# 使用vite第三方框架 vitesse (opens new window)
# 父传子 | 子传父
- 父传子传递 values name
- 子传父 handleOk sonToFatherMethedEmit
- Father.vue
<script lang="ts" setup>
import Son from "./Son.vue";
const values = ref("我是父组件的值");
console.log(values.value);
const handleOk = (value: string) => {
console.log(value);
};
const sonToFatherMethedEmit = (emitMsg: string) => {
console.log(emitMsg);
};
</script>
<template>
<Son
:values="values"
:name="'Tom'"
:handleOk="handleOk"
@sonToFatherEmit="sonToFatherMethedEmit"
/>
<div>{{ values.value }}</div>
</template>
<style scoped></style>
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
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
- 1 setup写在里面方式
- (父传子)props接收数组参数 | setup 参数接收props使用
- (子传父)handleOk直接在
props.handleOk('ccccccccc')
传递 - (子传父)setup写在里面时 setup接收ctx上下文 调用emit 传值
ctx.emit ('sonToFatherEmit', 'xxxxxxxxxxx')
Son.vue
<script lang="ts">
import { defineComponent, ref } from 'vue';
export default defineComponent({
props: ['name', 'values', 'sonToFatherEmit'],
mounted() {
console.log(this.name, this.values)
},
setup(props, ctx) {
const value = ref<string>('');
onMounted(() => {
console.log(props)
})
const clicks = () => {
props.handleOk('ccccccccc')
ctx.emit('sonToFatherEmit', 'xxxxxxxxxxx')
}
return {
value,
clicks
};
},
});
</script>
<template>
<Button @click="clicks">++++++</Button>
<Button @click="click">-------</Button>
</template>
<style scoped lang="less"></style>
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
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
2 setup写在外面方式
(父传子)defineProps接收 要写泛型否则接收不到没写的值
(子传父)
props.handleOk('111111111111')
(子传父) defineEmits接收函数
emits('sonToFatherEmit', "123")
<script lang="ts" setup>
const props = defineProps<{
values: string;
name: string;
handleOk: (a: string) => void;
}>();
const emits = defineEmits<{
(e: 'sonToFatherEmit', id: string): void;
}>()
console.log(emits, props);
const click = () => {
props.handleOk('111111111111')
emits('sonToFatherEmit', "123")
}
</script>
// setup写外面 父组件调用子组件方法 defineExpose 接收
<script lang="ts" setup>
const props = defineProps<{
values: string;
name: string;
handleOk: (a: string) => void;
}>();
const emits = defineEmits<{
(e: 'sonToFatherEmit', id: string, secondPar: string): void
}>()
const doSth = () => {
console.log('>>>>>>>>>>>>>>')
}
defineExpose({ doSth })
console.log(emits);
const click = () => {
props.handleOk('111111111111')
emits('sonToFatherEmit', "123", 'secondPar')
}
</script>
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
33
34
35
36
37
38
39
40
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
33
34
35
36
37
38
39
40
# 父组件调用子组件方法
- Father.vue 创建 childRef 组件里使用ref childRef.value调用 找不到子组件的方法可以套一层nextTick
const childRef = ref<any>();
// childRef.value.doSth();
nextTick(() => {
childRef.value.doSth();
})
<Son ref='childRef'>
1
2
3
4
5
6
7
2
3
4
5
6
7
- Son.vue
- 要调用的方法doSth可以卸载setup也可以在methods
<script lang="ts">
import { defineComponent, ref } from "vue";
export default defineComponent({
props: ["name", "values", "sonToFatherEmit", 'handleOk'],
// methods: {
// doSth() {
// console.log('>>>>>>>>>>')
// }
// },
mounted() {
console.log(this.name, this.values);
},
setup(props, ctx) {
const doSth = () => {
console.log('>>>>>>>>>>')
}
const value = ref<string>("");
onMounted(() => {
console.log(props);
});
const clicks = () => {
ctx.emit("sonToFatherEmit", "xxxxxxxxxxx");
props.handleOk('ccccccccc')
};
return {
value,
clicks,
doSth
};
},
});
</script>
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
33
34
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
33
34
# 状态管理pinia
- main.ts
app.use(createPinia())
1
- /src/store
- 定义一个use的 useCounterStore 直接 使用 `const counter: A =
- 异步同步函数都写在action里 useCounterStore()`
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', {
state: () => {
return { count: 111111 }
},
// could also be defined as
// state: () => ({ count: 0 })
actions: {
increment() {
this.count++
},
getData() {
return new Promise((resolve: any, reject: any) => {
resolve([
{
id: 1,
name: 'tom',
age: 18
},
{
id: 2,
name: 'jerry',
age: 14
},
{
id: 3,
name: 'spark',
age: 22
}
])
})
}
},
})
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
33
34
35
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
33
34
35
# pinia更新数据this.$patch
// @ts-check
import { defineStore, acceptHMRUpdate } from 'pinia'
/**
* Simulate a login
* @param {string} a
* @param {string} p
*/
function apiLogin(a, p) {
if (a === 'ed' && p === 'ed') return Promise.resolve({ isAdmin: true })
if (p === 'ed') return Promise.resolve({ isAdmin: false })
return Promise.reject(new Error('invalid credentials'))
}
export const useUserStore = defineStore({
id: 'user',
state: () => ({
name: 'Eduardo',
isAdmin: true,
}),
actions: {
logout() {
this.$patch({
name: '',
isAdmin: false,
})
// we could do other stuff like redirecting the user
},
/**
* Attempt to login a user
* @param {string} user
* @param {string} password
*/
async login(user, password) {
const userData = await apiLogin(user, password)
this.$patch({
name: user,
...userData,
})
},
},
})
if (import.meta.hot) {
import.meta.hot.accept(acceptHMRUpdate(useUserStore, import.meta.hot))
}
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# watch监听 数据
- watch监听到ref reactive数据
- watchEffect会自动检测你的数据但不能拿到oldValue
# 这四种结果一样 > 都会在onMounted后首次执行导致多次请求!!!! 而且新旧值相同
#
// 侦听getter 函数 需要加deep: true才能和下方一样 否则不生效
watch(() => paginationPar, (val, oldValue) => {
console.log(2222222,val, oldValue)
}, { deep: true })
// 普通引用对象
watch(paginationPar, (val, oldValue) => {
console.log(2222222,val, oldValue)
})
// 放进数组的方式 侦听getter 函数 需要加deep: true才能和下方一样 否则不生效
watch(() => [paginationPar], ([val]) => {
console.log(2222222,val)
}, {deep: true})
// 放进数组的方式 会首次执行
watch([paginationPar], ([val]) => {
console.log(2222222,val)
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 侦听引用对象的一个变化值 监听不到值情况 (可以改成侦听getter 函数)
// 侦听引用对象的一个变化值 ts报错 原因可能是watch只能侦听响应式数据源 加不加deep: true ts都报错 而且监听不到值
watch(paginationPar.current, (val, oldValue) => {
console.log(2222222,val, oldValue)
}, {deep: true})
// 放入数组一样监听不到值
watch([paginationPar.current], (val, oldValue) => {
console.log(2222222,val, oldValue)
})
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# getter函数方式侦听引用对象的一个变化值 以下两种都可以拿到新旧值!!!
watch(() => paginationPar.current, (val, oldValue) => {
console.log(2222222,val, oldValue)
})
watch(() => [paginationPar.current], ([val], [oldValue]) => {
console.log(2222222,val, oldValue)
})
1
2
3
4
5
6
2
3
4
5
6
# 侦听多个引用对象的一个变化值 都可以拿到新旧值!!!
// 标准写法
watch(() => [paginationPar.current, paginationPar.pageSize], ([val1, val2], [oldValue1,oldValue2]) => {
console.log(2222222,val1, val2,oldValue1,oldValue2)
})
// 这样无论怎么样都拿不到值
watch([paginationPar.current, paginationPar.pageSize], ([val1, val2], [oldValue1,oldValue2]) => {
console.log(2222222,val1, val2,oldValue1,oldValue2)
})
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# 结论:
- 侦听引用对象时: 可能会因为首次运行导致多次请求, { deep: true }仅仅适用于侦听某一个对象 不能拿到新旧值,发现是相同的
- 侦听引用对象的一个变化值时: 需要在一个getter函数内 否则不生效 不会导致多次请求 能拿到新旧值
const values = ref(666);
watch(values, (newValue, oldValue) => {
console.log('侦听器>>>>', newValue, oldValue)
})
watchEffect(() => {
console.log(counter.count)
})
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# JSX写法
安装import vueJsx from '@vitejs/plugin-vue-jsx'
像使用vue()一样在plugins使用
plugins: [
Vue({
include: [/\.vue$/, /\.md$/],
reactivityTransform: true,
}),
vueJsx(),
]
1
2
3
4
5
6
7
2
3
4
5
6
7
import { Breadcrumb, BreadcrumbItem, Button } from "ant-design-vue";
import { defineComponent, onMounted, withModifiers } from "vue";
import { fetchGetCommunity } from "~/services/text";
import { useCounterStore } from '~/store/counter'
import axios from '../utils/http'
const Text = defineComponent({
setup() {
const count = ref(0);
const counter = useCounterStore();
const inc = () => {
count.value++;
};
/**
*
*/
const getCommunity = async () => {
const res = await fetchGetCommunity();
};
onMounted(() => {
});
return () => (
<Breadcrumb>
<BreadcrumbItem>Home</BreadcrumbItem>
<BreadcrumbItem>
<a onClick={getCommunity}>Application Center</a>
</BreadcrumbItem>
<BreadcrumbItem>
<a onClick={inc}>111{{ count }}</a>
</BreadcrumbItem>
<BreadcrumbItem>An Application</BreadcrumbItem>家中有事,请假三天
</Breadcrumb>
);
},
});
export default Text;
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
33
34
35
36
37
38
39
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
33
34
35
36
37
38
39
# 注意
- 引入文件需要带.vue
- ref 的值可以在template直接{{}} 用 但是在script要 .value拿到
- pinia 最后可能需要这个来触发热更新
if (import.meta.hot) import.meta.hot.accept(acceptHMRUpdate(useUserStore, import.meta.hot))
- 最好使用最新的
<script lang="ts" setup> </script>
尽量抛弃vue2的写法