邮箱收件人组件(vue版)成长历程(一)
邮箱收件人组件(vue版)成长历程(一)
前期项目中需要优化原始的收件人、抄送、密送部分,换成更加现代化的样式和用户,当时将这部分抽象成一个组件了,最近的需求是发件人也要使用该组件,鉴于发件人比收件人等需要校验的地方和交互习惯变动点较多,进行了重构,在此过程中发现自己当初思维还是比较局限,特发文记录下。
先看看发件人组件的样式吧
很显然,这里的收件人支持最少两种写法,一种是纯粹的只有收件地址,比如第一个test@qq.com
,同时也支持第二种写法是带收件人和收件人地址另一个测试<anthortest @qq.com>
,毕竟在可读性上第二个比第一个要好。
以下为了方便描述,我们把第二图中的第一个收件人状态称为预览态,第二个收件人状态称为编辑态。
当时产品是参考网易邮箱大师(万恶之源)来实现功能的 总共需要支持以下功能
test@qq.com
和另一个测试</anthortest><anthortest @qq.com>
两种格式- 在预览态校验邮箱合法性并进行对应的标识
- 预览态双击进入编辑态,失去焦点或者回车后回到预览态
- 支持搜索,搜索候选项能用键盘上下键实现选择,能够用回车上屏
- 预览态时支持鼠标单击后高亮,图一中第一个就是被点击选中的,颜色与第二个稍微有点不同,再删除键时删除,删除后光标在前一个内容后面,并且可以一直向左删除
- 点击两个收件人预览态(如果有的话)中间空白处插入新的,然后再按删除键可以一直向左删除
- 兼容Outlook、网易邮箱大师的收件人的复制、粘贴 当时主要参考网易邮箱大师客户端和gmail邮箱网页版
当然要看代码实现的话,只能看到gmail邮箱的,它的交互不太符合产品要求,但是那都是不是技术难点。 首先需要支持这些样式,原来的input是肯定不行了,那只能div了,怎么让它可编辑呢?我发现gmail在输入还是用的input,预览态时是用的div实现,当时出于挑战自己和青铜的倔强,想试着换个方案,完全使用可编辑div来实现。。。这个小小的倔强为后续很多功能瓶颈埋下了隐患。。。
整体逻辑
我们知道这个组件里面的内容其实是一个数组,数组个每个元素都是一个收件人对象。比如:
{
label: '另一个测试',
value: 'anthortest@qq.com',
editable: true,
}
我们可以用一个属性editable,来控制当时是否是编辑态还是预览态,数组里面最多只会有一个是编辑态,让里面任何一个收件人失去焦点后或者被外部赋值后进行校验并更新预览态。在整个组件空白区域内点击时就网数组里面的合适位置插入一个收件人对象,并将其editable属性置为true,然后显示对应的光标。 我们可以把整个组件分成三个部分,一个是主组件main,一个是显示/输入组件inputItem,一个是候选词列表组件candidateBox
控制鼠标光标
这个应该是最先要考虑的问题,在contenteditable的div里面是点击到哪哪里就有光标,比如在预览态双击进入编辑态后,如果含有收件人信息的化,编辑态的需要展示的内容明显要比预览多的,这时怎么控制好光标到最后面呢? 此时光标默认在它的最后面,其中光标的实现可以用Range实现
const blank = document.createTextNode('');
const range = document.createRange();
range.selectNodeContents(blank); // 让光标聚焦在最后面
getSelection().removeAllRanges();
getSelection().addRange(range);
校验
在任何一个收件人信息输入失去焦点的校验,并更新预览态
响应点击
这个需要布局配合
- 在整个组件内但是非已存在收件人信息以外的区域(上图中的蓝框区域)点击时,认为是在最后面添加新的收件人,直接在数组最后push一个新的收件人对象
- 点击到某个收件人预览态(图中的绿框)时将其高亮,如果是双击的化则将其置为编辑态,如果是单击它前面(第一个小箭头所指区域),则是在它前面再增加一个收件人。这些都可以通过当前的index来实现。
删除
整个div内容通过tabindex
实现删除
搜索
这个就比较简单了
搜索候选词
整个组件内最多只会有一个候选词选择框,它必定伴随关联着某个收件人对象
简单分析后我们会发现复杂的逻辑再inputItem里面,它要是能够切换预览态和编辑态,能控制光标,响应单击、双击。其实我们对候选词的上下键及回车上屏的响应也可以放到它上面,我们只用把这几个键盘事件来间接控制候选框的“焦点”,其实哪有什么焦点,只要让对应的颜色根据鼠标按键变化就行了,在用户感知时就感觉在移动焦点,这个我们可以让inputItem通知main,main再让candidateBox进行响应的颜色变化。inputItem作为主要的用户交互对象,将用户的鼠标和键盘行为通过事件告知main,main作为大脑据此让inputItem和candidateBox做出对应的响应。
这里需要注意的是在整体失去焦点后需要对数据做一个清空操作,因为我们这里鼠标点击后那个光标处实际上也是整个数组里面的一个inputItem,只是它是{ label: '', value: '', editable: true}
而已。
这大概就是当时做的收件人组件的主要内容了,因为是公司项目,没法展示代码,欢迎和大家进行技术交流。
写不动了,关于在这个收件人组件的弊端和为何不满足简单扩展成发件人来使用,发件人和收件人需求点有何不同?这个部分内容下次再写。
- 分类:
- Web前端
相关文章
前端框架vue+wordpress做后端
目前正在利用闲暇时捯饬一下自己的博客,毕竟这么久没有维护了,wordpress是可以用restful API来获取数据的,决定前端用vue实现,目前正在尝试中,今天做了其中很小的一部分,就是博客目录 阅读更多…
Vue同一路由跳转页面不刷新解决方案及注意事项之二
之前写过一个 《Vue同一路由跳转页面不刷新解决方案及注意事项》 ,在这篇文章里面鞋到了怎么解决这个问题,具体内容可以点击查看,这里简单说一下,就是利用将时间戳传给路由的query,也就导致 $ro 阅读更多…
Vue和React hooks实现Select批量选择、选中条数、全选、反选实现对比
批量选择、全选、反选这些功能使用频率还是很高的,下面直接看看Vue和React分别怎么实现吧。 Vue 在使用Vue的时候是很容易实现的,我们以下列数据格式为例: const data 阅读更多…
命令式组件Message、Dialog的主流写法分析
这里还是以element-ui为例,那我们就看看里面的Message。 它的dom结构什么的就写在node-modules/element-ui/packages/notification/src/ 阅读更多…
vue发送请求是应该在mounted还是在created生命周期
一个经常会被问到的问题: 为什么不在 created 里去发ajax? created 可是比 mounted 更早调用啊,更早调用意味着更早返回结果,那样性能不是更高? 首先,一 阅读更多…
QQ邮箱、163邮箱自动保存草稿机制调研
背景 准备优化自己的邮箱项目中草稿的保存,目前是完全依赖调用后端接口保存,并且不支持自动保存功能,希望先调用主流邮箱的机制,并与之保持一致的用户体验。 QQ邮箱 页面切换时主体窗口内if 阅读更多…