Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
京东前端
nutui
提交
4e2314a2
N
nutui
项目概览
京东前端
/
nutui
通知
37
Star
4
Fork
1
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
N
nutui
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
4e2314a2
编写于
4月 13, 2021
作者:
richard_1015
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
chore: dialog
上级
aec2f726
变更
8
显示空白变更内容
内联
并排
Showing
8 changed file
with
282 addition
and
854 deletion
+282
-854
src/config.json
src/config.json
+1
-1
src/packages/dialog/demo.vue
src/packages/dialog/demo.vue
+29
-242
src/packages/dialog/doc.md
src/packages/dialog/doc.md
+31
-121
src/packages/dialog/index.scss
src/packages/dialog/index.scss
+40
-183
src/packages/dialog/index.ts
src/packages/dialog/index.ts
+55
-41
src/packages/dialog/index.vue
src/packages/dialog/index.vue
+114
-252
src/packages/popup/index.vue
src/packages/popup/index.vue
+5
-0
src/styles/variables.scss
src/styles/variables.scss
+7
-14
未找到文件。
src/config.json
浏览文件 @
4e2314a2
...
...
@@ -293,7 +293,7 @@
"cName"
:
"对话框"
,
"desc"
:
"模态对话框,在浮层中显示,引导用户进行相关操作,支持图片对话框。"
,
"sort"
:
8
,
"show"
:
fals
e
,
"show"
:
tru
e
,
"author"
:
"dsj"
},
{
...
...
src/packages/dialog/demo.vue
浏览文件 @
4e2314a2
<
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"
>
<a
href=
"javascript:;"
@
click=
"dialogShow = false"
:noCancelBtn=
"true"
>
点我可以直接关闭对话框
</a
title=
"标签式使用"
:close-on-click-overlay=
"false"
:content=
"content"
v-model:visible=
"visible"
>
</nut-dialog>
<!--
<template
v-slot:header
>
</
template
>
-->
</div>
</template>
<
script
lang=
"ts"
>
import
{
re
active
,
toRefs
,
createApp
}
from
'
vue
'
;
import
{
re
f
,
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
:
{}
const
{
proxy
}
=
getCurrentInstance
();
const
content
=
ref
(
'
模态对话框,在浮层中显示,引导用户进行相关操作,支持图片对话框。
'
);
const
visible
=
ref
(
false
);
const
baseClick
=
()
=>
{
proxy
.
$dialog
({
title
:
'
基础弹框
'
,
content
:
'
基础弹框内容
'
});
function
showDialog1
()
{
const
options
=
{
title
:
'
确定删除此订单?
'
,
content
:
'
删除后将从你的记录里消失,无法找回
'
,
closeOnPopstate
:
true
};
Dialog
(
options
);
}
function
showDialog2
()
{
const
options
=
{
title
:
'
确定要加入购物车吗?
'
const
noTitleClick
=
()
=>
{
visible
.
value
=
true
;
};
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
:
'
我知道了
'
});
}
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可阻止默认的链接跳转行为
}
});
}
return
{
...
toRefs
(
data
),
showDialog1
,
showDialog2
,
showDialog3
,
showDialog4
,
showDialog5
,
showDialog6
,
showDialog7
,
showDialog8
,
showDialog9
,
showImageDialog
content
,
visible
,
baseClick
,
noTitleClick
};
}
});
...
...
src/packages/dialog/doc.md
浏览文件 @
4e2314a2
# 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
:
"
弹窗弹出后,页面滚动锁止。在窗体和遮罩层上滑动时,页面不再跟随滚动。
"
});
```
## 图片弹窗
**type**
值为
**image**
时为图片弹窗,需要配置一张图片,可带链接(非必须)。默认展示关闭按钮。点击图片触发
**onClickImageLink**
事件,返回
**false**
可阻止默认的跳转链接行为。
import
{
createApp
}
from
'
vue
'
;
import
{
Dialog
}
from
'
@nutui/nutui
'
;
```
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
| cancel
BtnTxt | 取消按钮文案 | String | ”取
消“
| ok
BtnT
xt | 确定按钮文案 | String | ”确 定“
| cancel
Text | 取消按钮文案 | String | ”取
消“
| ok
Te
xt | 确定按钮文案 | 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
| lock
BgScroll | 锁定遮罩层滚动,不影响弹窗内部滚动(实验性质)会给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
src/packages/dialog/index.scss
浏览文件 @
4e2314a2
@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
;
}
align-items
:
center
;
width
:
$dialog-width
;
min-height
:
156px
;
padding
:
28px
24px
16px
24px
;
.nut-dialog-title
{
&
__header
{
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%
;
height
:
20px
;
font-size
:
16px
;
color
:
rgba
(
38
,
38
,
38
,
1
);
@include
oneline-ellipsis
();
}
}
.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
;
&
__content
{
width
:
100%
;
overflow
:
auto
;
}
.nut-dialog-content
{
flex
:
1
;
justify-content
:
center
;
overflow
:
auto
;
font-size
:
$font-size-base
;
margin
:
20px
0
;
max-height
:
268px
;
line-height
:
16px
;
font-size
:
12px
;
color
:
$text-color
;
word-wrap
:
break-word
;
word-break
:
break-all
;
padding-bottom
:
10px
;
-webkit-overflow-scrolling
:
touch
;
}
.nut-dialog-footer
{
height
:
50px
;
width
:
100%
;
line-height
:
50px
;
white-space
:
pre-wrap
;
}
&
__footer
{
display
:
flex
;
flex-shrink
:
0
;
overflow
:
hidden
;
flex-direction
:
row
;
justify-content
:
center
;
padding
:
0
30px
;
}
align-items
:
center
;
width
:
100%
;
justify-content
:
space-around
;
.nut-dialog-btn
{
display
:
block
;
max-width
:
104px
;
height
:
30px
;
border-radius
:
17px
;
position
:
relative
;
.nut-button
{
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
;
&
-cancel
{
margin-right
:
20px
;
}
&
.disabled
{
cursor
:
not
-
allowed
;
opacity
:
0
.68
;
}
&
:only-child
{
&
-ok
{
max-width
:
128px
;
color
:
#fff
;
background
:
linear-gradient
(
135deg
,
#fa2c19
0%
,
#fa3f19
45%
,
#fa5919
83%
,
#fa6419
100%
);
}
}
}
src/packages/dialog/index.ts
浏览文件 @
4e2314a2
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
;
src/packages/dialog/index.vue
浏览文件 @
4e2314a2
<
template
>
<
view
:class=
"classes"
@
click=
"handleClick"
>
<div
v-if=
"destroy
"
:class=
"[
'nut-dialog-wrapper',
customClass,
{ 'nut-dialog-image-wrapper': type === 'image' }
]
"
:id="i
d"
<
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=
"close
d"
>
<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
>
<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
>
<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"
<nut-button
size=
"small"
plain
type=
"primary"
class=
"nut-dialog__footer-cancel"
v-if=
"!noCancelBtn"
@
click=
"cancelBtnClick(cancelAutoClose)"
>
{{
cancelBtnTxt
}}
</button
@
click=
"onCancel"
>
<button
class=
"nut-dialog-btn nut-dialog-ok"
{{
cancelText
}}
</nut-button>
<nut-button
v-if=
"!noOkBtn"
size=
"small"
type=
"primary"
class=
"nut-dialog__footer-ok"
:class=
"
{ disabled: okBtnDisabled }"
:disabled="okBtnDisabled"
@click="okBtnClick"
>
{{
okBtnTxt
}}
</button
@click="onOk"
>
</div>
{{
okText
}}
</nut-button>
</
template
>
</div>
</div>
</transition>
</div>
</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
},
cancel
BtnT
xt
:
{
cancel
Te
xt
:
{
type
:
String
,
default
:
'
取消
'
},
ok
BtnT
xt
:
{
ok
Te
xt
:
{
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
},
onCancel
Btn
:
{
onCancel
:
{
type
:
Function
,
default
:
null
},
closeCallback
:
{
onClose
:
{
type
:
Function
,
default
:
null
},
onCl
ickImageLink
:
{
onCl
osed
:
{
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
();
close
d
();
});
}
});
watchEffect
(()
=>
{
if
(
props
.
lockBgScroll
)
{
//锁定or解锁页面滚动
lockMaskScroll
[
curVisible
.
value
?
'
afterOpen
'
:
'
beforeClose
'
]();
}
watch
(
show
,
value
=>
{
showPopup
.
value
=
value
;
});
watch
(
()
=>
props
.
visible
,
val
=>
{
curVisible
.
value
=
val
;
val
ue
=>
{
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
};
}
});
...
...
src/packages/popup/index.vue
浏览文件 @
4e2314a2
...
...
@@ -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
},
...
...
src/styles/variables.scss
浏览文件 @
4e2314a2
...
...
@@ -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.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录