前言
最近接到一个需求,要实现一个能输入带颜色的文字的输入框,可以渲染html字符串。立刻就想到了HTML的contenteditable属性。在HTML中,任何元素都可以编辑,只要将元素的contenteditable属性设置为true。
环境
- vue2.5
- webpack3.6
分析需要的功能
- 提供快捷键
- 提供input、change、focus、blur事件
- v-model指令可以绑定该组件
- 禁用功能
- 清空输入的内容
代码如下
EventUtil是封装的跨浏览器的事件对象。
<!--BaseEditDiv.vue-->
<template>
<div
class="base-edit-div"
:style="{'-webkit-user-modify': disabled ? 'read-only' : '', '-moz-user-modify': disabled ? 'read-only' : '', 'overflow-x': disabled ? 'hidden' : '', 'height' : disabled && !text ? '35px' : '100%'}"
contenteditable="true"
@focus="$emit('focus', $event)"
@click="$emit('click')"
@blur="$emit('blur', $event)"
@keydown="$emit('keydown', $event)"
@keyup="$emit('keyup', $event)"
@input="domInput"
></div>
</template>
<script>
import EventUtil from './EventUtil.js'
export default {
props: {
// 默认值
text: {
type: String,
default: ''
},
disabled: {
type: Boolean,
default: false
}
},
mounted () {
// 组件初始化,对innerHTML赋值
this.$el.innerHTML = this.text
// 一旦div的dom发生插入值的操作,调用domChange()方法传递值至父组件
EventUtil.addHandler(this.$el, 'DOMNodeInserted', this.domChange)
},
beforeDestroy () {
// 销毁
EventUtil.removeHandler(this.$el, 'DOMNodeInserted', this.domChange)
},
methods: {
domChange (event) {
this.$emit('input', this.$el.innerHTML, this.$el.dataset.index, event)
},
emptyInnerHTML () {
this.$el.innerHTML = ''
this.$emit('input', this.$el.innerHTML, this.$el.dataset.index, event)
},
domInput (event) {
this.$emit('input', this.$el.innerHTML, this.$el.dataset.index, event)
}
}
}
</script>
<style lang="less" scoped>
.base-edit-div{
position: relative;
outline: none;
border: 1px solid #EAECF1;
padding: 5px 26px 5px 12px;
border-radius: 2px;
box-sizing: border-box;
width: 100%;
height: 100%;
overflow: auto;
word-break: break-all;
user-select: text;
text-align: left;
}
</style>
使用
<!--HelloWorld.vue-->
<template>
<div class="content">
<base-edit-div
class="beautiful"
:text="checkHtml"
v-model="checkHtml"
>
</base-edit-div>
</div>
</template>
<script>
import BaseEditDiv from './BaseEditDiv'
export default {
components: {
BaseEditDiv
},
data () {
return {
checkHtml: '<b style="color:red;font-weight:normal" contenteditable="false">[噪音]</b>\r'
}
}
}
</script>
<style lang="less" scoped>
.content{
margin: 50px auto;
.beautiful{
width: 300px;
box-shadow: 0 2px 12px 0 rgba(0,0,0,.1);
border-radius: 4px;
border: 1px solid #ebeef5;
background-color: #fff;
overflow: hidden;
color: #303133;
transition: .3s;
}
}
</style>