Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
B
basic-vue-admin
概览
概览
详情
活动
周期分析
版本库
存储库
文件
提交
分支
标签
贡献者
分支图
比较
统计图
问题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程表
图表
维基
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
Basic
basic-vue-admin
Commits
2e79c9f3
提交
2e79c9f3
authored
12月 21, 2020
作者:
vben
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
feat: add ripple directive
上级
aafbb052
隐藏空白字符变更
内嵌
并排
正在显示
13 个修改的文件
包含
270 行增加
和
1 行删除
+270
-1
CHANGELOG.zh_CN.md
CHANGELOG.zh_CN.md
+4
-0
index.ts
src/directives/index.ts
+0
-0
loading.ts
src/directives/loading.ts
+0
-0
permission.ts
src/directives/permission.ts
+0
-0
repeatClick.ts
src/directives/repeatClick.ts
+0
-0
index.less
src/directives/ripple/index.less
+21
-0
index.ts
src/directives/ripple/index.ts
+191
-0
feat.ts
src/locales/lang/en/routes/demo/feat.ts
+1
-0
feat.ts
src/locales/lang/zh_CN/routes/demo/feat.ts
+1
-0
main.ts
src/main.ts
+1
-1
feat.ts
src/router/menus/modules/demo/feat.ts
+10
-0
feat.ts
src/router/routes/modules/demo/feat.ts
+8
-0
index.vue
src/views/demo/feat/ripple/index.vue
+33
-0
没有找到文件。
CHANGELOG.zh_CN.md
浏览文件 @
2e79c9f3
## Wip
### ✨ Features
-
新增
`v-ripple`
水波纹指令
### 🐛 Bug Fixes
-
修复混合模式下滚动条丢失问题
...
...
src/
setup/
directives/index.ts
→
src/directives/index.ts
浏览文件 @
2e79c9f3
File moved
src/
setup/
directives/loading.ts
→
src/directives/loading.ts
浏览文件 @
2e79c9f3
File moved
src/
setup/
directives/permission.ts
→
src/directives/permission.ts
浏览文件 @
2e79c9f3
File moved
src/
setup/
directives/repeatClick.ts
→
src/directives/repeatClick.ts
浏览文件 @
2e79c9f3
File moved
src/directives/ripple/index.less
0 → 100644
浏览文件 @
2e79c9f3
.ripple-container {
position: absolute;
top: 0;
left: 0;
width: 0;
height: 0;
overflow: hidden;
pointer-events: none;
}
.ripple-effect {
position: relative;
z-index: 9999;
width: 1px;
height: 1px;
margin-top: 0;
margin-left: 0;
pointer-events: none;
border-radius: 50%;
transition: all 0.6s cubic-bezier(0.4, 0, 0.2, 1);
}
src/directives/ripple/index.ts
0 → 100644
浏览文件 @
2e79c9f3
import
{
Directive
}
from
'vue'
;
import
'./index.less'
;
export
interface
RippleOptions
{
event
:
string
;
transition
:
number
;
}
export
interface
RippleProto
{
background
?:
string
;
zIndex
?:
string
;
}
export
type
EventType
=
Event
&
MouseEvent
&
TouchEvent
;
const
options
:
RippleOptions
=
{
event
:
'mousedown'
,
transition
:
400
,
};
const
RippleDirective
:
Directive
&
RippleProto
=
{
beforeMount
:
(
el
:
HTMLElement
,
binding
)
=>
{
if
(
binding
.
value
===
false
)
return
;
const
bg
=
el
.
getAttribute
(
'ripple-background'
);
setProps
(
Object
.
keys
(
binding
.
modifiers
),
options
);
const
background
=
bg
||
RippleDirective
.
background
;
const
zIndex
=
RippleDirective
.
zIndex
;
el
.
addEventListener
(
options
.
event
,
(
event
:
EventType
)
=>
{
rippler
({
event
,
el
,
background
,
zIndex
,
});
});
},
updated
(
el
,
binding
)
{
if
(
!
binding
.
value
)
{
el
?.
clearRipple
?.();
return
;
}
const
bg
=
el
.
getAttribute
(
'ripple-background'
);
el
?.
setBackground
?.(
bg
);
},
};
function
rippler
({
event
,
el
,
zIndex
,
background
,
}:
{
event
:
EventType
;
el
:
HTMLElement
}
&
RippleProto
)
{
const
targetBorder
=
parseInt
(
getComputedStyle
(
el
).
borderWidth
.
replace
(
'px'
,
''
));
const
clientX
=
event
.
clientX
||
event
.
touches
[
0
].
clientX
;
const
clientY
=
event
.
clientY
||
event
.
touches
[
0
].
clientY
;
const
rect
=
el
.
getBoundingClientRect
();
const
{
left
,
top
}
=
rect
;
const
{
offsetWidth
:
width
,
offsetHeight
:
height
}
=
el
;
const
{
transition
}
=
options
;
const
dx
=
clientX
-
left
;
const
dy
=
clientY
-
top
;
const
maxX
=
Math
.
max
(
dx
,
width
-
dx
);
const
maxY
=
Math
.
max
(
dy
,
height
-
dy
);
const
style
=
window
.
getComputedStyle
(
el
);
const
radius
=
Math
.
sqrt
(
maxX
*
maxX
+
maxY
*
maxY
);
const
border
=
targetBorder
>
0
?
targetBorder
:
0
;
const
ripple
=
document
.
createElement
(
'div'
);
const
rippleContainer
=
document
.
createElement
(
'div'
);
// Styles for ripple
Object
.
assign
(
ripple
.
style
??
{},
{
className
:
'ripple'
,
marginTop
:
'0px'
,
marginLeft
:
'0px'
,
width
:
'1px'
,
height
:
'1px'
,
transition
:
`all
${
transition
}
ms cubic-bezier(0.4, 0, 0.2, 1)`
,
borderRadius
:
'50%'
,
pointerEvents
:
'none'
,
position
:
'relative'
,
zIndex
:
zIndex
??
'9999'
,
backgroundColor
:
background
??
'rgba(0, 0, 0, 0.12)'
,
});
// Styles for rippleContainer
Object
.
assign
(
rippleContainer
.
style
??
{},
{
className
:
'ripple-container'
,
position
:
'absolute'
,
left
:
`
${
0
-
border
}
px`
,
top
:
`
${
0
-
border
}
px`
,
height
:
'0'
,
width
:
'0'
,
pointerEvents
:
'none'
,
overflow
:
'hidden'
,
});
const
storedTargetPosition
=
el
.
style
.
position
.
length
>
0
?
el
.
style
.
position
:
getComputedStyle
(
el
).
position
;
if
(
storedTargetPosition
!==
'relative'
)
{
el
.
style
.
position
=
'relative'
;
}
rippleContainer
.
appendChild
(
ripple
);
el
.
appendChild
(
rippleContainer
);
Object
.
assign
(
ripple
.
style
,
{
marginTop
:
`
${
dy
}
px`
,
marginLeft
:
`
${
dx
}
px`
,
});
const
{
borderTopLeftRadius
,
borderTopRightRadius
,
borderBottomLeftRadius
,
borderBottomRightRadius
,
}
=
style
;
Object
.
assign
(
rippleContainer
.
style
,
{
width
:
`
${
width
}
px`
,
height
:
`
${
height
}
px`
,
direction
:
'ltr'
,
borderTopLeftRadius
,
borderTopRightRadius
,
borderBottomLeftRadius
,
borderBottomRightRadius
,
});
setTimeout
(()
=>
{
const
wh
=
`
${
radius
*
2
}
px`
;
Object
.
assign
(
ripple
.
style
??
{},
{
width
:
wh
,
height
:
wh
,
marginLeft
:
`
${
dx
-
radius
}
px`
,
marginTop
:
`
${
dy
-
radius
}
px`
,
});
},
0
);
function
clearRipple
()
{
setTimeout
(()
=>
{
ripple
.
style
.
backgroundColor
=
'rgba(0, 0, 0, 0)'
;
},
250
);
setTimeout
(()
=>
{
rippleContainer
?.
parentNode
?.
removeChild
(
rippleContainer
);
},
850
);
el
.
removeEventListener
(
'mouseup'
,
clearRipple
,
false
);
el
.
removeEventListener
(
'mouseleave'
,
clearRipple
,
false
);
el
.
removeEventListener
(
'dragstart'
,
clearRipple
,
false
);
setTimeout
(()
=>
{
let
clearPosition
=
true
;
for
(
let
i
=
0
;
i
<
el
.
childNodes
.
length
;
i
++
)
{
if
((
el
.
childNodes
[
i
]
as
any
).
className
===
'ripple-container'
)
{
clearPosition
=
false
;
}
}
if
(
clearPosition
)
{
el
.
style
.
position
=
storedTargetPosition
!==
'static'
?
storedTargetPosition
:
''
;
}
},
options
.
transition
+
260
);
}
if
(
event
.
type
===
'mousedown'
)
{
el
.
addEventListener
(
'mouseup'
,
clearRipple
,
false
);
el
.
addEventListener
(
'mouseleave'
,
clearRipple
,
false
);
el
.
addEventListener
(
'dragstart'
,
clearRipple
,
false
);
}
else
{
clearRipple
();
}
(
el
as
any
).
setBackground
=
(
bgColor
:
string
)
=>
{
if
(
!
bgColor
)
{
return
;
}
ripple
.
style
.
backgroundColor
=
bgColor
;
};
}
function
setProps
(
modifiers
:
{
[
key
:
string
]:
any
},
props
:
Record
<
string
,
any
>
)
{
modifiers
.
forEach
((
item
:
any
)
=>
{
if
(
isNaN
(
Number
(
item
)))
props
.
event
=
item
;
else
props
.
transition
=
item
;
});
}
export
default
RippleDirective
;
src/locales/lang/en/routes/demo/feat.ts
浏览文件 @
2e79c9f3
...
...
@@ -9,6 +9,7 @@ export default {
copy
:
'Clipboard'
,
msg
:
'Message prompt'
,
watermark
:
'Watermark'
,
ripple
:
'Ripple'
,
fullScreen
:
'Full Screen'
,
errorLog
:
'Error Log'
,
tab
:
'Tab with parameters'
,
...
...
src/locales/lang/zh_CN/routes/demo/feat.ts
浏览文件 @
2e79c9f3
...
...
@@ -9,6 +9,7 @@ export default {
copy
:
'剪切板'
,
msg
:
'消息提示'
,
watermark
:
'水印'
,
ripple
:
'水波纹'
,
fullScreen
:
'全屏'
,
errorLog
:
'错误日志'
,
tab
:
'Tab带参'
,
...
...
src/main.ts
浏览文件 @
2e79c9f3
...
...
@@ -5,7 +5,7 @@ import router, { setupRouter } from '/@/router';
import
{
setupStore
}
from
'/@/store'
;
import
{
setupAntd
}
from
'/@/setup/ant-design-vue'
;
import
{
setupErrorHandle
}
from
'/@/setup/error-handle'
;
import
{
setupGlobDirectives
}
from
'/@/
setup/
directives'
;
import
{
setupGlobDirectives
}
from
'/@/directives'
;
import
{
setupI18n
}
from
'/@/setup/i18n'
;
import
{
setupProdMockServer
}
from
'../mock/_createProductionServer'
;
import
{
setApp
}
from
'/@/setup/App'
;
...
...
src/router/menus/modules/demo/feat.ts
浏览文件 @
2e79c9f3
...
...
@@ -6,6 +6,9 @@ const menu: MenuModule = {
menu
:
{
name
:
t
(
'routes.demo.feat.feat'
),
path
:
'/feat'
,
tag
:
{
dot
:
true
,
},
children
:
[
{
...
...
@@ -45,6 +48,13 @@ const menu: MenuModule = {
name
:
t
(
'routes.demo.feat.watermark'
),
},
{
path
:
'ripple'
,
name
:
t
(
'routes.demo.feat.ripple'
),
tag
:
{
content
:
'new'
,
},
},
{
path
:
'full-screen'
,
name
:
t
(
'routes.demo.feat.fullScreen'
),
},
...
...
src/router/routes/modules/demo/feat.ts
浏览文件 @
2e79c9f3
...
...
@@ -87,6 +87,14 @@ const feat: AppRouteModule = {
},
},
{
path
:
'ripple'
,
name
:
'RippleDemo'
,
component
:
()
=>
import
(
'/@/views/demo/feat/ripple/index.vue'
),
meta
:
{
title
:
t
(
'routes.demo.feat.ripple'
),
},
},
{
path
:
'full-screen'
,
name
:
'FullScreenDemo'
,
component
:
()
=>
import
(
'/@/views/demo/feat/full-screen/index.vue'
),
...
...
src/views/demo/feat/ripple/index.vue
0 → 100644
浏览文件 @
2e79c9f3
<
template
>
<div
class=
"p-4"
>
<div
class=
"demo-box"
v-ripple
>
content
</div>
</div>
</
template
>
<
script
lang=
"ts"
>
import
{
defineComponent
}
from
'vue'
;
import
{
Alert
}
from
'ant-design-vue'
;
import
RippleDirective
from
'/@/directives/ripple'
;
export
default
defineComponent
({
components
:
{
Alert
},
directives
:
{
Ripple
:
RippleDirective
,
},
setup
()
{
return
{};
},
});
</
script
>
<
style
lang=
"less"
scoped
>
.demo-box
{
display
:
flex
;
width
:
300px
;
height
:
300px
;
font-size
:
24px
;
color
:
#fff
;
background
:
#408ede
;
border-radius
:
10px
;
justify-content
:
center
;
align-items
:
center
;
}
</
style
>
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论