来晒一下过程和逻辑,还有一些todo的部分
不能直接给大家是因为,这个是可爱的yys2077特供版(重要原因),以及还有一些版务处理的部分(完全不重要的原因)
而且我用的还不是油猴
大概写了2个小时左右,有不完善的地方,海涵(这个算是笔记?)
今天正好也看到有人要写这种东西,有一些天坑要来说一下,主要集中在最后一页里
2021.12 数据,可能有更多内容
来晒一下过程和逻辑,还有一些todo的部分
不能直接给大家是因为,这个是可爱的yys2077特供版(重要原因),以及还有一些版务处理的部分(完全不重要的原因)
而且我用的还不是油猴
大概写了2个小时左右,有不完善的地方,海涵(这个算是笔记?)
今天正好也看到有人要写这种东西,有一些天坑要来说一下,主要集中在最后一页里
先来看第一个部分
界面实现比较简单:
1. 疯狂createElement() 加 appendChild(),设置className或id,以便接下来的css和元素获取
2. 写按钮toggle的显示逻辑,显示与不显示,很方便
3. 遍历,for,把表情格子腾出来 + 预览
4. 一些简单的css动画效果 + 处理一下border的融合
根据你的元素情况,可以用 负margin 或者 border-collapse 处理
5. 由于后文要在dz的编辑器内获取 range & selection 部分,
焦点必须保证在 textarea / iframe (dz的两套逻辑) 里
于是我给表情界面里的一些元素添加了 return false;
如果出现问题可能要再 e.preventDefault,不过我没试出来问题
随后就是翻页功能:
qq里的表情翻页是一次性翻3行(每页有3行的表情)
根据测量,qq内表情预览的大小大约是70*70
内部有个几px的白边padding,图片position是center,然后加contain适应
我再测量了一下,在表情外面套了一个div作为box,每次翻页移动的高度大概是 72*3 px
(实际情况请根据各位自己写的代码和css来测量,我只是说我的情况23333)
1. 开一个Number1来记录目前页码,再开一个Boolean来判断是用户在滚动还是代码导致的滚动
最后再开一个Number2存一下移动前的移动高度
2. 添加scroll监听器,由于是代码在帮用户滚,不需要节流/防抖
3. 储存的移动高度Number2 减去 element.scrollTop
大于0是向上滚,小于0是向下滚,不考虑0,因为这时候没有滚
4. 直接用 scrollTo() 滚,高度可以直接用页码+1或-1,乘以一页高度 (72*3) 来计算应该移动到哪里
5. scrollTo 会触发监听器,然后变成无限 scrollTo,所以在每次移动后要用一开始准备的Boolean救命
我这边是 1 代表下一次监听到的是代码滚动,滚动结束后异或一下,0 则是代表下一次是用户滚动
当然,我的逻辑是一次性直接到下一页,各位也可以再加一个简单的动画逻辑
直接 requestAnimationFrame(callback) 即可
比如每次移动的距离为 当前位置s 到 目标位置t 的差的绝对值 的1/4,这样速度是从快到慢,左高右低
而qq内的目测是 慢->快->慢 ,也就是有个峰,大家可以自己去实现一下,吾辈的水平有限,有一点臃肿
最后考虑一下浏览器的兼容情况
如果ie低版本完全不兼容的话还要自己写一个setTimeout自己手动callback
最后几个兼容情况直接 || 连起来就好
什么?不是已经写完了吗??
哦 原来极光使用了图床作为表情的储存地点
对于外链图床而言,这是非常普通的一件事,最多就是表情预览加载不出来而已
可如果使用mcbbs的附件作为图床,那么每次打开页面的时候就会请求很多次图片
这些图片可能会让你被403或者别的什么
虽然浏览器的缓存可以拯救你的账号,让你很少被403,可我们还需要一些更加优雅的解决方案
逻辑
使用canvas制作 小缩略图/劣化图,取base64,再存到 localStorage 里 :
1. 假装我们有个url,createElement('canvas');
调整画布大小到和图片一致
随后把图片塞进去 drawImage();
最后 canvas.toDataURL("image/png");
[!]
得到了 base64
如果不用论坛图床,可能要考虑跨域问题(?),似乎用不上
setAttribute("crossOrigin",'Anonymous');
2. 在得到base64之前加一段压缩逻辑,
计算 背景样式 contains 的自适应情况
判断图片长和宽哪个高
假设框70x70,边框留白5px,那么内部就是60px
取长宽最大的那个,变成60px,另一条边同比例缩小即可
获得了变化后的高度,然后绘图drawImage,最后toDataURL
此外还有一个jpeg的劣化方案,与上面类似
3. 存起来
localStorage.setItem( 'emoji--' + i , base64);
由于劣化/缩略图,预览图非常非常小,不太需要在意占用的空间
不过这个只是逻辑,我觉得写的时候会有一点其他的问题
而且必须要求浏览器支持localStorage
此外,我们还要再开个数组存是否有缩略图
并且准备一套 '用户更新表情' 的逻辑,不过会比较麻烦
我没写。
剩下的就是最烦的部分了,也就是往编辑器里写入东西
我觉得比较正常优雅的方法是:
使用appendChild的方法往页面中写入script,直接使用dz自带的editor.js的函数
找个办法写callback/hook,然后就可以自己注册一些富文本编辑器内的功能了
我们就可以用自带的函数往编辑器里插入图片
可以一次性支持textarea和iframe(dz自带的两套编辑器,前者是纯文本模式,后者是非纯文本模式)
然而我的浏览器插件默认是单独插了个script进去,虽然这完全不影响我用上面的手段
我在写的时候其实是知道可以直接append的,但是必须先去读懂dz那个editor.js里的逻辑
我打开那个js一看:
惊人的变量命名 wysiwyg,真就所见即所得呗
不明觉厉的元素id_fullswitcher,_adv_s3
不想看,吐了,自己手动加吧
随后我发现了一个很离谱的东西
dz的编辑器高级模式有 纯文本模式 和 非纯文本模式
纯文本模式是 textarea (在iframe外)
非纯文本模式是 iframe (里面有另一层html)
当你点 input 的时候,它俩里的内容会互相转换
插入文本的逻辑和方案很朴素,靠range和selection得到光标的地点,然后在后面加入内容
操作 textarea 里的内容是富文本编辑器的基操
可是在外面动iframe里的东西就有点鬼畜了,超出了我能力范围
再加上是在 iframe>body 里而非 iframe>input/textarea 里,我假期里再研究下怎么插
反正现在iframe里的range和selection我拿不到
百度了一下,解决方法似乎是有的,但是我没太看懂
我看最近论坛有些脚本开发想写这个,特此过来提醒一下各位注意这个天坑
因此,我现在写的功能只有在纯文本模式下才能使用
对于ie:
有一套不符合w3c规范的方法
直接获取 theSelection = document.selection;
随后 theSelection.createRange().text = '[ img]url[/img]';
简单简单
对于非ie:
有一套 eStart = element.selectionStart; 和 eEnd = element.selectionEnd;
分别是选中区域的开始和结尾的位置
我们要的效果是,如果有选区,替换选区的内容,否则就光标后插入
到了喜闻乐见的拼串环节
element.value.substr(0,eStart) + '[ img]url[/img]' + element.value.substr(eEnd, element.value.length);
接下来,我们要移动光标到最后的部分
假装 strLength = '[ img]url[/img]'.length;
而最后的部分其实是一个光标而非一块区域,也就是说eStart应该等于eEnd
element.selectionStart = eStart + strLength;
element.selectionEnd = eStart + strLength;
[不要写连等]
不知道类型怎么样,我没开strict模式,这样写倒是能过。
todo
应该是iframe/iframe下body的原因,导致我没办法直接操作非纯文本的内容
不知道各位坛友是否有什么经验
不过大概知道了原因,我假期里可以再试着写写看
