比如 dialog 弹框 之前 react 最常见的写法就是传个 visible prop 来空值显示隐藏,vue 也是这么写,后面看别人的代码里经常就 this.$refs.xxxDialog.visible = true
或者 this.$refs.xxxDialog.open()
直接处理子组件的状态,而不是通过传 prop 的方式,我感觉这样写确实更方便。
这种处理方式是不是也比较常见?有没有什么弊端这么写的话
1
wednesdayco 2022-07-22 14:05:00 +08:00
这么写的话耦合就比较严重
|
2
binhb 2022-07-22 14:06:53 +08:00
虽然开了口子, 但是不建议直接操作 dom, 而且这种情况明显不是一定要操作 dom 的
既然用了 vue, 应该要按着 vue 推荐的方式来写吧 |
3
yaphets666 2022-07-22 14:09:06 +08:00
为啥要传进 dialog 来控制 dialog 的显隐? 直接在 dialog 的模板上控制不就行了,当然,也可以传进去。ref 只是处理特殊情况的方法。
|
4
lin07hui 2022-07-22 14:17:04 +08:00
this.$refs.xxxDialog.visible = true 不推荐
this.$refs.xxxDialog.open() 推荐 调用组件方法是常见的,如:this.$refs.form.validate() 最好先看组件文档,如果有方法可调用,一般都会有说明的 |
5
lifesimple OP @binhb 所以这种操作并不是 vue 的最佳实践吧 但是这种操作组件内部的 state 比 prop 要方便点
|
6
wu67 2022-07-22 14:33:40 +08:00 1
调子组件的方法可以. 直接改状态-->打死.
|
7
lifesimple OP @wu67 就比如页面中打开个弹框 A (没写在当前页面的)要么就是当前页面的 visible state 传入弹框组件中展示;还有就是直接在弹框 A 中写个 visible state 来空值,点击打开的时候通过$refs.dialog.visible 直接改变,或者含蓄点就是在弹框 A 中写个 openDialog() { this.visible = true } 然后$refs.dialog.openDialog() 但实际上没啥区别吧,你一般这种会采用哪种方式写呢
|
8
wu67 2022-07-22 14:46:57 +08:00
@lifesimple 你写这一段真的是看了头疼.
首先弹窗必定与当前页面有关, 你能在当前页面打开与当前页面无关的弹窗(除非全局的错误提示之类的), 那叫 bug. 不然就是全局的状态抽屉之类的...这种自然有其包装层的数据和逻辑控制. 其次, 打开弹窗, 你可以直接调里面的 openDialog(). 如果不想调, 就绑状态变量 A 到弹窗组件, 然后组件里面 wath 这个 prop A, 合适的时候更改变量, 真正的 dialog 例如 el-dialog 的显示由变量 B 控制, 而不是直接控制弹窗组件里面的变量. |
9
sjhhjx0122 2022-07-22 14:49:33 +08:00
既然觉得弹窗通过 true false 奇怪,其实不如封装个服务来调用弹窗,把 show 变量隐藏起来
|
10
cyrbuzz 2022-07-22 14:50:37 +08:00
这种方法我个人感觉是最后山穷水尽的方法,不应该首选。
非 props 的东西除非明确在文档里注明,否则应该一律视为私有。 私有内容的改动就不会对外部的调用负责,比如哪一天我去组件里把 visible 的名字改了就改了,不需要让调用者知道,调用者本来也不需要关心。 Vue3 和 React 也是这个思路,通过`defineExpose`和`useImperativeHandle`只暴露出公开方法。 |
11
Terry05 2022-07-22 14:52:03 +08:00
严重不推荐这么用,通常他们这么弄,基本原因只是不想在界面上去多定义一个 visiable 变量
有这样使用习惯的,感觉是还停留在 jquery 的使用习惯上,还没切换到数据驱动的模式上来 通过 ref 去访问组件内部的 method 不到一些特殊需求也是不推荐使用,绝大数情况下通过 props 和 emit 就可以很好的完成功能实现了,就像官方文档里经常提及的,如果这种经典的输入输出不能解决问题,通常情况不是设计出了问题,就是真的需求超级复杂,比如富文本之类 vue2.x 的 option 定义的 methods 默认都可以直接访问到,到了 vue3.x 的 setup 模式下,只有被 expose 的内容才可以被外部访问,或许就并不能直接调用到所有资源了 |
12
Mark85 2022-07-22 14:54:14 +08:00
弹窗与否本来不就是应该交给外部控制的,并同步显示、隐藏状态的吗?还把 visible 隐藏在组件内让人通过 refs 来改显示隐藏,怎么想的,看到`$refs.dialog.openDialog()`这种代码我就想骂
``` // 弹窗组件 props: { visible: { type: Boolean, default: false, }, }, computed: { _visible: { get() { return this.visible }, set(val) { this.$emit('update:visible', val) }, }, }, // 内部操作_visible ``` 外部使用 ``` <dialog :visible.sync="xxxVisible" /> ``` |
13
lifesimple OP @sjhhjx0122 emm 不是这个觉得奇怪,只是讨论对于一个子组件父子组件通信一般都是 props 方式把值传递给子组件,子组件做了什么操作通过$emit 在父组件中改变 prop 值。如果通过$refs.childComp 的方式,可以把这些 props 值全部设置成子组件的 state 值,操作时候可以调用子组件的一个比如 init() 方法 参数就是原本的 props 值,init(a,b,c,d) { this.a = a;this.b = b...} 把值传过去控制。
@cyrbuzz 嗯 有道理 谢谢 |
14
wunonglin 2022-07-22 15:02:58 +08:00
vue 的设计模式决定了只能通过 this.$ref.xxx.open()或者 this.dialog = true 这样打开弹窗。
@sjhhjx0122 #9 我曾经在 vue 里实现了一个和 angular dialog 一样的东西,但是有个很严重的问题,无法将值传递给组件还有弹窗的返回值无法回到调用者的页面。 https://stackblitz.com/edit/vue-ic6mz2?file=src/components/dialog.vue 这个示例的设计逻辑参考 https://material.angular.io/components/dialog/api#MatDialog |
15
Moeyua 2022-07-22 15:09:46 +08:00 via iPhone
Vue 3 子组件需要显式 expose 一些属性后才可以被父组件读取,这种方式应该更合理一些吧。
|
16
sjhhjx0122 2022-07-22 15:12:24 +08:00
@wunonglin 可以啊,创建一个 promise 就 ok 了,我写过一个文章
https://juejin.cn/post/7101144285763862565 ,如果喜欢 ng ,用 rxjs 也可以实现 唯一的缺点是创建的弹窗是重新 new vue 没法使用项目里的上下文依赖 |
17
sjhhjx0122 2022-07-22 15:13:56 +08:00
@lifesimple 那不如通过 provide ,inject 啊
|
18
ipwx 2022-07-22 15:17:23 +08:00
this.$refs.XXX.open() 我觉得没啥毛病。
this.$refs.XXX.visible = true 我觉得有大猫饼 |
19
jrtzxh020 2022-07-22 15:20:40 +08:00
当写了无数个弹窗后,发现用 this.$refs.xxxDialog.open() 真香 哈哈
|
20
wunonglin 2022-07-22 15:31:14 +08:00
@sjhhjx0122 #16
vue3 还没看,弃坑了。专心 ng 了,我这里以 vue2 为例。 @sjhhjx0122 #17 provide ,inject 我记得会有严重问题。如果你是嵌套打开 dialog 的话,依赖注入就不能用了,嵌套的 dialog 不能获取它自己的 ref 。 |
21
lifesimple OP |
22
sjhhjx0122 2022-07-22 15:41:08 +08:00
@wunonglin vue2 也可以的,用 Vue.extend 创建就好了,我也是主用 ng ,依赖注入我还没遇到你说的这个问题
|
23
wangtian2020 2022-07-22 15:56:54 +08:00
我都是这么写的
this.$refs['childDialogComponent'].showAddDialog(params) 调用子组件方法,子组件执行自己的方法修改自身状态 |
24
wunonglin 2022-07-22 16:03:54 +08:00
|
25
sechi 2022-07-22 16:47:37 +08:00
大部分时候都是用 this.$refs.xxxDialog.open(),反正大部分时候都是写 crud 业务,真的没有那么多条条框框,怎么舒服怎么来
|
26
AlphaTr 2022-07-22 18:03:22 +08:00
简单一个调用 result = await this.$refs.dialog.open(params) 直接将给 Dialog 传参数并打开、获取弹窗的返回值都做了;比通过给组件传 props ,然后监听组件的事件这样子分布在各处的方式个人感觉更好些
|
27
snarkprayer 2022-07-22 18:36:50 +08:00
ref 引用读数据调方法可以,写数据应该禁止
$refs.ddialog.open()这种的可以加一层封装 点击 trigger slot 显示 ``` <Extend-Modal> <content-compoennt /> <button slot="trigger">按钮</button> </Extend-Modal> ``` |
28
ymcz852 2022-07-22 19:46:57 +08:00 via iPhone
看那么多人支持 $refs 去调用子组件方法有点惊讶,虽然方便,但个人认为除了用 $refs 去调用第三方组件的方法的场景外,这种方法带来的可维护性肯定不佳的,子组件根本不知道有哪些父组件调用了它的方法,一旦是改动了这些方法就难搞了
|
29
jdi 2022-07-22 20:46:34 +08:00
官方是不推荐的,原来开了个口子,现在把口子缩小了点:
> 使用了 <script setup> 的组件是默认私有的:一个父组件无法访问到一个使用了 <script setup> 的子组件中的任何东西 |
30
humbass 2022-07-22 21:11:02 +08:00 1
如果是 Alert 、Loading... 这样的框,最好是用 extend 封装一层,然后用函数调用,这样就完全解耦了。
vue2 的写法 : https://joyran.github.io/yi-blog/blog/alert.html (随便搜的) |
31
thtznet 2022-07-22 21:48:27 +08:00 1
两种不通的思想,面向对象的写法和数据驱动,Vue 嘛,既然得了 2 者的优势就会有带着 2 者的影子,所以感觉有点不伦不类。
|
32
dengshen 2022-07-23 10:07:07 +08:00 via iPhone
sync 不好用吗?
|
33
xsldebugger0030 2022-07-23 16:13:57 +08:00
@wunonglin vue 的设计模式决定了你有 n 种方式打开弹窗。不需要调内部方法或修改内部属性。直接把 dialog 的 visible 绑定到 prop 里,由父组件控制就好了。
|
34
wunonglin 2022-07-23 16:17:57 +08:00
@xsldebugger0030 #33 笑了
|
35
xsldebugger0030 2022-07-23 16:55:50 +08:00
@wunonglin https://www.v2ex.com/help/assertive
我们希望能够在 V2EX 建立和倡导一种好好说话的氛围。 请尽量描述事实,而非观点。 如果你要反驳什么,请反驳那个主要的要点,而不是一些旁枝末节。 如果你要说的话是为了伤害别人,那么请不要说。如果你要说的话,你有预感在将来你会想要删掉它,那你最好现在就不要说。 在一个公共空间的公共讨论中,我们应该关注的,是自己能够在这些讨论中提供什么样的建设性增益,而不是那些纯粹个人的感受。比如当大家在讨论一件你不了解的东西时,你没有必要去回复一条“不明觉厉”。 回忆一下你看过的电影里的那些正面角色的说话方式——把一件事情好好陈述出来,没有冷笑,没有嘲讽,没有反问,就只是好好说话而已。 |