XIANFESchool / FE-problem-collection

前端问题收集和知识经验总结
https://github.com/ShuyunXIANFESchool/FE-problem-collection/issues
63 stars 22 forks source link

web前端emoji表情 #33

Open mmmaming opened 8 years ago

mmmaming commented 8 years ago

随着互联网的发展,传统的文字已经不能满足人们生活交流的需要,有时一张图片,一个表情,更能传递想要表达的内容。(具体可参考微信斗图-_-! )如今比较有名的 emoji 已经可以被大部分设备所兼容,那么问题来了,如何在网页上显示一个emoji表情呢?

通常作为前端,我们接收到的表情不会是一张图片,而是类似 :smile : 、[微笑]、/微笑这样的字符串,那么如何将字符串转换为对应的表情就是问题的关键。毋庸置疑,通过正则表达式对相应的字符串作匹配替换,从而将对应的emoji表情显示出来是比较好的一个方法。

首先,本地要有一个emoji表情库,类似 1111 或者一个雪碧图 22 本地表情文件的不同,对应的处理方法也会不一样。 有了这样的一个表情库文件,接下来就是对相应的表情字符串进行匹配。

其次:匹配,就免不了要用到正则表达式,针对不同的表情字符串,需要写不同的匹配规则。如需匹配[微笑]或者/微笑格式的表情,对应的正则如下

//对于元字符 如 [] {} + ? 等,需要转义
var reg = new RegExp("\\[" + emoji.name + "\\]|\\/" + emoji.name, "gm");

写好了匹配规则,接下来要对需要转换的字符串进行替换。 replace()很好的帮我们解决了这个问题。

var result  = input.replace(reg, '<img class="emoji" src="' + emoji.src + '"/>');

那么问题来了,在这两行code中,用到了emoji.name,emoji.src,这个emoji对象到底是个什么样的东西。其实这个emoji对象相当于一个emoji配置,他的code长这个样子:

var emojis = [{
        name: '微笑',
        src: 'emoji/default/0.png'
    }, {
        name: '撇嘴',
        src: 'emoji/default/1.png'
    }, {
        name: '发呆',
        src: 'emoji/default/3.png'
    }]

我们用到的emoji则是其中的一个个对象。最后,我们需要循环这个数组,将每个对应的字符串匹配成对应的表情。完整代码如下:

function filterEmoji(input, emoji) {
    var regexp = new RegExp('\\[' + emoji.name + '\\]|\\/' + emoji.name, 'gm');
    var result = input.replace(regexp, '<img class="emoji" src="' + emoji.src + '"/>');
    return result;
}

function emoji($sce) {
    return function(input) {
        // 循环emojis配置表,匹配对应表情
        emojis.forEach(function(emoji) {
            input = filterEmoji(input, emoji);
        });
                //这里由于angular的安全限制,使用$sce将匹配到的表情转换为可识别的标签。
        return $sce.trustAsHtml(input);
    };
}

最后,在需要转换表情的地方,加上这个emoji过滤器就Ok了。

当然,这种方法有一个弊端就是需要加载很多的emoji表情图片,可以优化为用一张雪碧图去搞定。 在写法上也要有一些变化。首先肯定不能再通过标签去显示每一张表情图片,而是通过css添加background来实现。我们需要一个css的配置文件去匹配每个表情对应的雪碧图的位置。

.emoji {
  display: inline-block;
  background: url(emoji/default/emoji.png) no-repeat;
  width: 21px;
  height: 21px
}
.emoji.emoji_dai {
  background-position: 0 0
}
.emoji.emoji_smile {
  background-position: -21px 0
}

emojis也需要做一些修改

var emojis = [{
        name: '微笑',
        css: 'emoji_smile'
    }, {
        name: '发呆',
        css: 'emoji_dai'
    }]

匹配函数修改为:

function filterEmoji(input, emoji) {
  var regexp = new RegExp('\\[' + emoji.name + '\\]|\\/' + emoji.name, 'gm');
  var result = input.replace(regexp,"<i class='emoji" + b + "></i>");

}

最后,一个完整的emoji表情匹配到底结束。