Vue.js支持表情输入框
关于这上功能的实现,有两个事表。 - 表情列表 - 支持表情输入的输入框
我们网站原来的表情输入其实是emoji(日本在无线通信中所使用的视觉情感符号),也就是可以以字符的形式输入,跟普通文字没啥区别,但呢看起来不同 浏览器,不同的客户端预览的效果就不一样了。所以我们换成图片会更好。
如果换成了图片,input输入不支持图片输入呀,所以我们要造一个自定义的输入框,支持图片和文字内容输入。
网站的效果可以查看网站的地址:
https://www.sunofbeach.net/moment
表情资源获取
表情图片资源,同学们可以到github上去获取。
https://github.com/twitter/twemoji
里面大概有3000多个表情,同学们可选择部分即可。
我这里选择了130个表情,然后命名则是1~130
修改好命名以后,把图片上传到自己的CDN上,或者同学可以是使用阳光沙滩提供的资源。
访问地址:https://cdn.sunofbeaches.com/emoji/1.png
这个数字的范围是1~130
到此,我们的表情资源就准备好了。
项目创建
项目创建的话,Vue项目也可,nuxt.js项目也可以的。反正都是vue.js
如果同学们不懂的话就看这篇文章的配套课程吧。
表情面板编写
编写表情面板之前,我们先确定结构。
- 最近使用
- 全部
一共四部分,title+内容
代码:
<div class="emoji-container">
<div class="emoji-list">
<div class="emoji-title-history" v-if="historyList.length!==0">
最近使用
</div>
<div class="emoji-history-list" v-if="historyList.length!==0">
<span v-for="i in historyList" :key="i">
<img class="emoji-item" :src="'https://cdn.sunofbeaches.com/emoji/'+i+'.png'">
</span>
</div>
<div class="emoji-title-all">
全部
</div>
<div class="emoji-all-list">
<span v-for="i in 130" :key="i">
<img class="emoji-item" :src="'https://cdn.sunofbeaches.com/emoji/'+i+'.png'">
</span>
</div>
</div>
</div>
CSS样式代码:
.emoji-container {
width: 420px;
margin: 30px auto;
}
.emoji-item {
width: 45px;
height: 45px;
padding: 10px;
}
.emoji-list {
box-shadow: 0 10px 10px 0 #efefef;
width: 400px;
height: 300px;
padding: 10px;
overflow-y: scroll;
overflow-x: hidden;
}
/*滚动条效果*/
.emoji-list::-webkit-scrollbar {
width: 10px;
}
.emoji-list::-webkit-scrollbar-track {
background-color: #F9FAFB;
-webkit-border-radius: 2em;
-moz-border-radius: 2em;
border-radius: 2em;
}
.emoji-list::-webkit-scrollbar-thumb {
background-color: #E5E6EB;
-webkit-border-radius: 2em;
-moz-border-radius: 2em;
border-radius: 2em;
}
历史数据:
<script>
export default {
name: 'App',
data() {
return {
historyList: [10,23,1,33,22]
}
}
}
</script>
预览效果:
到这里呢,我们的表情包面板就有了,关于点击事件的处理,稍后再写。
输入框编写
原生的Input标签不支持图片输入,所以我们使用div标签,并且让这个div可以输入内容。
所以这个代码呀:
<div class="input-panel" ref="msgInputContainer"
contenteditable="true" spellcheck="false">
</div>
- contenteditable = "true" 表示内容可以编辑
CSS样式代码:
.input-panel {
margin: 0 auto;
background: #efefef;
width: 400px;
height: 100px;
outline: none;
border: #1390ff 2px solid;
border-radius: 4px;
padding: 5px;
}
这样子,就可以得到了一个可以编辑的框框了。
但是呢,我们这个输入框不输入东西的时候,并没有提示信息
我们网站的是有提示信息的
这个怎么实现呢?
添加placeholder属性!发现无效!!!
<div class="input-panel" ref="msgInputContainer"
placeholder="一起探讨先进的摸鱼技术!"
contenteditable="true" spellcheck="false">
</div>
还得加CSS样式代码
.input-panel:empty:before {
content: attr(placeholder);
position: absolute;
color: gray;
background-color: transparent;
}
这样子,似乎我们的输入框也有了。
整合一下代码
<template>
<div id="app">
<div class="mo-yu-container">
<div class="input-part">
<div class="input-panel" ref="msgInputContainer"
placeholder="一起探讨先进的摸鱼技术!"
contenteditable="true" spellcheck="false">
</div>
<div class="action-bar" id="input-action-bar">
<span class="emoji-btn" @click="handleEmojiPanelVisibility">表情</span>
<span class="post-btn">发布</span>
</div>
</div>
<div class="emoji-container" id="emoji-container" v-show="isEmojiShow">
<div class="emoji-list">
<div class="emoji-title-history" v-if="historyList.length!==0">
最近使用
</div>
<div class="emoji-history-list" v-if="historyList.length!==0">
<span v-for="i in historyList" :key="i">
<img class="emoji-item" @click="onEmojiClick(i)"
:src="'https://cdn.sunofbeaches.com/emoji/'+i+'.png'">
</span>
</div>
<div class="emoji-title-all">
全部
</div>
<div class="emoji-all-list">
<span v-for="i in 130" :key="i">
<img @click="onEmojiClick(i)" class="emoji-item"
:src="'https://cdn.sunofbeaches.com/emoji/'+i+'.png'">
</span>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
historyList: [],
isEmojiShow: false
}
},
methods: {
handleEmojiPanelVisibility() {
this.isEmojiShow = !this.isEmojiShow;
},
removeHistory() {
//清空历史
},
//表情点击事件
onEmojiClick(i) {
//如果输入框没有焦点,那么让它获取焦点
if (this.$refs.msgInputContainer !== document.activeElement) {
this.$refs.msgInputContainer.focus();
}
//往焦点出插入内容
let targetUrl = "https://cdn.sunofbeaches.com/emoji/" + i + ".png";
console.log("targetUrl==> " + targetUrl);
let imageTag = `<img src="${targetUrl}" width="20" height="20">`;
document.execCommand("insertHtml", false, imageTag);
//保存历史记录
//先要获取出来,然后进行拼接
let targetStr = i.toString();
let items = window.localStorage.getItem("emoji-history");
if (items) {
//进行切割
let currentIndex = 0;
let itemArray = items.split(",");
for (let j = 0; j < itemArray.length; j++) {
//从头开始加,targetStr一定是有的了
//所以,先添加逗号
//判断i是否已经包含了
let item = itemArray[j];
if (targetStr.indexOf(item) === -1) {
targetStr += ",";
targetStr += item;
currentIndex++;
}
//1+1,2,3,4,5==>6个元素
if (currentIndex > 4) {
break;
}
}
}
//console.log("targetStr ==> " + targetStr);
//最多保存6个,也就是最近使用
window.localStorage.setItem("emoji-history", targetStr);
this.updateHistory();
},
updateHistory() {
let items = window.localStorage.getItem("emoji-history");
if (items) {
this.historyList = items.split(",");
}
}
},
mounted() {
//防止点击表情的时候输入框失去焦点
let inputPart = document.getElementById("input-action-bar");
if (inputPart) {
inputPart.addEventListener("mousedown", function (e) {
e.preventDefault();
})
}
let emojiContainer = document.getElementById("emoji-container");
if (emojiContainer) {
emojiContainer.addEventListener("mousedown", function (e) {
e.preventDefault();
})
}
//更新历史
this.updateHistory();
}
}
</script>
<style>
html {
background: #F4F5F6;
}
.emoji-btn {
padding: 5px 0;
color: dodgerblue;
cursor: pointer;
}
.post-btn {
cursor: pointer;
border-radius: 4px;
padding: 5px 20px;
background: dodgerblue;
color: white;
}
.action-bar {
display: flex;
justify-content: space-between;
}
.action-bar {
padding: 10px 10px 0;
}
.input-part {
padding: 10px;
}
.mo-yu-container {
width: 420px;
background: #fff;
margin: 30px auto;
}
.emoji-item {
width: 45px;
cursor: pointer;
height: 45px;
padding: 10px;
}
.emoji-list {
width: 400px;
height: 300px;
padding: 10px;
overflow-y: scroll;
overflow-x: hidden;
}
/*滚动条效果*/
.emoji-list::-webkit-scrollbar {
width: 10px;
}
.emoji-list::-webkit-scrollbar-track {
background-color: #F9FAFB;
-webkit-border-radius: 2em;
-moz-border-radius: 2em;
border-radius: 2em;
}
.emoji-list::-webkit-scrollbar-thumb {
background-color: #E5E6EB;
-webkit-border-radius: 2em;
-moz-border-radius: 2em;
border-radius: 2em;
}
.input-panel:focus {
border: dodgerblue 2px solid;
}
.input-panel img {
margin: 0 2px;
vertical-align: middle;
}
.input-panel {
margin: 0 auto;
font-size: 14px;
line-height: 20px;
background: #efefef;
width: 380px;
height: 100px;
outline: none;
border: #F4F5F6 2px solid;
border-radius: 4px;
padding: 5px;
}
.input-panel:empty:before {
content: attr(placeholder);
position: absolute;
color: #4d4d4d;
background-color: transparent;
}
</style>
最后的效果
代码地址
https://github.com/TrillGates/emoji-demo
请看我表演
//TODO:视频