Vue实现contenteditable元素双向绑定的方法详解

目录
  • 前言
  • contenteditable
  • 基础使用
  • 进阶使用
  • 总结

前言

如何实现一个即时通讯的聊天页面,网上有很多的开源或不开源的成品,可以直接使用,或者简单修改后使用。但在实际项目中,直接使用开源的即时通讯往往不是我们想要的,如何自己开发一个聊天页面呢。本文就着学习的目的,从0开始一步步实现一个聊天框的开发,至于消息的发送和接收,这个就得依靠后端大佬了。

在开发前,首先得明确用什么来实现。用input输入框和textare文本输入肯定是不行的,这两个只能输入文本类数据(输入法表情也算),想要在输入框内展示图片、表情包或回复消息等复杂内容时就不行了。灵光一闪,展示图片这些用富文本不就好了,但仔细想想,使用富文本不就引入额外的组件了嘛。想要自己实现一个类似“富文本”输入框,就需要借助contenteditable来实现。

本项目需要解决的问题:

实现一个可输入文本、图片等复杂消息的输入框

实现数据的“双向绑定”

contenteditable

contenteditable是所有HTML元素都有的枚举属性,表示元素是否可以被用户编辑。可用于所有元素,但是不是所有元素对该属性都起作用。如果元素支持该属性,并且设置了contenteditable,则浏览器会修改元素以允许编辑。

关于contenteditable需要注意:

  • true或者空字符串,表示元素可编辑
  • false,表示元素不可编辑
  • 如果没有设置该属性的值,则其值被视为空字符串
  • 如果没有设置该属性或者设置了无效值,则其值默认继承自父元素。如果父元素是可编辑的,那么该子元素也是可编辑的;否则,该子元素不可编辑。
  • 虽然该属性可以设置true、false,但是contenteditable是一个枚举属性而不是布尔属性。

本项目采用对div增加contenteditable属性实现输入框。

基础使用

首先新建一个Vue项目(如果只是实现demo,也可以不创建Vue项目),vue create simple-chat-inputbox,采用默认的即可(新版vue-cli默认新建的是Vue3项目,本项目采用Vue2)。

然后进入项目,npm run serve运行起来,不运行怎么能看到效果呢。

在实际开发前,先做好准备工作:

  • 初始化本地仓库,并关联远端仓库(可选)
  • 取消App.vue中的默认样式,隐藏HelloWorld

新建InputBox.vue,作为输入框组件

...
<div class="input-box" contenteditable="true"></div>
...
<style scoped>
.input-box {
  width: 400px;
  height: 250px;
  border: 1px solid #6e6e6e;
  outline: none; /* 隐藏聚焦时外边框 */
  padding: 10px;
}
</style>

注册并引入InputBox.vue,运行后如下图:

此时就可以在输入框中就可以输入你想输入的内容,但是仅仅是输入,怎么获取值,以及怎么实现双向绑定呢。

进阶使用

自定义事件 — Vue.js (vuejs.org)有一句话:

一个组件上的 v-model 默认会利用名为 value 的 prop 和名为 input 的事件,仍然需要在组件的 props 选项里声明 value 这个 prop

根据此特性,我们再来改造一下项目:

虽然div变成了可编辑,但是并不能input一样直接使用v-model来完成双向绑定,但我们可以另辟蹊径,模拟实现双向绑定。首先我们需要创建两个组件:InputBox.vueDivEditable.vue,分别表示父组件和子组件,对外只提供父组件。

对于父组件来说,只需要使用v-model传入值就行。

// InputBox.vue
<template>
  <div>
    <DivEditable v-model="inputContent" />
    <input type="text" v-model="inputContent">
    <div @click="changeValue">父组件修改子组件的值</div>
  </div>
</template>
<script>
import DivEditable from '@/components/DivEditable'
export default {
  name: 'inputBox',
  data() {
    return {
      inputContent: '',
    }
  },
  watch: {
    inputContent(val) {
      console.log('父组件接收到的输入框的值', val);
    }
  },
  components: {
    DivEditable
  },
  methods: {
    changeValue() {
      this.inputContent = this.model1;
    }
  }
}
</script>

子组件处理就相对复杂点,需要接收值并且监听事件:

<template>
  <div ref="editor" class="input-box" contenteditable="true" @input="inputText" @blur="inputBlur" @focus="inputFocus"></div>
