最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • Vue: 造轮子-04:Dialog组件

    正文概述 掘金(卷心菜wanwan)   2021-06-29   369

    Vue: 造轮子-04:Dialog组件

    需求分析

    • 点击后弹出
    • 有遮罩层 overlay
    • 有 close 按钮
    • 有标题
    • 有内容
    • 有 yes / no 按钮
    1. 期望效果
    <Dialog 
      visible
      
      @yes="fn1" @no="fn2"
    ></Dialog>
    
    

    支持visible属性

    1. 注意不要用show表示是否可见
    2. 创建dialog.vue和dialogDemo.VUE
    • dialog.vue

    overlay:笼罩层。wrapper:主体

    <template>
        <div class="dialog-overlay"></div>
        <div class="dialog-wrapper">
            <header>标题</header>
            <main>
                <p>1</p>
                <p>2</p>
            </main>
            <footer>
                <Button>ok</Button>
                <Button>cancel</Button>
            </footer>
        </div>
    </template>
    

    dialog组件接受props:visible变量,用v-if判断是否显示。

    让dialog可以点击关闭

    1. 注意不能通过修改 props.visible控制。不能直接改props
    2. 在dialog里添加close事件,用户点击触发。

    dialog.VUE

     const close=()=>{
                    context.emit('update:visible',false)
                }
    

    dialogDemo.vue

    <Dialog :visible="x" @update:visible = "x = $event"></Dialog>
    // :visible= 和 @update:visible=可以合并为 v-model:visible=
    <Dialog v-model:visible="x" ></Dialog>
    
    1. 如果想点击dialog黑色遮罩层时也关闭,只需要在遮罩层上也加上@click="close"即可。 但是这样体验不好(用户有时可能不小心就点到了黑色部分,就关闭了),所以可以新加一个props:closeOnClickOverlay

    dialog-template

     <div class="gulu-dialog-overlay" @click="closeOnClickOverlay"></div>
    

    dialog-script

     props:{
                visible:{
                    type:Boolean,
                    default: false
                },
                closeOnClickOverlay:{ // 是否点击遮罩层关闭,默认是
                    type:Boolean,
                    default:true
                },
              
            },
      setup(props,context){
        const close=()=>{
            context.emit('update:visible',false)
        }
        const closeOnClickOverlay=()=>{
            if(props.closeOnClickOverlay ){ // 如果开启了这个功能,才调用close,否则就什么都不做。
                close()
            }
        }
      
        return {close,closeOnClickOverlay}
    }
    
    1. 点击cancel和ok
    • cancel触发cancel事件(f2),ok触发ok事件(f1)。
    • dialogDemo给dialog传f1和f2事件,dialog接受props,类型是Function
    • ok
     const ok=()=>{
                  if(props.ok && props.ok()!==false){ //如果ok存在,且ok执行后的结果不是false.新写法: props.ok ?.()!==false
                      close()
                  }
                }
    
    • cancel
     const cancel=()=>{
                    context.emit('cancel')
                    close()
    
                }
    
    1. 点击关闭代码
    • dialogDemo
    <Dialog v-model:visible="x" :ok="f1" :cancel="f2"></Dialog>
    
    export default {
            name: "DialogDemo",
            components:{Dialog,Button},
            setup(){
                const x =ref(false)
                const toggle = ()=>{
                    console.log(x)
                    x.value =!x.value
                }
                const f1=()=>{
                    return true
                }
                const f2=()=>{
                }
                return {x,toggle,f1,f2}
            }
        }
    
    • dialog.vue
    <template>
        <template v-if="visible">
        <div class="gulu-dialog-overlay" @click="closeOnClickOverlay"></div>
        <div class="gulu-dialog-wrapper">
            <div class="gulu-dialog">
            <header>标题
                <span @click="close" class="gulu-dialog-close"></span>
            </header>
            <main>
                <p>1</p>
                <p>2</p>
            </main>
            <footer>
                <Button @click="ok">ok</Button>
                <Button @click="cancel">cancel</Button>
            </footer>
            </div>
        </div>
        </template>
    
    </template>
    
    <script lang="ts">
        import Button from './button.vue'
        export default {
            name: "dialog",
            components:{Button},
            props:{
                visible:{
                    type:Boolean,
                    default: false
                },
                closeOnClickOverlay:{
                    type:Boolean,
                    default:true
                },
                ok:{
                    type:Function
                },
                cancel:{
                    type:Function
                }
            },
            setup(props,context){
                const close=()=>{
                    context.emit('update:visible',false)
                }
                const closeOnClickOverlay=()=>{
                    if(props.closeOnClickOverlay ){
                        close()
                    }
                }
                const cancel=()=>{
                    context.emit('cancel')
                    close()
    
                }
                const ok=()=>{
                  if(props.ok && props.ok()!==false){ //新写法: props.ok ?.()!==false
                      close()
                  }
    
                }
                return {close,closeOnClickOverlay,cancel,ok}
            }
        }
    </script>
    

    支持title和content

    1. 使用插槽
    • dialogDemo
     <Dialog v-model:visible="x" :ok="f1" :cancel="f2">
            <template v-slot:content>
                <div>hi</div>
            </template>
            <template v-slot:title>
                <strong>加醋的title</strong>
            </template>
    
        </Dialog>
    
    • dialog
    <template>
        <template v-if="visible">
        <div class="gulu-dialog-overlay" @click="closeOnClickOverlay"></div>
        <div class="gulu-dialog-wrapper">
            <div class="gulu-dialog">
            <header>
                <slot name="title"></slot>
                <span @click="close" class="gulu-dialog-close"></span>
            </header>
            <main>
                <slot name="content"></slot>
            </main>
            <footer>
                <Button @click="ok">ok</Button>
                <Button @click="cancel">cancel</Button>
            </footer>
            </div>
        </div>
        </template>
    
    </template>
    
    • 语法:
    // 外面
     <template v-slot:content></template>
     // 里面
      <main>
                <slot name="content"></slot>
      </main>
    

    把dialog移动到body下面

    1. 为什么要放到body下面: 防止dialog被遮挡。
    2. 注意堆叠上下文
    3. 使用新组建:Teleport
    • 自带组件,不用引入
    • 作用: 把里面的东西放到body下面。
    • dialog.vue
    <template>
        <template v-if="visible">
            <Teleport to="body">
                <div class="gulu-dialog-overlay" @click="closeOnClickOverlay"></div>
                <div class="gulu-dialog-wrapper">
                    <div class="gulu-dialog">
                        <header>
                            <slot name="title"></slot>
                            <span @click="close" class="gulu-dialog-close"></span>
                        </header>
                        <main>
                            <slot name="content"></slot>
                        </main>
                        <footer>
                            <Button @click="ok">ok</Button>
                            <Button @click="cancel">cancel</Button>
                        </footer>
                    </div>
                </div>
            </Teleport>
    
        </template>
    
    </template>
    
    

    一句话打开 Dialog

    1. 我不想声明 visible 变量,然后改变它的值
    2. 技术点:动态挂载组件
    3. 希望ooutput
    <Button @click="showDialog">showDialog</Button>
    
    
    const showDialog=()=>{
                    openDialog({
                        title:'标题',
                        content:'HELLO',
                        ok(){
                            console.log('ok')
                        },
                        cancel(){
                            console.log('cancel')
                        }
                    })
                }
    
    1. 新建openDialog.ts
    import Dialog from './dialog.vue'
    import {createApp,h} from 'vue'
    export const openDialog = (options)=>{
        const {title, content,ok,cancel} = options
        const div = document.createElement('div')
        document.body.appendChild(div) //创建一个div,并且放到body里面。
        const close = ()=>{
            app.unmount(div)
            div.remove()
        }
        const app = createApp({
            render(){
                return h(Dialog,{visible:true, // 在渲染dialog的时候,传visible:true
                    'onUpdate:visible':(newVisible)=>{ // 关闭,visible
                    if(newVisible ===false){
                        close()
                      }
                    },
                    ok,cancel},{
                    title:title,
                    content:content
                })
            }
         })
         app.mount(div) // 把dialog放到div里面
    }
    

    起源地下载网 » Vue: 造轮子-04:Dialog组件

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元