请教一个 vue 中组件复用的问题

2022-09-27 16:33:28 +08:00
 yezheyu

如何让复用的组件内部代码随着切换多次执行呢?

App.vue 组件:有两个按钮,点击按钮下面 div 显示对应按钮中的文字

<template>
    <button @click="changeData($event)">user1</button>
    <button @click="changeData($event)">user2</button>
    <User :name="data"></User>
</template>

<script setup>
    import { ref } from 'vue';
    import User from './components/user.vue';
    let data = ref('')

    function changeData(e) {
        data.value = e.target.innerText
    }
</script>

User.vue 组件:

<template>
    <div> {{ name }} </div>
    <!-- <div> {{ attrs.name }} </div> -->
</template>

<script setup>
    import { useAttrs } from 'vue';
    let attrs = useAttrs()
    let name = attrs.name
    console.log(name);
</script>

User 组件内部的代码只会执行一次,`console.log` 不会随着 button 的点击事件执行多次,不符合预期

如果在 template 中直接使用 attrs.name 是没问题的,不会丢失响应式

如果使用变量 name 接收,因为组件内部代码只执行一次的缘故,就不能实现切换文字效果

如何才能让 User 组件内部的代码随着 button 点击多次执行呢?

2024 次点击
所在节点    程序员
23 条回复
sunny1688
2022-09-27 16:35:40 +08:00
定义 props
optional
2022-09-27 16:41:09 +08:00
name 定义成 computed
musi
2022-09-27 16:42:39 +08:00
props + watch
cydysm
2022-09-27 16:45:37 +08:00
凑活看吧
<template>
<div> {{ name }} </div>
</template>

<script setup>
import {watch} from 'vue'
let props = defineProps({
name:String
})
watch(props.name, (val) => {
console.log(val)
})
</script>
HugoChao
2022-09-27 16:49:25 +08:00
看了半天都怀疑自己有没有学 vue 了,发现是 vue3 语法
EyebrowsWhite
2022-09-27 16:51:39 +08:00
接 4 楼, 可以不用 watch, 用 toRef 或者 toRefs,
`const name = toRef(props, 'name')`
EyebrowsWhite
2022-09-27 16:53:20 +08:00
额, 好吧, 没看清楚, 如果要是想运行 console 的话, 还是要 watch 的
vinsony
2022-09-27 16:53:20 +08:00
<User :name="data" :key="data" />
yezheyu
2022-09-27 16:54:30 +08:00
@cydysm
@EyebrowsWhite

就是说把需要变化的逻辑写在 watch 中是吗
EyebrowsWhite
2022-09-27 16:57:40 +08:00
@yezheyu 是的,如果你想在某个值变化之后执行一些逻辑,那么这些逻辑要写在 watch 里面
cydysm
2022-09-27 16:57:50 +08:00
@yezheyu setup 简单理解取代了 beforecate 和 created ,只会触发一次
你写成选项式,就明白了
export default defineComponent({
setup(){},
mounted(){}
})
setup 中只会走一次 mounted 也是
yezheyu
2022-09-27 16:59:22 +08:00
@vinsony
好使,多谢

能稍微解释下吗
cydysm
2022-09-27 17:03:01 +08:00
@yezheyu #8 加 key 属性,每次只要变了都会认为是一个新的组件 而不是复用
在这个基础上的话 我觉得 key 可以改成 symbol
cydysm
2022-09-27 17:04:07 +08:00
yezheyu
2022-09-27 17:09:56 +08:00
@cydysm
多谢老哥,明白了
bebop
2022-09-27 18:20:55 +08:00
我觉得最合适的办法是,在 User.vue 中定义一个方法,然后暴露给父组件。父组件每次点击按钮的时候,调用这个方法,把新的数据传递给子组件。
horizon
2022-09-27 20:16:56 +08:00
这明显是 Props 。。
yoghurtoreo
2022-09-27 20:41:55 +08:00
@bebop 俺也觉得🐼
Zzzz77
2022-09-27 21:35:24 +08:00
这就是最基础的父子组件啊,首先 props 的定义是必须的,不理解 OP 为什么会选择用 attrs.name 这种方式来取父组件的值..

其次`User 组件内部的代码只会执行一次,`console.log` 不会随着 button 的点击事件执行多次`,这是当然的,和响应式无关,不管 name 变不变,console.log 肯定都只会执行一次。如果需要在 name 变化时执行一些副作用,watch 是最正统的方式,#8 的方法不建议...#16 的方法可行,但这明显更倾向 React 的思维
yezheyu
2022-09-29 09:59:15 +08:00
@Zzzz77
那复用的组件生成的页面之间不希望有任何的关联,是不是用绑定 key 的方式最合适。

例如有下面一个场景:
user 组件中有个输入框,点击按钮切换页面时,希望表单数据只停留在当前页面,新切换的页面不能包含上一个页面的表单数据。

这种是不是最好就是借助绑定 key 渲染出的页面,同时使用 keepAlive 缓存

`<keep-alive> <User :name="data" :key="data" /> </keep-alive>`

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/883320

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX