做前端的人在面临页面需要某种效果或插件的时候,都会想,是从网上找呢,还是自己造轮子开发。
如果在需求比较紧张的时候我们可能会选择从网上找相关的插件,然后学习它的用法。但是从网上找的通常功能太大太全,而且存在一个学习成本,还有可能不完全符合我们项目的需求,这样改起来也并不轻松。
所以在需求不是很紧张的时候,我们还是自己慢慢造轮子吧,这样也知根知底,容易修改。
如何开发一个轻量级比较适用的插件
- 减少对UI的限制
- 提供api,易于扩展
例如,我们要做一个textarea输入文本域支持输入emoji的插件。
确定需求
- 点击表情选择按钮,输入框支持展示emoji表情
- 复制粘贴文本自动清除格式
默认设置和选项
根据需求,我们需要一个图片的路径path参数,需要一个emoji文件名数组icons参数,还需要一个触发emoji的dom节点button, 代码如下:
(function($, window, document) {
$.fn.emoji = function(options) {
var settings = $.extend({}, {
path: '',
icons: {},
button: null
}, options)
return this.each(function() {
// emoji plugin code here
})
}
})
插件原理和可用性
emoji插件的原理:大家都知道textarea是不支持html的,而我们展示emoji是通过转换成html格式来实现的。那么,怎么才能既支持文本输入又支持html呢。html5来拯救世界了!
contenteditable 属性是 HTML5 中的新属性。
语法:
<element contenteditable="true|false">
经验告诉我们,在使用新属性的时候不要盲目,不要像发现新大陆一样兴奋地立即使用,稳妥些我得看下它的兼容性,can i use contenteditable ?
主流的浏览器大部分还是支持的,ie11以下就不支持了,为了向下兼容,我们得判断一下,采取两种机制,保证在不支持的情况下不出问题。
(function($, window, document) {
$.fn.emoji = function(options) {
var settings = $.extend({}, {
path: '',
icons: {},
button: null
}, options)
return this.each(function() {
var $textarea = $(this)
if ('contentEditable' in document.body) {
new Emoji_Content($textarea, settings);
} else {
new EmojiArea_Textarea($textarea, settings);
}
})
}
})
虽然现在解决了编辑问题,但是编辑的过程中会有很多操作,比如光标的定位,复制文本区域等各种问题,这里需要乃们对window.getSelection有一定的了解。这篇文章对他的属性和方法有详细的解释javascript标准selection操作
插入一个表情符:
- 获取当前的range对象
- 将range添加到selection对象中
- 插入表情符,从当前的selection对象中获得某个range对象,删除range区域的文本内容,创建并插入img节点,设置img节点在range范围的开始点
Method
根据上面的思路,构成下面的四个方法:
var methods = {
// 获取选中区域
saveSelection: function() {
// 非ie下
if (window.getSelection) {
var sel = window.getSelection()
// 选中区域的数组,支持多选
var ranges = []
if (sel.rangeCount) {
for (var i = 0; i < sel.rangeCount; i++) {
ranges.push(sel.getRangeAt(i))
}
}
return ranges
} else {
console.log('暂不支持ie浏览器!')
}
},
pureSelection: function(saveSelection) {
// 非ie下
if (window.getSelection) {
var sel = window.getSelection()
// 先移除所有的range对象,保证range是来自插入符号的,避免插入符号的时候输入多余的文本
sel.removeAllRanges()
for (var i = 0; i < saveSelection.length; i++) {
// 将range添加到selection中,在谷歌中不允许同时存在多个range
sel.addRange(saveSelection[i])
}
}
},
replaceSelection: function(content) {
var sel = window.getSelection()
var range = null
var node = typeof content === 'string' ? document.createTextNode(content) : content
if (sel.getRangeAt && sel.rangeCount) {
range = sel.getRangeAt(0)
// 删除range区域应该选中的文本
range.deleteContents()
// 往range区域插入一个空的文本节点
range.insertNode(document.createTextNode(' '))
range.insertNode(node)
// 设置插入符号后的位置为起始点
range.setStart(node, 0)
}
},
// 把符号插入textarea中
insertAtCursor: function(text, el) {
var content = ' ' + text
var val = el.value
var selectionStart = el.selectionStart
var selectionEnd = el.selectionEnd
var endIndex = 0
var startIndex = 0
var range = null
if (typeof selectionStart != 'undefined' && typeof selectionEnd != 'undefined') {
startIndex = selectionStart
endIndex = selectionEnd
el.value = val.substring(0, startIndex) + text + val.substring(endIndex)
// 重置插入符号后输入元素selection的起始和终止位置
el.selectionStart = el.selectionEnd = startIndex + text.length
}
}
}
未完~