V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
wunonglin
V2EX  ›  Vue.js

终于把 Vue 的 Dialog 给整舒服了

  •  1
     
  •   wunonglin · 2022-08-11 15:26:06 +08:00 · 1204 次点击
    这是一个创建于 596 天前的主题,其中的信息可能已经有所发展或是发生改变。

    目前流行的弹窗,不管是

    <dialog visible="visible">
    	<user-dialog />
    </dialog>
    

    还是

    <template>
        <dialog visible="visible"></dialog>
    </template>
    <script>
    	visible = false
        open(){
        	this.visible = true
        }
        close(){
        	this.visible = true
        }
    </script>
    

    都难受至极。

    第一种写法

    • 在使用 dialog 的时候,dialog 就已经加载好了,但是我还不需要,所以造成不必要的资源浪费(可忽略),以及在代码里看着这堆东西太不优雅了
    	<dialog ref="dialog1" :visible="dialog1" />
    	<dialog ref="dialog2" :visible="dialog2" />
    	<dialog ref="dialog3" :visible="dialog3" />
    	<dialog ref="dialog4" :visible="dialog4" />
    	......
    
    • visible 会留在调用组件里,调用者有 N 个 dialog 就有 N 个变量
    data(){
    	return {
    		dialog1: false,
    		dialog2: false,
    		dialog3: false,
    		......
    	}
    }
    
    • 想在关闭 dialog 的时候做一些事情很难受,要么 watch dialog1~N 这个变量,要么给所有 dialog 写<dialog @close="close" />
    • 在关闭弹窗时,接收返回的变量很难受
      <dialog :visible.sync="visible">
      	<user-dialog @close="close" />
      </dialog>
      
      data(){
      	return {
      		visible: true
      	}
      }
      
      close(event){
      	console.log(event)
      	this.visible = false
      }
      

    第二种写法

    • 一旦引入组件,组件便开始 mount 了,生命周期也执行了,如果调用者引入了 N 个 dialog ,那性能可想而知,还不如第一种写法

    • 因失去了生命周期的特性,导致关闭弹窗的时候需要你自己重置数据,做清理

    • 而且你开不能利用生命周期来做数据加载,因为你还没打开弹窗,90%的业务场景是没必要加载数据的,所以你还要在 open 里自己加载

    • 还有一些问题我暂时想不起来,先略吧

    忍了好久了,终于把 https://material.angular.io/components/dialog/overview 的 dialog 给挪过来了,所说不太完美,但是至少满足我的痛点了。

    使用文档可以看我写的demo,API 参考的话可以看Dialog | Angular Material

    各位如果也有同样的痛苦的话,可以 fork 到自己项目里去改一下就可以用了。

    写得不是很完美,仅作为一个想法、思路。

    ps:真的想吐槽手动初始化 Vue 这个过程,难受至极,离开了文档的操作,啥也不是。

    swordne
        1
    swordne  
       2022-08-11 16:18:22 +08:00
    vant 的 dialog 还行啊。
    wunonglin
        2
    wunonglin  
    OP
       2022-08-11 16:24:48 +08:00
    @swordne #1 vant 的调用的方式,还是没逃脱我上文说的这两种写法
    corcd
        3
    corcd  
       2022-08-15 03:35:17 +08:00 via iPhone
    你可以挂 ref 然后把 visible 状态维持在 dialog 内部,用 open 和 close 方法去修改 visible 就好了,就是不太符合数据驱动的思路
    wunonglin
        4
    wunonglin  
    OP
       2022-08-15 03:43:42 +08:00
    @corcd #3 你这种就是我列出的第二种写法,弊端我上文写了。还是没人能跳出这两种思路
    gausszhou
        5
    gausszhou  
       2022-08-16 09:49:57 +08:00
    我这之前是直接用了 v-if 了, 然后 在 dialog 内 created 和 mounted 进行 接口数据调用和 ref 操作 /(ㄒoㄒ)/~~
    chenjiangui998
        6
    chenjiangui998  
       2022-08-28 01:59:27 +08:00
    直接用 v-if 代替 visible 啊, 关闭直接 emit('close'), 不用管是否实际关闭
    wunonglin
        7
    wunonglin  
    OP
       2022-08-28 03:09:56 +08:00
    @chenjiangui998 #6

    这么做的话其实和上述第一种写法没什么区别。

    假设 A 里面有 B ,C 两个 dialog:

    传值的的时候在 A 里定义一个变量去传递给下级,有 N 个 dialog 就会有 N 个变量,不优雅且难管理。

    假如 B ,C 两个都是使用同一个变量的话,加上 ts 的话这个变量定义会变得又臭又长,例如 dialogData: TypeB | TypeC | .... = null ,你需要手动管理这个变量,用起来也会很糟心。

    其实作为初始化 dialog 的 data 是没必要在当前组件定义变量的,太啰嗦了。

    接收 dialog 事件的问题如上。

    -----------

    我目前接手过的 vue 项目 100%都是上述两种写法,如果写的人有心去写好的话,那也问题不大(也难受就是了),但不知道什么原因,每个地方都是写的流水账一样,一个 dialog 有 n 个需要传递的变量,还有 n 个接收 event 的方法,还没类型,全写在父组件上,父组件还不只一个 dialog ,不知道是不是 vue 就是推崇这种写法的还是怎么的,看到 vue 主流的的 ui 都是这样的

    -----------

    你可以看下 https://material.angular.io/components/dialog/overview ,做的很优雅,对你应该挺有帮助的
    chenjiangui998
        8
    chenjiangui998  
       2022-08-28 14:14:43 +08:00
    @wunonglin 看了, 这个相当于实现了个公用 dialog, 切换内部内容, 而且要用 rxjs 和事件驱动, 我觉得不如直接状态驱动简单干脆,
    ```
    const dialog = {
    show: true,
    components: 'xxx1',

    }

    <dialog :visible="dialog.show">
    <component></component>
    </dialog>

    ```
    chenjiangui998
        9
    chenjiangui998  
       2022-08-28 14:16:53 +08:00
    @wunonglin
    看了, 这个相当于实现了个公用 dialog, 切换内部内容, 而且要用 rxjs 和事件驱动, 我觉得不如直接状态驱动简单干脆,
    ```
    const dialog = {
    show: true,
    components: 'xxx1',
    props: {}
    }

    <dialog :visible="dialog.show" @close="xxx">
    <component :is="dialog.components" v-bind="props"></component>
    </dialog>

    ```
    刚回车了, 我觉得这个和你发的那个没啥区别, 而且还是状态驱动的
    wunonglin
        10
    wunonglin  
    OP
       2022-08-28 14:18:07 +08:00
    @chenjiangui998 #8 确实是简单了。不过太不优雅了
    wunonglin
        11
    wunonglin  
    OP
       2022-08-28 14:21:32 +08:00
    @chenjiangui998 #9 目前我在公司内部用着我写的这个了,体验和 ng 的一样,还不错。后面打算去掉 element ,自己实现个 layout 层,这样体验会更好
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   3592 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 10:29 · PVG 18:29 · LAX 03:29 · JFK 06:29
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.