06 - Vue3 UI Framework - Dialog 组件
做完按钮之后,我们应该了解了遮罩层的概念,接下来我们来做
Dialog组件!返回阅读列表点击 这里
需求分析
- 默认是不可见的,在用户触发某个动作后变为可见
- 自带白板卡片,分为上中下三个区域,分别放置标题、内容、操作
- 有两个基本操作:确定、取消
- 卡片后应放置淡黑色遮罩层,遮住原本网页内容
- 可以自定义是否允许取消
- 右上角提供小叉叉来允许关闭
- 允许通过点击遮罩层来关闭
所以,我们能够得出如下的参数表格
| 参数 | 含义 | 类型 | 可选值 | 默认值 |
|---|---|---|---|---|
| visible | 是否可见 | boolean | false / true | false |
| title | 标题 | string | 任意字符串 | 必填 |
| ok | 确定回调 | ()=>boolean | 返回 boolean 的函数 | ()=>true |
| cancel | 取消回调 | ()=>boolean | 返回 boolean 的函数 | ()=>true |
注意:可以通过设置返回值为 true 来允许事件发生,反之不允许。可以通过设置返回 false 来取消事件
骨架
我们复用之前做好的
Button组件
一般情况下,我们不希望对话框弹窗在 DOM 树上的位置,而希望是 body 的直接子元素,那么我们可以使用 vue3 的 teleport 组件。
代码如下:
<template>
<template v-if="visible">
<teleport to="body">
<div class="jeremy-dialog-overlay" @click="close"></div>
<div class="jeremy-dialog">
<header class="jeremy-dialog-header">
{{ title }}
<span class="jeremy-dialog-close" @click="close"></span>
</header>
<div class="jeremy-dialog-divider" />
<main class="jeremy-dialog-main">
<slot></slot>
</main>
<div class="jeremy-dialog-divider" />
<footer class="jeremy-dialog-footer">
<jeremy-button level="plain" @click="close">取消</jeremy-button>
<jeremy-button @click="task" :loading="loading">确定</jeremy-button>
</footer>
</div>
</teleport>
</template>
</template>
这样,在渲染时,teleport 内部的内容就会出现在 body 的子级上。
功能
现在 ts 中声明参数:
declare const props: {
visible: boolean;
title: string;
ok: () => boolean;
cancel: () => boolean;
};
declare const context: SetupContext;
然后在 export default 中,写入我们的参数:
export default {
install: function (Vue) {
Vue.component(this.name, this);
},
name: "JeremyDialog",
props: {
visible: {
type: Boolean,
default: false,
},
title: {
type: String,
required: true,
},
ok: {
type: Function,
default: () => {
return true;
},
},
cancel: {
type: Function,
default: () => {
return true;
},
},
},
components: {
JeremyButton,
},
};
再补全 setup 方法,此处选用 Promise 制造提交等待响应的感觉
setup(props, context) {
const loading = ref(false);
const close = () => {
if (loading.value) {
return;
}
new Promise((resolve, reject) => {
resolve(props.cancel());
}).then((result) => {
if (result !== false) {
context.emit("update:visible", false);
}
});
};
const task = () => {
new Promise((resolve, reject) => {
loading.value = true;
resolve(props.ok());
}).then((result) => {
if (result === true) {
loading.value = false;
context.emit("update:visible", false);
}
});
};
return { loading, close, task };
},
样式表
最后再补全样式表:
<style lang="scss">
.jeremy-dialog-overlay {
z-index: 20;
position: fixed;
left: 0;
top: 0;
background: fade-out($color: #000000, $amount: 0.7);
width: 100vw;
height: 100vh;
}
.jeremy-dialog {
z-index: 20;
position: fixed;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
min-width: 300px;
min-height: 200px;
border-radius: 8px;
background: white;
display: flex;
flex-direction: column;
> * {
padding: 8px;
}
> .jeremy-dialog-divider {
border: 1px solid #8c6fef;
padding: 0;
}
> .jeremy-dialog-header {
display: flex;
justify-content: space-between;
> .jeremy-dialog-close {
position: relative;
display: inline-block;
width: 16px;
height: 16px;
cursor: pointer;
&::before,
&::after {
content: "";
position: absolute;
height: 1px;
background: black;
width: 100%;
top: 50%;
left: 50%;
}
&::before {
transform: translate(-50%, -50%) rotate(-45deg);
}
&::after {
transform: translate(-50%, -50%) rotate(45deg);
}
}
}
> .jeremy-dialog-main {
flex-grow: 1;
background: white;
}
> .jeremy-dialog-footer {
display: flex;
justify-content: flex-end;
}
}
</style>
一行代码打开
多数时候我们是不希望使用组件式的,而是直接用函数生成一个弹窗。那么,我们只要使用 vue3 提供的 createApp 和 h 函数就可以做到了。
我们再创建一个 ts 文件,即 createDialog.ts ,代码如下:
import { createApp, h } from 'vue'
import JeremyDialog from './Dialog.vue'
export const createDialog = options => {
const { title, content, ok, cancel } = options
const div = document.createElement('div')
document.body.appendChild(div)
const close = () => {
app.unmount(div)
div.remove()
}
const app = createApp({
render() {
return h(JeremyDialog, {
visible: true,
'onUpdate:visible': newVisible => {
if (newVisible === false) {
close();
}
},
title,
ok, cancel
}, { default() { return content } })
}
})
app.mount(div)
}
然后再需要使用的地方导入即可:
import {createDialog} from './createDialog.ts'
注意:该函数要求传入一个 options 对象,该对象包含 title, content, ok, cancel 等 4 个部分,content 指代组件式中的插槽,其余含义见需求分析
然后使用 h 函数渲染新 app 中的内容,并作为参数传入 createApp 函数用以创建新的 app,最后挂载到 DOM 树上。
运行效果
接下来,我们将组件引入到页面中,看一下实际运行效果

感谢阅读
06 - Vue3 UI Framework - Dialog 组件的更多相关文章
- 05 - Vue3 UI Framework - Button 组件
官网基本做好了,接下来开始做核心组件 返回阅读列表点击 这里 目录准备 在项目 src 目录下创建 lib 文件夹,用来存放所有的核心组件吧.然后再在 lib 文件夹下创建 Button.vue 文件 ...
- 08 - Vue3 UI Framework - Input 组件
接下来再做一个常用的组件 - input 组件 返回阅读列表点击 这里 需求分析 开始之前我们先做一个简单的需求分析 input 组件有两种类型,即 input 和 textarea 类型 当类型为 ...
- 09 - Vue3 UI Framework - Table 组件
接下来做个自定义的表格组件,即 table 组件 返回阅读列表点击 这里 需求分析 开始之前我们先做一个简单的需求分析 基于原生 table 标签的强语义 允许用户自定义表头.表体 可选是否具有边框 ...
- 10 - Vue3 UI Framework - Tabs 组件
标签页是非常常用的组件,接下来我们来制作一个简单的 Tabs 组件 返回阅读列表点击 这里 需求分析 我们先做一个简单的需求分析 可以选择标签页排列的方向 选中的标签页应当有下划线高亮显示 切换选中时 ...
- 11 - Vue3 UI Framework - Card 组件
卡片是非常常用也是非常重要的组件,特别是在移动端的众多应用场景中,随便打开一个手机 App ,您会发现充斥着各种各样的卡片. 所以,我们也来制作一个简易的 Card 组件 返回阅读列表点击 这里 需求 ...
- 00 - Vue3 UI Framework - 阅读辅助列表
阅读列表 01 - Vue3 UI Framework - 开始 02 - Vue3 UI Framework - 顶部边栏 03 - Vue3 UI Framework - 首页 04 - Vue3 ...
- 04 - Vue3 UI Framework - 文档页
官网的首页做完了,接下来开始做官网的文档页 返回阅读列表点击 这里 路由设计 先想想我们需要文档页通向哪些地方,这里直接给出我的设计: 所属 子标题 跳转路径 文件名(*.vue) 指南 介绍 /do ...
- 01 - Vue3 UI Framework - 开始
写在前面 一年多没写过博客了,工作.生活逐渐磨平了棱角. 写代码容易,写博客难,坚持写高水平的技术博客更难. 技术控决定慢慢拾起这份坚持,用作技术学习的阶段性总结. 返回阅读列表点击 这里 开始 大前 ...
- 12 - Vue3 UI Framework - 打包发布
基础组件库先做到这个阶段,后面我会继续新增.完善 接下来,我们对之前做的组件进行打包发布到 npm 返回阅读列表点击 这里 组件库优化 通用层叠样式表 我想大家都注意到了,前面我们在写组件的时候,sc ...
随机推荐
- 算法学习->整数拆分问题
动态规划典型题目/ 00 题目 将正整数n无需拆分为最大数为k的拆分方案有多少种?要求所有的拆分方案不重复. 示例: 输入:n=5,k=5 输出:(5,5)=7 示例分析: 5=5 5=4+1 5= ...
- [cf1137F]Matches Are Not a Child's Pla
显然compare操作可以通过两次when操作实现,以下仅考虑前两种操作 为了方便,将优先级最高的节点作为根,显然根最后才会被删除 接下来,不断找到剩下的节点中(包括根)优先级最高的节点,将其到其所在 ...
- [loj3341]时代的眼泪
题意即求在区间$[l,r]$中且权值在$[x,y]$中的逆序对个数 考虑分块,逆序对个数包含4部分: 1.左/右块外内部,预处理出$i$到其所在块的块首/尾,小于/小于等于$j$(需要对$j$离散)的 ...
- git不显示提交代码
今天提交代码找不到提交的具体代码,找了好半天,最后发现是右边能下拉能拉下去,尴尬.
- Promise(resolve,reject)的基本使用
什么是Promise? Promise是一个构造函数,其原型上有 then.catch方法,还有reslove,reject等静态方法.通过创建Promise实例,可以调用Promise.protot ...
- 【2020-8-21】【数字游戏】【启发式搜索IDA*】
有这么一个游戏: 写出一个1-N的排列a[i],然后每次将相邻两个数相加,构成新的序列,再对新序列进行这样的操作,显然每次构成的序列都比上一次的序列长度少1,直到只剩下一个数字位置.下面是一个例子: ...
- 洛谷 P4887 -【模板】莫队二次离线(第十四分块(前体))(莫队二次离线)
题面传送门 莫队二次离线 mol ban tea,大概是这道题让我第一次听说有这东西? 首先看到这类数数对的问题可以考虑莫队,记 \(S\) 为二进制下有 \(k\) 个 \(1\) 的数集,我们实时 ...
- LeeCode刷题笔记
(本来想在LeeCode题目页面上做注释的,结果没找到位置,只好来这里了) 字符串部分: 14.最长公共前缀:编写一个函数来查找字符串数组中的最长公共前缀. 示例 1: 输入: ["flow ...
- 【GS应用】基因组选择在杂交玉米上的应用示例
目录 GS两步走 示例 缩短周期和成本 分类 杂交类型 试验研究 选择响应 选择的强度 选择的周期 预测能力 数据分析的注意事项 GS实施 优缺点 GS的成功 展望 GS两步走 示例 缩短周期和成本 ...
- EXCEL ctrl+e 百变用法不只是你用的那么简单
Excel2013版本中,新增加了一个快捷键:Ctrl+E,可以依据字符之间的关系,实现快速填充功能.一些需要使用公式或者其他功能进行解决的问题,现在只要一个快捷键就可以实现了. 用法1:快速拆解出需 ...