vue文本编辑器 div[contenteditable]

vue文本编辑器

特性:
支持placeholder
支持与fastclick插件共存,如果不需要,可以去掉needsclick这个class
支持v-model
支持readonly
支持任意数量个实例
支持移动端换行
支持最大字符限制
ios和mac下没有点击bug
直接上代码:

div-editor.vue

<template>
  <p
    :id="`divEditor_${id}`"
    :ref="`divEditor_${id}`"
    :placeholder="placeholder"
    class="div-editor needsclick"
    :class="{ readonly: readonly }"
    @blur="focus"
    @focus="focus"
    @input="update"
    @click="editContent"
    v-html="valueText"
    :contenteditable="!readonly"
  ></p>
</template>
<script>
import uuid from "@/util/uuid";

export default {
  model: {
    prop: "value",
    event: "change",
  },
  props: {
    value: {
      type: String,
      default: "",
    },
    placeholder: {
      type: String,
      default: "请输入",
    },
    readonly: {
      type: Boolean,
      default: false,
    },
    maxLength: {
      type: Number,
      default: null,
    },
  },
  data() {
    return {
      id: uuid(8, 2),
      focusIn: false,
      valueText: "",
    };
  },
  created() {
    this.valueText = this.value;
  },

  watch: {
    value(newVal) {
      if (!this.focusIn) {
        this.valueText = newVal;
      }
    },
  },
  methods: {
    editContent() {
      if (this.readonly) {
        return;
      }

      let el = this.$refs[`divEditor_${this.id}`];
      if (this.valueText.length) {
        let sel = window.getSelection();
        sel.collapse(el, 1);
      }
      el.focus();
      this.focusIn = true;
    },
    update(e) {
      if (this.maxLength && e.target.innerHTML.length > this.maxLength) {
        let text = e.target.innerHTML.slice(0, this.maxLength);
        text = text.replace(/(<br>)|(&amp;|&lt;)|([&<?])$/gi, "");
        e.target.innerHTML = text;
        this.$emit("change", text);
        this.setFocus(e);
      } else {
        if (!this.readonly) {
          this.$emit("change", e.target.innerHTML);
        }
      }
    },
    focus(e) {
      this.focusIn = true;
    },
    blur() {
      this.focusIn = false;
    },
    setFocus() {
      let obj = this.$refs[`divEditor_${this.id}`];

      if (window.getSelection) {
        //ie11 10 9 ff safari
        var range = window.getSelection(); //创建range
        range.selectAllChildren(obj); //range 选择obj下所有子内容
        range.collapseToEnd(); //光标移至最后
      } else if (document.selection) {
        //ie10 9 8 7 6 5
        var range = document.selection.createRange(); //创建选择对象
        range.moveToElementText(obj); //range定位到obj
        range.collapse(false); //光标移至最后
        range.select();
      }
    },
  },
};
</script>

<style lang="scss" scoped>
.div-editor {
  width: 100%;
  outline: 0 none;
  min-height: 45px;
  max-height: 300px;
  white-space: pre;
  word-break: break-all;
  background-color: transparent;
  border: 0 none;
  font-size: 32px;
  font-family: PingFangSC-Regular, PingFang SC;
  font-weight: 400;
  color: #333333;
  line-height: 45px;
  text-align: left;
  overflow-y: auto;

  &[contenteditable="true"] {
    margin: 0;
    padding: 0;
    -webkit-user-select: text;
    user-select: text;
    -webkit-user-modify: read-write-plaintext-only;
    * {
      -webkit-user-select: text !important;
      user-select: text !important;
    }
  }
  &:empty::after {
    content: attr(placeholder);
    font-size: 30px;
    font-family: PingFangSC-Regular, PingFang SC;
    line-height: 45px;
    color: rgba(0, 0, 0, 0.5);
    text-align: left;
    pointer-events: none;
  }
  &.readonly {
    &:empty::after {
      display: none;
    }
  }
}
</style>

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值