这是我参与8月更文挑战的第16天,活动详情查看:8月更文挑战
转个弯
惯例:前言
原定计划到这一部分应该是讲业务组件了。
但是想来,业务组件本身和组件库的关系不算特别大,更多的是一种工作中的经验积累;其次,业务组件也是涉及到一些系统组件的,所以换个顺序,先说系统组件。再谈业务组件。
系统组件在我最初的设想里,主要是一些提供给项目展示信息的组件,例如交互反馈、信息提示、导航提示等。那么在这一部分中也将围绕几个常见的系统组件进行解析。
提示信息组件。
提示信息组件在移动端看的比较多,多见于应用内通知。
但是在PC端也是尤其用处的,以掘金为例,常见于bug的时候,或者错误信息通知
喏,就像掘金的这个信息,属于提醒作者的信息。
但是不得不吐槽一句,真的不友好,讲道理,这类提示不应该是输入框红框+附近文字提示的吗? 或者类似于下图。
当然,吐槽归吐槽,再怎么这也是一个比较好拿来距离的Notice组件了。
从布局开始的组件
既然要开始做了,自然是要先放下掘金,先考虑下常见的此类通知应该如何去设计。
在移动端的话,需要考虑三大交互: 从上到下的出现效果、从下到上隐藏、用户手动隐藏通知、点击事件,此外就是标题,内容,图标,
而在PC端时,内容版块不变,还是标题、内容、图标,并且除内容外应该都是可选的。出现隐藏方式可以自由设计。并且可以考虑当用户鼠标悬浮时,判断为用户正在查看内容,暂停隐藏的倒计时。
先看布局。
block content
transition(
name="notice"
@before="beforeLeave"
@leave="leave"
@after="afterLeave"
appear
)
div(
class="yx-notice-content-rect"
v-if="isShow"
@mouseover="endTime"
@mouseout="startTime"
)
div.yx-notice-content
div(
class="yx-notice-bar"
v-if="duration"
:class="type"
)
i(:style="{width: bar + '%'}")
span(
class="yx-notice-icon"
v-if="type"
)
i(:class="[icon || iconType[type], type]")
div.yx-notice-title {{title}}
div(
class="yx-notice-description"
v-if="content"
) {{content}}
span(
class="yx-notice-close"
@click="close"
)
i.yx-icon-x
补充一下,其实左上角应该有
success的icon,但是我懒得填充icon图标库,就没有了,大家脑补下。再补充一下,右上角要有个关闭的按钮,同理,懒。嘻嘻嘻。
逻辑部分
逻辑部分,主要是完善刚刚说的几个交互的部分。
首先从隐藏说起,本身的出现隐藏没什么,css也能控制,主要是鼠标悬停时,停止倒计时。
// 控制当前通知的进度
const progress = () => {
if(s <= t) {
bar.value = (s/t) * 100
s += 100
} else {
endTime()
close()
}
}
// 开始计时
const startTime = () => {
if(props.duration > 0) time = setInterval(progress, 100)
}
// 暂停/结束计时
const endTime = () => {
clearInterval(time)
time = null;
}
关闭通知栏以及点击事件。
// 关闭通知
const close = () => {
isShow.value = false;
}
const emits = defineEmits(['click'])
const handleClick = () => {
// code
emits('click')
}
最后
最后就是对事件的挂载了,这类组件一般挂载在全局。但挂载全局还是组件内,影响不大。
import element from './notice.vue';
let NoticeWrap;
// 生成dom 无需在template内另写
function createNoticeWrap(){
const NoticeWrap = document.createElement('div');
NoticeWrap.className = 'yx-notice-wrap';
document.body.appendChild(NoticeWrap)
return NoticeWrap
}
// 挂载到根节点
function createComponent(component, props){
const vnode = h(component, props)
render(vnode, document.createElement('div'))
return vnode.component
}
function noticeCreate(props, type){
if(!props.title){
return
}
if(type){
props.type = type;
}
if(!NoticeWrap){
NoticeWrap = createNoticeWrap()
}
const component = createComponent(element, props);
NoticeWrap.appendChild(component.vnode.el)
}
function notice(props){
noticeCreate(props)
}
// 不同的type,通过props传递给组件内。
;['info','error','success','warning'].forEach(type => {
notice[type] = props => noticeCreate(props, type)
})
export default notice;
----------------------------
// 调用
// main.js
import notice from '@/components/notice/index';
app.config.globalProperties.$notice = notice;
// pages
this.$notice.info({
title: 'Notice 通知',
content: 'notice内容 ',
// icon: '',
// duration: ''
})
到此结束,快乐GG。