1. 基本使用
<template>
<div class="comment" v-clickoutside="inputBlur">
<div class="auth-card" @click="inputFocus" ref="inpContainer">
<div
ref="inputBox"
class="input-box"
tabindex="0"
contenteditable="true"
placeholder="请输入评论(Enter换行)"
spellcheck="false"
v-handlePastestyle
@input="onDivInput"
></div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
commentValue: '',
maxLen: 120
};
},
}
</script>
<style scoped lang="less">
.comment {
width: calc(100% - 96px); // 设置宽度的作用是因为输入过长时宽度会被撑开
}
.auth-card {
border: 1px solid #f4f5f5;
background-color: #f4f5f5;
border-radius: 2px;
transition: all .3s;
.input-box {
box-sizing: border-box;
min-height: 72px;
padding: 8px 12px;
font-size: 14px;
&:empty::before {
content: attr(placeholder); // 显示placeholder
font-size: 14px;
color: #86909c;
}
&:focus {
border: none;
box-shadow: none;
outline: none;
}
}
}
</style>
2. 开发中遇到的问题
2.1 聚焦、失焦
<script>
export default {
...
directives: {
clickoutside: {
// 初始化指令
bind(el, binding, vnode) {
function documentHandler(e) {
// 这里判断点击的元素是否是本身,是本身,则返回
if (el.contains(e.target)) return false;
// 判断指令中是否绑定了函数
if (binding.expression) {
// 如果绑定了函数 则调用那个函数
binding.value(e);
}
}
// 给当前元素绑定个私有变量,方便在unbind中可以解除事件监听
el.vueClickOutside = documentHandler;
document.addEventListener('click', documentHandler);
},
unbind(el, binding) {
// 解除事件监听
document.removeEventListener('click', el.vueClickOutside);
delete el.vueClickOutside;
}
},
methods: {
/**
* 对input框相关样式作处理
* @param {borderColor} 边框颜色
* @param {bgColor} 背景色
* @param {isFocus} 是否聚焦
*/
handleInputStatus(borderColor, bgColor, isFocus) {
const inpContainerDOM = this.$refs.inpContainer
inpContainerDOM.style.borderColor = borderColor;
inpContainerDOM.style.backgroundColor = bgColor;
const inputDOM = this.$refs.inputBox;
isFocus ? inputDOM.focus() : inputDOM.blur();
},
// 点击后输入框聚焦
inputFocus() {
this.handleInputStatus('#1e80ff', '#fff', true);
},
// 输入框失焦
inputBlur() {
this.handleInputStatus('#f4f5f5', '#f4f5f5', false);
},
}
}
2.2 输入框字数超限制后,光标会移动到第一个的问题(innerText
情况)
<script>
export default {
...
methods: {
...
// 输入框输入事件
onDivInput(e) {
this.commentValue = e.target.innerText.trim().replace(/(\r\n|\r|\n)/g, ' ').replace(/\s+/, ' ');
const commentValueLen = this.commentValue.length;
if (commentValueLen > this.maxLen) {
const inpBox = this.$refs.inputBox;
inpBox.innerText = this.commentValue = this.commentValue.slice(0, this.maxLen);
// 解决输入框字数超限制后,光标会到第一个的问题
if(document.all) {
inpBox.range = document.selection.createRange();
inpBox.range.select();
inpBox.range.moveStart("character",-1);
} else {
inpBox.range = window.getSelection().getRangeAt(0);
inpBox.range.setStart(inpBox.range.startContainer, this.maxLen);
}
}
}
}
}
</script>
<script>
export default {
...
directives: {
...
// 处理粘贴时会粘贴样式的问题
handlePastestyle: {
bind(el, binding) {
function pasteHandler(e) {
// 阻止默认粘贴
e.preventDefault();
// 粘贴事件有一个clipboardData的属性,提供了对剪贴板的访问,clipboardData的getData(fomat) 从剪贴板获取指定格式的数据
var text = (e.originalEvent || e).clipboardData.getData('text/plain');
// 插入
document.execCommand('insertText', false, text);
}
el.pasteHandler = pasteHandler;
el.addEventListener('paste', pasteHandler)
},
unbind(el, binding, vnodee) {
el.removeEventListener('paste', el.pasteHandler);
delete el.pasteHandler;
}
}
}
...
}
</script>