</template>
<script>
export default {
  name: 'inputBox',
  props: ['value'], // 父组件v-model绑定的prop
  data() {
    return {
      isBlur: true, // 解决赋值时光标自动定位到起始位置
    }
  },
  watch: {
    value(val) {
      if (this.isBlur) {
        this.$refs.editor.innerHTML = val;
      }
    }
  },
  methods: {
    // 监听输入框内容
    inputText() {
      console.log('子组件输入框的输入内容', this.$refs.editor.innerHTML);
      this.$emit('input', this.$refs.editor.innerHTML);
    },
    inputFocus() {
      this.isBlur = false;
    },
    inputBlur() {
      this.isBlur = true;
    }
  }
}
</script>
<style scoped>
.input-box {
  width: 400px;
  height: 250px;
  border: 1px solid #6e6e6e;
  outline: none; /* 隐藏聚焦时外边框 */
  padding: 10px;
}
</style>

虽然div不可以使用v-model,但是可以监听inputfocusblur等事件。上述代码其实并不复杂,主要就是利用了v-model的特性。有一点需要说明,由于是“双向绑定”,子组件里面输入的值会通过父组件赋值到子组件,导致子组件的光标始终处于起始位置,因此需要增加一个isBlur变量,用来解决这个问题。感兴趣的可以试一下去掉isBlur会是什么效果。

运行结果如下图:

通过修改父组件输入框的值,子组件对应的值也会发生改变;同理,修改子组件也是同样的效果。基本实现了“双向绑定”。

总结

本文基于contenteditable,实现可“双向绑定”的输入框

实现双向绑定,可以动态赋值,或者根据用户的输入实时处理,例如输入@的时候弹出渲染的弹窗,在选择用户后再插入到输入框

项目完整代码可参考 项目地址,接下来将陆续介绍怎么实现粘贴文本、图片,以及对光标的处理。

