类似QQ表情的制作
前言
工作要求需要一款图标控件,具体要求就是选择可以选择图标,选择后的图标要上传并保存到数据库,有点像QQ更换头像或者qq那样选择表情一样,刚开始楼组胆大,自己做了一个,效果嘛。马马虎虎(惨不忍睹),老大终于看不过去了,就说,你这是可以找一个插件的,应该有的,嗯?什么意思,也就是我前几天做的东西都没用了?没办法,只好上网找,功夫不负有心人,其实还是找到一些的,做一下对比
表情插件
1.qqface ,单纯的qq表情的插件,没有扩展
2.emoji-master,支持qq表情,支持后台数据json格式(重要)qqface网站
3.jquery.sinaEmotion 封装的新浪表情,丰富完美,但是貌似不支持后台数据
选择插件
工作要求,图标是要后台生成的,所以选用了相对简单暴力的emoji-master,
使用方法
- 引入jquery文件,可以直接使用百度的CSDN
<script src="http://libs.baidu.com/jquery/1.9.0/jquery.min.js"></script>
- 引入underscore.js文件,这个是js的集合集,为项目中提高简单高效的方法
<script type="text/javascript" src="js/underscore-min.js"></script>
- 网站提供了引入editor.js文件,该文件该文件提供了一个文本框插入文本的方法,仅用于需要自己写编辑器插入表情的情况。(但是我在项目中并未引入,并不太需要,看情况而定)
<script type="text/javascript" src="js/editor.js"></script>
- 引入该插件的主js文件(重要)
<script type="text/javascript" src="js/emojis.js"></script>
- 引入css文件,该文件定义了表情的基本样式,可以自己改写样式。
<link rel="stylesheet" type="text/css" href="css/emoji.css">
- 需要指定一个html标签容器提供容纳表情
<div id="emoji" class="emoji-container">
![](emoji/unicode/1f604.png)
</div>
注意:id="emoji" 是为重要的,必须指定的,默认的emoji-container的样式,里面定义一个img标签,默认的是emoji-btn的样式,也是必须指定的。
- 初始化插件
$('#emoji1').emoji({
//- 参数列表
});
参数讲解
- data
data是数据源,表情的数据,是一个json数组格式(就是看重的是json数组);
data:[
{"typ":"EmojiCategory-People","nm":"数据库",
"items":[
{"name":"bbs","src":"app-bbs"},
{"name":"ERP","src":"app-ERP"},
{"name":"ISM","src":"app-ISM"}
]},
{"typ":"EmojiCategory-sys","nm":"应用系统",
"items":[
{"name":"IIS","src":"CH-IIS"},
{"name":"DB","src":"CH-DB"},
{"name":"oracle","src":"CH-oracle"}
]},
....
]
里面的key是固定的,在项目中别修改,typ是图标分类,nm是分类名字,name是图标中文名也就是title,src是图标英文名
- path
表情的图片的路径 - category
要显示的表情分类,默认的完整分类为(没有顺序之分,与上面的typ一致):
category: ['EmojiCategory-People','EmojiCategory-Nature','EmojiCategory-Objects','EmojiCategory-Places','EmojiCategory-Symbols']
- showbar
是否显示左侧的分类菜单,如果只有显示一个分类,可以选择不显示 - trigger
分类切换的事件,默认为click,可以设置任意鼠标事件,mouseover也可以的
事件
- insertAfter
这是该插件的唯一的事件,表示点击每个表情图片发生的事件,如果需要把表情插入到文本框中,我们这样写的
$(function(){
var em = $('#emoji').emoji({
insertAfter: function(item){
$('#area').insertContent('[:'+item.name+':]')
}
});
})
其中item参数是一个json对象,包括name和src
name是该表情的字符串标识
src表示表情图片的路径
数据处理
该表情包是处理前端的展示,最终我们将数据存到了数据库里面,比如一条留言,那么我们该怎么样来展示这条留言呢?有两种方式来阻止文本:
1. 直接存表情图片路径
如果我们将表情图片的路径存到了数据库里面,可以直接显示,这种方法会将图片的路径写死,不推荐
2. 存表情的标识
即我们上面提到的insertAfter中的item.name 然后我们可以通过正则去将标识替换成图片。
更新
原插件中的效果是,页面初始化后默认加载第一个分类的所有图片,如果你觉得这会带来额外的带宽,可以选择在点击插入表情图标后才初始化整个插件,而后才加载图片。那么你可以将 emojis.js 中的:
return this.each(function(){
render_nav(this,options)
render_emoji(this,options)
switchitem(this,options)
togglew(this,options)
})
修改成
return this.each(function(){
var obj = this
$(this).find('.emoji-tbtn').one('click',function(){
render_nav(obj,options)
render_emoji(obj,options)
switchitem(obj,options)
togglew(obj,options)
})
})
data 格式数据源
前言
如果我们使用的data不是并不是本地的的路径而是项目的中的一个文件,根据文件里的元素名字,自动生成的
这是就需要读取文件的元素
例如:
我需要读取下载的字体图标来作为数据源,字体图标的文件格式如:
如果使用的是svg需要引入相应的js,以iconfont为例
symbol引用
- 引入js
//at.alicdn.com/t/font_8d5l8fzk5b87iudi.js
- 引入加入通用css代码(引入一次就行):
<style type="text/css">
.icon {
width: 1em; height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
</style>
- 实例
<svg class="icon" aria-hidden="true">
<use xlink:href="#icon-xxx"></use>
</svg>
symbol文件结构如下所示
<li>
<svg class="icon" aria-hidden="true">
<use xlink:href="#icon-shujubeifen"></use>
</svg>
<div class="name">数据备份</div>
<div class="fontclass">#icon-node_host_shujubeifen</div>
</li>
<li>
<svg class="icon" aria-hidden="true">
<use xlink:href="#icon-realtime"></use>
</svg>
<div class="name">实时状态</div>
<div class="fontclass">#icon-node_app_realtime</div>
</li>
读取文件
使用JavaScript是无法读取本地文件的,所以要想读取文件只能使用后台语言读取,这里我找到一个插件,就是JSOUP
jsoup的读取文件
jsoup的使用方法:
jsoup的下载和安装方法:
Download and install jsoup;
由于公司使用的是Maven构建的
所以只需要引入
<dependency>
<!-- jsoup HTML parser library @ https://jsoup.org/ -->
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.10.3</version>
</dependency>
jsoup的读取方法:
使用 jsoup 对 HTML 文档进行解析和操作
后台Java文件编写
说明
如果要是对本地文件进行解析,就需要本地文件中命名的规范,如面本地文件的展示,#icon-node_app_sql
#icon 是系统自带的,node_app是分类名,sql是数据源名字,这样就可以使用下列的Java文件了
由于我是前端,java并不会太多(其实,连语法都说不清楚),求大神轻拍。由于数据格式使用的公司自己封装的eiInfo类,所以只提供java文件,中间传输的方式不再说明
String rootPath = getClass().getResource(".").getFile().toString();
System.out.println(rootPath);
String Path = rootPath.substring(0,rootPath.indexOf("/WEB-INF"));
System.out.println(Path);
File input = new File(Path+"\\console\\assets\\font\\demo_symbol.html");
System.out.println(input);
Document doc = Jsoup.parse(input, "UTF-8", "http://example.com/");
// Elements iconLists = doc.getElementsByClass("icon_lists");
Elements fontClass = doc.getElementsByClass("fontclass");
Elements fontName = doc.getElementsByClass("name");
String[] fontClassList = new String[fontClass.size()];
String[] fontNameList = new String[fontName.size()];
for(int i=0;i<fontClassList.length;i++){
fontClassList[i] = (fontClass.get(i).text());
}
for(int i=0;i<fontNameList.length;i++){
fontNameList[i] = (fontName.get(i).text());
}
Map<String,String> nameMap = new HashMap();
List result = new ArrayList();
for(int i=0;i<fontClassList.length;i++){
nameMap.put(fontClassList[i],fontNameList[i]);
}
Map<String,List> resultMap = new HashMap<String,List>();
List hostList = new ArrayList();
List appList = new ArrayList();
List otherList = new ArrayList();
List softwareList = new ArrayList();
for(int i=0;i<fontClassList.length;i++){
Map perfixMap = new HashMap();
if(fontClassList[i].lastIndexOf('_')>0) {
//类名截取
String perfix = fontClassList[i].substring(6, fontClassList[i].lastIndexOf("_"));
//名字截取
String lastfix = fontClassList[i].substring(6);
//title截取
String lastName = fontNameList[i].substring(fontNameList[i].lastIndexOf("_")+1);
Map map = new HashMap();
map.put("src", lastfix);
map.put("name",lastName);
if ("node_app".equals(perfix)) {
if (!resultMap.containsKey(perfix)) {
perfixMap.put("typ", perfix);
perfixMap.put("nm", "应用系统");
resultMap.put(perfix, appList);
perfixMap.put("items", appList);
}
appList.add(map);
}
if ("node_soft".equals(perfix)) {
if (!resultMap.containsKey(perfix)) {
perfixMap.put("typ", perfix);
perfixMap.put("nm", "常用软件");
resultMap.put(perfix, softwareList);
perfixMap.put("items", softwareList);
}
softwareList.add(map);
}
if ("node_host".equals(perfix)) {
if (!resultMap.containsKey(perfix)) {
perfixMap.put("typ", perfix);
perfixMap.put("nm", "云主机");
resultMap.put(perfix, hostList);
perfixMap.put("items", hostList);
}
hostList.add(map);
}
if ("node_other".equals(perfix)) {
if (!resultMap.containsKey(perfix)) {
perfixMap.put("typ", perfix);
perfixMap.put("nm", "其他");
resultMap.put(perfix, otherList);
perfixMap.put("items", otherList);
}
otherList.add(map);
}
}
if(perfixMap.size()>0){
result.add(perfixMap);
}
}
System.out.println(result);
返回的数据格式就是
[
{
"typ":"node_app",
"items":[
{
"src":"node_app_bbs",
"name":"bbs2"
},
{
"src":"node_app_ERP1",
"name":"ERP2"
},
{
"src":"node_app_morenyingyongxitong",
"name":"默认应用系统"
}
],
"nm":"应用系统"
}
]
得到的数据格式与原数据格式一致,那么当然是可以用了
样式就是