提交 4e2314a2 编写于 作者: richard_1015's avatar richard_1015

chore: dialog

上级 aec2f726
......@@ -293,7 +293,7 @@
"cName": "对话框",
"desc": "模态对话框,在浮层中显示,引导用户进行相关操作,支持图片对话框。",
"sort": 8,
"show": false,
"show": true,
"author": "dsj"
},
{
......
<template>
<div class="demo">
<h2>基本用法</h2>
<div>
<nut-cell
:is-link="true"
:show-icon="true"
@click="showDialog1"
title="自定义标题和内容"
>
</nut-cell>
<nut-cell
:is-link="true"
:show-icon="true"
@click="showDialog2"
title="只有标题"
>
</nut-cell>
<nut-cell
:is-link="true"
:show-icon="true"
@click="showDialog3"
title="只有内容"
>
</nut-cell>
<nut-cell
:is-link="true"
:show-icon="true"
@click="showDialog4"
title="移除按钮栏"
>
</nut-cell>
<nut-cell
:is-link="true"
:show-icon="true"
@click="showDialog5"
title="事件"
>
</nut-cell>
<nut-cell
:is-link="true"
:show-icon="true"
@click="showDialog6"
title="无弹出动效且关闭时不销毁dislog实例"
>
</nut-cell>
<nut-cell
:is-link="true"
:show-icon="true"
@click="showDialog7"
title="遮罩层透明"
>
</nut-cell>
</div>
<h2>图片弹窗</h2>
<p>
type值为“image”时为图片弹窗,需要配置一张图片,可带链接(非必须)。默认展示关闭按钮。点击图片触发onClickImageLink事件,返回false可阻止默认的跳转链接行为。
</p>
<div>
<nut-cell
:is-link="true"
:show-icon="true"
@click="showImageDialog"
title="图片弹窗"
>
</nut-cell>
</div>
<h2>背景滚动锁定</h2>
<p
>lockBgScroll值设为true时,可在弹窗出现时锁定页面滚动,且不影响窗体内部滚动。</p
>
<div>
<nut-cell
:is-link="true"
:show-icon="true"
@click="showDialog8"
title="背景滚动锁定"
>
</nut-cell>
<nut-cell
:is-link="true"
:show-icon="true"
@click="showDialog9"
title="窗体内部滚动不影响页面滚动"
>
</nut-cell>
</div>
<h2>高级用法</h2>
<p>如果Dialog内容有复杂交互,可使用Dialog的标签式用法。</p>
<div>
<nut-cell
:is-link="true"
:show-icon="true"
@click="dialogShow = true"
title="以标签形式调用Dialog"
>
</nut-cell>
</div>
<!-- 以标签形式调用Dialog -->
<!-- <nut-cell title="基础弹框" @click="baseClick"></nut-cell> -->
<nut-cell title="标签弹框" @click="noTitleClick"></nut-cell>
<nut-dialog
title="标签形式调用"
:visible="dialogShow"
:cancel-auto-close="false"
@ok-btn-click="dialogShow = false"
@cancel-btn-click="dialogShow = false"
@close="dialogShow = false"
title="标签式使用"
:close-on-click-overlay="false"
:content="content"
v-model:visible="visible"
>
<a href="javascript:;" @click="dialogShow = false" :noCancelBtn="true"
>点我可以直接关闭对话框</a
>
</nut-dialog>
<!-- <template v-slot:header>
</template> -->
</div>
</template>
<script lang="ts">
import { reactive, toRefs, createApp } from 'vue';
import { ref, getCurrentInstance } from 'vue';
import { createComponent } from '@/utils/create';
import Dialog from './index';
// 全局注册
const app = createApp({});
app.use(Dialog);
const { createDemo } = createComponent('dialog');
export default createDemo({
props: {},
setup() {
const data = reactive({
dialogShow: false,
isEditor: false,
item: {}
});
function showDialog1() {
const options = {
title: '确定删除此订单?',
content: '删除后将从你的记录里消失,无法找回',
closeOnPopstate: true
};
Dialog(options);
}
function showDialog2() {
const options = {
title: '确定要加入购物车吗?'
};
Dialog(options);
}
function showDialog3() {
const options = {
content: '点击返回将中断注册,确定返回?<br>删除后您可以在回收站还原。',
closeBtn: true,
noOkBtn: true,
cancelBtnTxt: '我知道了'
};
Dialog(options);
}
function showDialog4() {
const options = {
customClass: 'my-dialog',
title: '注册说明',
content:
'原账号为您本人所有,建议直接登录或找回密码。原账号内的订单资产可能丢失,可联系京东客服找回。',
closeBtn: true,
noFooter: true
};
Dialog(options);
}
function showDialog5() {
const options = {
okBtnTxt: '好 的',
title: '事件',
content: '点击按钮触发事件',
closeBtn: true,
onOkBtn(event) {
alert('okBtn');
Dialog.close(); //关闭对话框
},
onCancelBtn(event) {
alert('cancelBtn');
//return false; //阻止默认“关闭对话框”的行为
},
onCloseBtn(event) {
alert('closeBtn');
//return false; //阻止默认“关闭对话框”的行为
},
closeCallback(target) {
alert('will close');
}
};
Dialog(options);
}
function showDialog6() {
Dialog({
animation: false, //禁用弹出动效
title: '注册说明',
canDestroy: false,
content:
'原账号为您本人所有,建议直接登录或找回密码。原账号内的订单资产可能丢失,可联系京东客服找回。'
});
}
function showDialog7() {
Dialog({
maskBgStyle: 'rgba(0,0,0,0)', //设置遮罩层背景透明
title: '注册说明',
content:
'原账号为您本人所有,建议直接登录或找回密码。原账号内的订单资产可能丢失,可联系京东客服找回。'
});
}
function showDialog8() {
Dialog({
title: '背景滚动锁定',
lockBgScroll: true,
content:
'弹窗弹出后,页面滚动锁止。在窗体和遮罩层上滑动时,页面不再跟随滚动。',
noOkBtn: true,
cancelBtnTxt: '我知道了',
onCancelBtn() {
Dialog.close();
}
});
}
function showDialog9() {
Dialog({
title: '《桃花行》',
lockBgScroll: true,
content:
'桃花帘外东风软,<br>桃花帘内晨妆懒。<br>帘外桃花帘内人,<br>人与桃花隔不远。<br>东风有意揭帘栊,<br>花欲窥人帘不卷。<br>桃花帘外开仍旧,<br>帘中人比桃花瘦。<br>花解怜人花也愁,<br>隔帘消息风吹透。<br>风透帘栊花满庭,<br>庭前春色倍伤情。<br>闲苔院落帘空卷,<br>斜日栏干人自凭。<br>凭栏人向东风泣,<br>茜裙偷傍桃花立。<br>桃花桃叶乱纷纷,<br>花绽新红叶凝碧。<br>树树烟封一万株,<br>烘照楼台红模糊。<br>天机烧破鸳鸯锦,<br>春色欲酣珊瑚枕。<br>侍女金盆进水来,<br>香泉欲蘸胭脂冷。<br>胭脂鲜艳何相类,<br>花之颜色人之泪。<br>若将人泪比桃花,<br>泪自长流花自媚。<br>泪眼看花泪易乾,<br>泪乾春尽花憔悴。<br>憔悴花枝憔悴人,<br>花飞人倦易黄昏。<br>一声杜宇春归尽,<br>寂寞帘栊空月痕。',
noOkBtn: true,
cancelBtnTxt: '我知道了'
const { proxy } = getCurrentInstance();
const content = ref(
'模态对话框,在浮层中显示,引导用户进行相关操作,支持图片对话框。'
);
const visible = ref(false);
const baseClick = () => {
proxy.$dialog({
title: '基础弹框',
content: '基础弹框内容'
});
}
function showImageDialog() {
Dialog({
type: 'image',
link: 'http://m.jd.com',
imgSrc:
'https://m.360buyimg.com/mobilecms/s750x750_jfs/t1/4875/23/1968/285655/5b9549eeE4997a18c/070eaf5bddf26be8.jpg!q80.dpg',
onClickImageLink() {
return false; //返回false可阻止默认的链接跳转行为
}
});
}
};
const noTitleClick = () => {
visible.value = true;
};
return {
...toRefs(data),
showDialog1,
showDialog2,
showDialog3,
showDialog4,
showDialog5,
showDialog6,
showDialog7,
showDialog8,
showDialog9,
showImageDialog
content,
visible,
baseClick,
noTitleClick
};
}
});
......
# Dialog 对话框
模态对话框,在浮层中显示,引导用户进行相关操作,支持图片对话框。
## 基本用法
### 介绍
```javascript
import Dialog from './index';
// 全局注册
const app = createApp();
app.use(Dialog);
```
```javascript
Dialog({
title: "确定删除此订单?",
content: "删除后将从你的记录里消失,无法找回"
});
```
## 直接关闭当前dialog
```javascript
Dialog.closed() //可以直接关闭当前dialog
```
## ID
同一个页面中,id相同的Dialog的DOM只会同时存在一个,不指定id时,id的默认值为**nut-dialog-default-id**
```javascript
Dialog({
id:'my-dialog',
title: "确定删除此订单?",
content: "删除后将从你的记录里消失,无法找回"
});
```
> 如果希望同时弹出多个Dialog,请给不同的Dialog设置不同的id。
模态对话框,在浮层中显示,引导用户进行相关操作,常用于消息提示、消息确认,或在当前页面内完成特定的交互操作。
## 事件
```javascript
Dialog({
title: "自定义Dialog标题",
content: "小屏或移动端浏览效果最佳",
closeBtn:true, //显式右上角关闭按钮
onOkBtn(event) { //确定按钮点击事件
alert("okBtn");
this.close(); //关闭对话框
},
onCancelBtn(event) { //取消按钮点击事件,默认行为关闭对话框
alert("cancelBtn");
//return false; //阻止默认“关闭对话框”的行为
},
onCloseBtn(event) { //右上角关闭按钮点击事件
alert("closeBtn");
//return false; //阻止默认“关闭对话框”的行为
},
closeCallback(target) {
alert("will close"); //对话框关闭回调函数,无论通过何种方式关闭都会触发
}
});
```
## 关闭dialog不销毁实例
```javascript
Dialog({
animation: false, //禁用弹出动效
title: "注册说明",
canDestroy:false,
content:
"原账号为您本人所有,建议直接登录或找回密码。原账号内的订单资产可能丢失,可联系京东客服找回。"
});
```
## 页面滚动锁定
**lockBgScroll** 值设为 **true** 时,可在弹窗出现时锁定页面滚动,且不影响窗体内部滚动。
弹出框组件支持函数调用和组件调用两种方式。
### 安装
```javascript
Dialog({
title: "背景滚动锁定",
lockBgScroll:true,
content:"弹窗弹出后,页面滚动锁止。在窗体和遮罩层上滑动时,页面不再跟随滚动。"
});
```
import { createApp } from 'vue';
import { Dialog } from '@nutui/nutui';
## 图片弹窗
**type** 值为 **image** 时为图片弹窗,需要配置一张图片,可带链接(非必须)。默认展示关闭按钮。点击图片触发 **onClickImageLink** 事件,返回**false**可阻止默认的跳转链接行为。
```javascript
Dialog({
type:"image", //设置弹窗类型为”图片弹窗“
link:"http://m.jd.com", //点击图片跳转的Url
imgSrc:"https://m.360buyimg.com/mobilecms/s750x750_jfs/t1/4875/23/1968/285655/5b9549eeE4997a18c/070eaf5bddf26be8.jpg", //图片Url
onClickImageLink:function(){ //图片点击事件,默认行为是跳转Url
console.log(this); //this指向该Dialog实例
return false; //返回false可阻止默认的链接跳转行为
}
});
const app = createApp();
app.use(Dialog);
```
## 标签式写法
如果Dialog内容有复杂交互,可使用Dialog的标签式用法。注意标签使用的时候,属性不建议使用驼峰,推荐使用如下写法
```html
<nut-dialog title="标签形式调用" :visible="dialogShow" @ok-btn-click="dialogShow=false" @cancel-btn-click="dialogShow=false" @close="dialogShow=false">
<a href="javascript:;" @click="dialogShow=false" :noCancelBtn="true">点我可以直接关闭对话框</a>
</nut-dialog>
<nut-dialog :title="title" :close-on-click-overlay="false" :content="content" v-model:visible="visible"></nut-dialog>
```
```javascript
``` javascript
import { ref } from 'vue';
export default {
data() {
return {
dialogShow: false
};
}
}
setup() {
const visible = ref(true);
const title = '标签式使用';
const content = '内容';
return { visible,title,content };
},
};
```
## prop
## Props
| 字段 | 说明 | 类型 | 默认值
|----- | ----- | ----- | -----
| id | 标识符,相同者共享一个实例 | String/Number | nut-dialog-default-id
| canDestroy | 是否关闭弹窗时销毁实例 | Boolean | true
| title | 标题 | String | -
| content | 内容,支持HTML | String | -
| type | 弹窗类型,值为**image**时为图片弹窗 | String | -
| closeOnClickModal | 点击蒙层是否关闭对话框 | Boolean | true
| close-on-click-overlay | 点击蒙层是否关闭对话框 | Boolean | true
| noFooter | 是否隐藏底部按钮栏 | Boolean | false
| noOkBtn | 是否隐藏确定按钮 | Boolean | false
| noCancelBtn | 是否隐藏取消按钮 | Boolean | false
| cancelBtnTxt | 取消按钮文案 | String | ”取 消“
| okBtnTxt | 确定按钮文案 | String | ”确 定“
| cancelText | 取消按钮文案 | String | ”取消“
| okText | 确定按钮文案 | String | ”确 定“
| okBtnDisabled | 禁用确定按钮 | Boolean | false
| cancelAutoClose | 取消按钮是否默认关闭弹窗 | Boolean | true
| textAlign | 文字对齐方向,可选值同css的text-align | String | "center"
| maskBgStyle | 遮罩层样式(颜色、透明度) | String | -
| customClass | 增加一个自定义class | String | -
| link | 点击图片跳转的Url,仅对图片类型弹窗有效 | String | -
| imgSrc | 图片Url,仅对图片类型弹窗有效 | String | -
| animation | 是否开启默认动效 | Boolean | true
| closeOnPopstate | 是否在页面回退时自动关闭 | Boolean | false
| lockBgScroll | 锁定遮罩层滚动,不影响弹窗内部滚动(实验性质)会给body添加posotion:fix属性,注意 | Boolean | false
| lock-scroll | 背景是否锁定 | Boolean | false
## 事件
## Events
| 字段 | 说明 | 类型 | 默认值
|----- | ----- | ----- | -----
| onOkBtn | 确定按钮回调 | Function | -
| onCancelBtn | 取消按钮回调 | Function | -
| onCloseBtn | 关闭按钮回调 | Function | -
| closeCallback | 关闭回调,任何情况关闭弹窗都会触发 | Function | -
| onClickImageLink | 图片链接点击回调,仅对图片类型弹窗有效 | Function | -
| closed | 关闭dialog | Function | -
\ No newline at end of file
| ok | 确定按钮回调 | Function | -
| cancel | 取消按钮回调 | Function | -
| open | 关闭按钮回调 | Function | -
| closed | 关闭回调,任何情况关闭弹窗都会触发 | Function | -
\ No newline at end of file
@import '../../styles/variables.scss';
@import '../../styles/mixins/make-animation';
@import '../../styles/mixins/text-ellipsis.scss';
@import '../../styles/animation/fade';
@import '../../styles/animation/ease';
$mask-bg: rgba(0, 0, 0, 0.5) !default;
$font-size-base: 14px !default;
body.dialog-open {
position: fixed;
}
.nut-dialog-wrapper {
position: relative;
z-index: $zindex-mask;
}
.nut-dialog-box {
position: fixed;
display: flex;
align-items: center;
justify-content: center;
color: $text-color;
}
.nut-dialog-mask,
.nut-dialog-box {
left: 0;
top: 0;
right: 0;
bottom: 0;
}
.nut-dialog-mask {
position: fixed;
background: $mask-bg;
}
.nut-dialog {
position: relative;
width: 86%;
max-height: 70vh;
background: #fff;
border-radius: 12px;
overflow: hidden;
display: flex;
flex-direction: column;
}
.nut-dialog-title {
display: block;
line-height: 1.5;
color: #262626;
font-size: 16px;
text-align: center;
flex-shrink: 0;
@include text-ellipsis;
padding-bottom: 11px;
// &:only-child {
// padding-bottom: 0;
// }
}
.nut-dialog-close {
position: absolute;
right: 0;
top: 0;
width: 36px;
height: 46px;
font-size: 20px;
text-align: center;
text-decoration: none;
background: url('//img13.360buyimg.com/imagetools/jfs/t1/144349/40/19537/4004/5fe1ca9bE2daa4196/7afe4a2ac681804a.png')
no-repeat center;
background-size: 10px 10px;
img {
height: 10px;
}
}
.nut-dialog-image-wrapper {
position: relative;
.nut-dialog {
width: auto;
max-width: 80%;
max-height: 75%;
background: transparent;
border-radius: none;
display: inline-block;
overflow: visible;
}
.nut-dialog-close {
position: absolute;
left: 50%;
top: auto;
bottom: -48px;
width: 24px;
height: 24px;
margin-left: -12px;
background: url(./close.svg) no-repeat center;
background-size: 100%;
}
}
.nut-dialog-link {
display: inline-block;
}
.nut-dialog-image {
max-width: 100%;
max-height: 100%;
vertical-align: bottom;
}
.nut-dialog-body {
box-sizing: border-box;
padding: 30px 20px 20px;
display: flex;
flex-direction: column;
flex: 0 1 auto;
overflow: auto;
}
.nut-dialog-content {
flex: 1;
justify-content: center;
overflow: auto;
font-size: $font-size-base;
word-break: break-all;
padding-bottom: 10px;
-webkit-overflow-scrolling: touch;
}
.nut-dialog-footer {
height: 50px;
width: 100%;
line-height: 50px;
display: flex;
flex-shrink: 0;
overflow: hidden;
flex-direction: row;
justify-content: center;
padding: 0 30px;
}
.nut-dialog-btn {
display: block;
max-width: 104px;
height: 30px;
border-radius: 17px;
position: relative;
flex: 1;
font-size: $font-size-base;
border: none;
background: transparent;
appearance: none;
outline: none;
user-select: none;
margin: 0 10px;
&.nut-dialog-ok {
width: 128px;
color: #fff;
background: linear-gradient(
135deg,
#fa2c19 0%,
#fa3f19 45%,
#fa5919 83%,
#fa6419 100%
);
}
&.nut-dialog-cancel {
color: #fa2c19;
border: 1px solid #fa2c19;
align-items: center;
width: $dialog-width;
min-height: 156px;
padding: 28px 24px 16px 24px;
&__header {
display: block;
text-align: center;
height: 20px;
font-size: 16px;
color: rgba(38, 38, 38, 1);
@include oneline-ellipsis();
}
&.disabled {
cursor: not-allowed;
opacity: 0.68;
&__content {
width: 100%;
overflow: auto;
flex: 1;
margin: 20px 0;
max-height: 268px;
line-height: 16px;
font-size: 12px;
color: $text-color;
word-wrap: break-word;
word-break: break-all;
white-space: pre-wrap;
}
&:only-child {
max-width: 128px;
color: #fff;
background: linear-gradient(
135deg,
#fa2c19 0%,
#fa3f19 45%,
#fa5919 83%,
#fa6419 100%
);
&__footer {
display: flex;
align-items: center;
width: 100%;
justify-content: space-around;
.nut-button {
flex: 1;
}
&-cancel {
margin-right: 20px;
}
&-ok {
max-width: 128px;
}
}
}
import dialog from './index.vue';
import { defineComponent, createVNode, render, toRef, watch } from 'vue';
const confirmConstructor = defineComponent(dialog);
import dialogInstance from './index.vue';
import { render, createVNode, ref } from 'vue';
export const show = ref(false);
export class DialogOptions {
title: string = '';
content: string = '';
cancelText: string = '取消';
okText: string = '确定';
textAlign: string = 'center';
teleport: String | Element = 'body';
// function
private onUpdate: Function = (value: boolean) => {
show.value = value;
};
onOk: Function = () => {};
onCancel: Function = () => {};
onClose: Function = () => {};
onClosed: Function = () => {};
noFooter: boolean = false;
noOkBtn: boolean = false;
noCancelBtn: boolean = false;
okBtnDisabled: boolean = false;
closeOnPopstate: boolean = false;
lockScroll: boolean = false;
}
class Dialog {
options: DialogOptions = new DialogOptions();
constructor(_options: DialogOptions) {
Object.assign(this.options, _options);
show.value = true;
const instance: any = createVNode(dialogInstance, this.options as any);
render(instance, document.body);
}
let instance: any;
const Dialog = (options: any) => {
options = options ? options : {};
close = () => {
// if (instance) {
// instance.component.ctx.close();
// }
};
options.id = options.id || 'nut-dialog-default-id';
options.visible = true;
if (options.type === 'image' && typeof options.closeBtn === 'undefined') {
options.closeBtn = true;
}
setDefaultOptions = (options: DialogOptions) => {
// Object.assign(this.currentOptions, options);
};
// 生成组件实例
instance = createVNode(confirmConstructor, options);
// 渲染挂载组件
const container = document.createElement('div');
render(instance, container);
const dialogDom = document.querySelector('#' + options.id);
if (options.id && dialogDom && dialogDom.parentNode) {
dialogDom.parentNode.replaceChild(instance.el, dialogDom);
} else {
document.body.appendChild(instance.el);
}
resetDefaultOptions = () => {
// Dialog.currentOptions = { ...Dialog.defaultOptions };
};
}
// 初始化组件参数
const props = instance.component.props;
Object.keys(options).forEach(key => {
props[key] = options[key];
});
const _Dialog = function(options: DialogOptions) {
return new Dialog(options);
};
Dialog.close = function() {
if (instance) {
instance.component.ctx.close();
}
};
Dialog.install = function(app: any) {
app.use(dialog);
app.config.globalProperties.$dialog = Dialog;
_Dialog.install = (app: any) => {
app.use(dialogInstance);
app.config.globalProperties.$dialog = _Dialog;
};
Dialog.Component = dialog;
export default Dialog;
export default _Dialog;
<template>
<view :class="classes" @click="handleClick">
<div
v-if="destroy"
:class="[
'nut-dialog-wrapper',
customClass,
{ 'nut-dialog-image-wrapper': type === 'image' }
]"
:id="id"
>
<transition :name="animation ? 'nutFade' : ''">
<div
:class="'nut-dialog-mask'"
:style="{ background: maskBgStyle }"
@click="modalClick"
v-show="curVisible"
>
</div>
</transition>
<transition :name="animation ? 'nutEase' : ''">
<div class="nut-dialog-box" v-show="curVisible" @click="modalClick">
<div class="nut-dialog" @click.stop>
<a
href="javascript:;"
v-if="closeBtn"
@click="closeBtnClick"
class="nut-dialog-close"
></a>
<template v-if="type === 'image'">
<a
href="javascript:;"
@click="imageLinkClick"
class="nut-dialog-link"
>
<img :src="imgSrc" class="nut-dialog-image" alt />
</a>
</template>
<template v-else>
<div class="nut-dialog-body">
<span
class="nut-dialog-title"
v-html="title"
v-if="title"
></span>
<div
class="nut-dialog-content"
v-if="isShowContent"
:style="{ textAlign }"
>
<slot></slot>
</div>
<div
class="nut-dialog-content"
v-html="content"
v-else-if="content"
:style="{ textAlign }"
></div>
</div>
<div class="nut-dialog-footer" v-if="!noFooter">
<button
class="nut-dialog-btn nut-dialog-cancel"
v-if="!noCancelBtn"
@click="cancelBtnClick(cancelAutoClose)"
>{{ cancelBtnTxt }}</button
>
<button
class="nut-dialog-btn nut-dialog-ok"
v-if="!noOkBtn"
:class="{ disabled: okBtnDisabled }"
:disabled="okBtnDisabled"
@click="okBtnClick"
>{{ okBtnTxt }}</button
>
</div>
</template>
</div>
</div>
</transition>
</div>
</view>
<nut-popup
name="pop"
:teleport="teleport"
v-model:visible="showPopup"
:close-on-click-overlay="closeOnClickOverlay"
:lock-scroll="lockScroll"
round
@click-overlay="closed"
@click-close-icon="closed"
>
<view :class="classes">
<view v-if="title" class="nut-dialog__header">
<slot v-if="$slots.header" name="header"></slot>
<template v-else>{{ title }}</template>
</view>
<view class="nut-dialog__content" :style="{ textAlign }">
<slot v-if="$slots.default" name="default"></slot>
<template v-else>{{ content }}</template>
</view>
<view class="nut-dialog__footer" v-if="!noFooter">
<slot v-if="$slots.footer" name="footer"></slot>
<template v-else>
<nut-button
size="small"
plain
type="primary"
class="nut-dialog__footer-cancel"
v-if="!noCancelBtn"
@click="onCancel"
>
{{ cancelText }}
</nut-button>
<nut-button
v-if="!noOkBtn"
size="small"
type="primary"
class="nut-dialog__footer-ok"
:class="{ disabled: okBtnDisabled }"
:disabled="okBtnDisabled"
@click="onOk"
>
{{ okText }}
</nut-button>
</template>
</view>
</view>
</nut-popup>
</template>
<script lang="ts">
import { ref, onMounted, watch, watchEffect, computed } from 'vue';
import { onMounted, computed, watch, onUnmounted, ref, toRefs } from 'vue';
import { createComponent } from '@/utils/create';
const { componentName, create } = createComponent('dialog');
const lockMaskScroll = (bodyCls => {
let scrollTop = 0;
return {
afterOpen: function() {
scrollTop =
(document.scrollingElement && document.scrollingElement.scrollTop) ||
document.body.scrollTop;
document.body.classList.add(bodyCls);
document.body.style.top = -scrollTop + 'px';
},
beforeClose: function() {
if (document.body.classList.contains(bodyCls)) {
document.body.classList.remove(bodyCls);
if (document.scrollingElement) {
document.scrollingElement.scrollTop = scrollTop;
}
}
}
};
})('dialog-open');
import { Button, Popup } from '@/nutui';
import { show } from './index';
export default create({
inheritAttrs: false,
children: [Popup, Button],
components: {
'nut-popup': Popup,
'nut-button': Button
},
props: {
...Popup.popupProps,
visible: {
type: Boolean,
default: false
},
id: {
type: String,
default: ''
},
title: {
type: String,
default: ''
......@@ -123,35 +76,6 @@ export default create({
type: String,
default: ''
},
type: {
type: String,
default: ''
},
link: {
type: String,
default: ''
},
imgSrc: {
type: String,
default: ''
},
animation: {
type: Boolean,
default: true
},
lockBgScroll: {
type: Boolean,
default: false
},
closeBtn: {
type: Boolean,
default: false
},
closeOnClickModal: {
type: Boolean,
default: true
},
noFooter: {
type: Boolean,
default: false
......@@ -164,11 +88,11 @@ export default create({
type: Boolean,
default: false
},
cancelBtnTxt: {
cancelText: {
type: String,
default: '取消'
},
okBtnTxt: {
okText: {
type: String,
default: '确定'
},
......@@ -184,136 +108,57 @@ export default create({
type: String,
default: 'center'
},
onOkBtn: {
type: Function,
default: null
},
onCloseBtn: {
onOk: {
type: Function,
default: null
},
onCancelBtn: {
onCancel: {
type: Function,
default: null
},
closeCallback: {
onClose: {
type: Function,
default: null
},
onClickImageLink: {
onClosed: {
type: Function,
default: null
},
maskBgStyle: {
type: String,
default: ''
},
canDestroy: {
type: Boolean,
default: true
},
customClass: {
type: String,
default: ''
},
closeOnPopstate: {
type: Boolean,
default: false
}
},
// emits: ['click'],
emits: [
'update',
'update:visible',
'ok',
'cancel',
'open',
'opened',
'close',
'closed'
],
setup(props, { emit }) {
const showPopup = ref(false);
showPopup.value = show.value;
setup(props, { emit, slots }) {
const curVisible = ref(false);
let destroy = ref(true);
onMounted(() => {
curVisible.value = props.visible;
});
const isShowContent = computed(() => {
return slots.default;
});
const todestroy = () => {
if (!props.canDestroy) {
destroy = ref(false);
}
};
const close = (target?: string) => {
emit('close', target);
emit('close-callback', target);
todestroy();
if (
typeof props.closeCallback === 'function' &&
props.closeCallback(target) === false
) {
return;
}
curVisible.value = false;
};
const modalClick = () => {
if (!props.closeOnClickModal) {
return;
}
close('modal');
};
const okBtnClick = () => {
emit('ok-btn-click');
if (typeof props.onOkBtn === 'function') {
props.onOkBtn.call(props);
}
};
const cancelBtnClick = (autoClose: boolean) => {
emit('cancel-btn-click');
if (!autoClose) {
return;
}
if (typeof props.onCancelBtn === 'function') {
if (props.onCancelBtn.call(props) === false) {
return;
}
}
close('cancelBtn');
};
const closeBtnClick = () => {
if (typeof props.onCloseBtn === 'function') {
if (props.onCloseBtn.call(props) === false) {
return;
}
}
close('closeBtn');
};
//图片类型弹窗中的链接点击事件,默认跳转
const imageLinkClick = () => {
if (
props.onClickImageLink &&
props.onClickImageLink.call(props) === false
) {
return;
}
if (props.link) {
location.href = props.link;
}
};
const handleClick = (event: Event) => {
emit('click', event);
};
onMounted(() => {
if (props.closeOnPopstate) {
window.addEventListener('popstate', function() {
close();
closed();
});
}
});
watchEffect(() => {
if (props.lockBgScroll) {
//锁定or解锁页面滚动
lockMaskScroll[curVisible.value ? 'afterOpen' : 'beforeClose']();
}
watch(show, value => {
showPopup.value = value;
});
watch(
() => props.visible,
val => {
curVisible.value = val;
value => {
showPopup.value = value;
}
);
......@@ -322,19 +167,36 @@ export default create({
[componentName]: true
};
});
const update = (val: boolean) => {
emit('update', val);
emit('update:visible', val);
};
const closed = () => {
update(false);
emit('closed');
};
const onCancel = () => {
emit('cancel');
if (props.cancelAutoClose) {
closed();
}
};
const onOk = () => {
closed();
emit('ok');
};
return {
handleClick,
curVisible,
destroy,
modalClick,
close,
todestroy,
okBtnClick,
cancelBtnClick,
closeBtnClick,
imageLinkClick,
isShowContent,
classes
closed,
classes,
onCancel,
onOk,
show,
showPopup
};
}
});
......
......@@ -7,6 +7,7 @@
:class="overlayClass"
:style="overlayStyle"
:z-index="zIndex"
:lock-scroll="lockScroll"
:duration="duration"
@click="onClickOverlay"
/>
......@@ -53,6 +54,7 @@ import { useLockScroll } from './use-lock-scroll';
import { overlayProps } from './../overlay/index.vue';
import overlay from '@/packages/overlay/index.vue';
import { createComponent } from '@/utils/create';
import { OverLay } from '@/nutui';
const { componentName, create } = createComponent('popup');
let _zIndex = 2000;
......@@ -112,6 +114,9 @@ export const popupProps = {
};
export default create({
children: [overlay],
components: {
'nut-overlay': OverLay
},
props: {
...popupProps
},
......
......@@ -22,6 +22,10 @@ $padding-xs: 12px;
$font-family: PingFang SC, Microsoft YaHei, Helvetica, Hiragino Sans GB, SimSun,
sans-serif !default;
// ---- Animation ----
$animation-duration: 0.25s !default;
$animation-timing-fun: cubic-bezier(0.55, 0.085, 0.68, 0.53) !default;
// Font
$font-size-0: 10px;
$font-size-1: 12px;
......@@ -170,20 +174,6 @@ $overlay-bg-color: rgba(0, 0, 0, 0.7);
//popup
$popup-close-icon-margin: 16px;
$popup-border-radius: 20px;
// ---- Animation ----
$animation-duration: 0.25s !default;
$transition-duration: 0.2s !default;
$transition-duration-fast: 0.2s !default;
$transition-duration-slow: 0.4s !default;
$animation-timing-fun: cubic-bezier(0.55, 0.085, 0.68, 0.53) !default;
$ease-in-out: cubic-bezier(0.445, 0.05, 0.55, 0.95);
$ease-out: cubic-bezier(0.895, 0.03, 0.685, 0.22);
// ---- z-index ----
$zindex-mask: 9998 !default;
$zindex-actionsheet: 10001 !default;
$zindex-dialog: 10000 !default;
$zindex-picker: 10050 !default;
// Notify
$notify-text-color: $white;
......@@ -246,6 +236,9 @@ $address-region-tab-line: linear-gradient(
$primary-color-end 100%
);
// dialog
$dialog-width: 296px;
view-block {
display: block;
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册