到此这篇关于Vue实现contenteditable元素双向绑定的方法详解的文章就介绍到这了,更多相关Vue元素双向绑定内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • vue.js使用v-model实现表单元素(input) 双向数据绑定功能示例

    本文实例讲述了vue.js使用v-model实现表单元素(input) 双向数据绑定功能.分享给大家供大家参考,具体如下: v-model 一般表单元素(input) 双向数据绑定 el:'#box',//这里放的是选择器. 不然会不生效 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>www.jb51.net vu

  • Vue双向绑定详解

    目录 1.双向绑定 2.那么其它标签选中会不会也有这个结果,答案当然是有: 3.我们再来看一个: 4.注意 总结 1.双向绑定 双向绑定就是 你们前端数据改变 你们data中的数据也会改变,同样的,你们data中的数据改变了 前端页面中的数据也同样会发生改变,而且,这个过程是不需要刷新的. <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> &l

  • VUE实现表单元素双向绑定(总结)

    本文介绍了VUE实现表单元素双向绑定(总结) ,分享给大家,具体如下: checkbox最基本用法: <input type="checkbox" v-model="inputdata" checked/> <input type="checkbox" v-model="inputdata"/> <input type="checkbox" v-model="inpu

  • electron+vue实现div contenteditable截图功能

    最近在学习基于electron + electron-vue开发聊天客户端项目时,需要用到编辑器插入表情功能.一般通过input或textarea也能实现,通过插入[笑脸].(:12 这些标签,展示的时候解析标签就行. 如下图效果: 在网上找到的jq插件实现在textarea光标处插入表情符标签 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></t

  • Vue中div contenteditable 的光标定位方法

    在Vue做项目时,做了一个div[contenteditable=true]的组件作为文本输入框 在非手动输入值后,光标会丢失,经测试以下这段代码可用,直接将光标定位到最后 function keepLastIndex(obj) { console.log(obj) console.log(window.getSelection) console.log(document.selection) if (window.getSelection) { //ie11 10 9 ff safari ob

  • Vue实现contenteditable元素双向绑定的方法详解

    目录 前言 contenteditable 基础使用 进阶使用 总结 前言 如何实现一个即时通讯的聊天页面,网上有很多的开源或不开源的成品,可以直接使用,或者简单修改后使用.但在实际项目中,直接使用开源的即时通讯往往不是我们想要的,如何自己开发一个聊天页面呢.本文就着学习的目的,从0开始一步步实现一个聊天框的开发,至于消息的发送和接收,这个就得依靠后端大佬了. 在开发前,首先得明确用什么来实现.用input输入框和textare文本输入肯定是不行的,这两个只能输入文本类数据(输入法表情也算),想

  • React利用插件和不用插件实现双向绑定的方法详解

    前言 以前对于双向绑定概念来自于Angular.js,现在我用我感兴趣的react.js来实现这样的方式. 有2种方式分析,1:不用插件,2:用插件 (引入react.js操作省略...) 不用插件: 先创建react组件 var NoLink = React.createClass({}); React.render(<NoLink />,document.body); 组件创建好了,需要一个初始化变量,来公用显示输入的数据 var NoLink = React.createClass({

  • vue双向绑定及观察者模式详解

    在Vue中,使用了Object.defineProterty()这个函数来实现双向绑定,这也就是为什么Vue不兼容IE8 1 响应式原理 让我们先从相应式原理开始.我们可以通过Object.defineProterty()来自定义Object的getter和setter 从而达到我们的目的. 代码如下 function observe(value, cb) { Object.keys(value).forEach((key) => defineReactive(value, key, value

  • 对Python闭包与延迟绑定的方法详解

    Python闭包可能会在面试或者是工作中经常碰到,而提到Python的延迟绑定,肯定就离不开闭包的理解,今天总结下 关于闭包的概念以及一个延迟绑定的面试题. Python闭包 1.什么是闭包,闭包必须满足以下3个条件: 必须是一个嵌套的函数. 闭包必须返回嵌套函数. 嵌套函数必须引用一个外部的非全局的局部自由变量. 举个栗子 # 嵌套函数但不是闭包 def nested(): def nst(): print('i am nested func %s' % nested.__name__) ns

  • js基础之DOM中元素对象的属性方法详解

    在 HTML DOM (文档对象模型)中,每个部分都是节点. 节点是DOM结构中最基本的组成单元,每一个HTML标签都是DOM结构的节点. 文档是一个    文档节点 . 所有的HTML元素都是    元素节点 所有 HTML 属性都是    属性节点 文本插入到 HTML 元素是    文本节点 注释是    注释节点. 最基本的节点类型是Node类型,其他所有类型都继承自Node,DOM操作往往是js中开销最大的部分,因而NodeList导致的问题最多.要注意:NodeList是'动态的',

  • 在vue项目中引入highcharts图表的方法(详解)

    npm进行highchars的导入,导入完成后就可以进行highchars的可视化组件开发了 npm install highcharts --save 1.components目录下新建一个chart.vue组件 <template> <div class="x-bar"> <div :id="id" :option="option"></div> </div> </templa

  • vue.js 双层嵌套for遍历的方法详解, 类似php foreach()

    主要运用 template 标签,可相当于 php foreach() foreach(lists as $key){ //todo foreach($key.自定义字段 as k){ //todo } } <template v-for="key in lists" v-cloak> <tr> <td></td> <td ></td> <td ></td> <td ></

  • 对Vue.js之事件的绑定(v-on: 或者 @ )详解

    1.Vue.js事件绑定的一般格式 v-on:click='function' v-on:click/mouseout/mouseover/ @click 2.Vue.js事件绑定的实现 2.1 JavaScript代码 <script type="text/javascript" src="../js/vue-1.0.21.js"></script> <script type="text/javascript"&g

  • vue项目打包部署_nginx代理访问方法详解

    我又来了,今天部署了下vue项目,使用nginx做了代理,这样可以解决跨域的问题,这里做一个简单讲解. 1.先看vue项目打包(我这里使用的是vscode开发工具) 这里是我的项目结构: 打包之前需要修改如下配置文件: 配置文件一:build>>utils.js (修改publicPath:"../../" , 这样写是处理打包后找不到静态文件的问题) 配置文件二:config>>index.js(修改assetsPublicPath:'./' ,修改目的是为了

  • Python列表元素删除和remove()方法详解

    删除列表中元素的方法有三种: 1. del命令 使用del命令能够删除列表中指定位置上的元素,也可以删除整个列表. 2. pop( )方法 使用列表的pop()方法能够删除并返回列表指定位置(默认为最后一个位置)的元素. 3. remove方法 使用列表的remove()方法能够删除列表中首次出现的指定元素,如果列表中不存在该元素则抛出异常.有的时候可能需要删除列表中某一大量重复的数据,我们很容易就会想到列表的remove()方法,例如: x=[1,2,1,2,1,2,1,2] y=[1,1,2

随机推荐