javascript - Vue 2 contentEditable with v-model

标签 javascript vue.js contenteditable

我正在尝试制作一个类似于 Medium 的文本编辑器。我正在使用一个内容可编辑的段落标记,并将每个项目存储在一个数组中,并使用 v-for 呈现每个项目。但是,我在使用 v-model 将文本与数组绑定(bind)时遇到了问题。似乎与 v-model 和 contenteditable 属性存在冲突。这是我的代码:

<div id="editbar">
     <button class="toolbar" v-on:click.prevent="stylize('bold')">Bold</button>
</div>
<div v-for="(value, index) in content">
     <p v-bind:id="'content-'+index" v-bind:ref="'content-'+index" v-model="content[index].value" v-on:keyup="emit_content($event)" v-on:keyup.delete="remove_content(index)" contenteditable></p>
</div>

在我的脚本中:

export default { 
   data() {
      return {
         content: [{ value: ''}]
      }
   },
   methods: {
      stylize(style) {
         document.execCommand(style, false, null);
      },
      remove_content(index) {
         if(this.content.length > 1 && this.content[index].value.length == 0) {
            this.content.splice(index, 1);
         }
      }
   }
}

我还没有在网上找到任何答案。

最佳答案

我试了一个例子,eslint-plugin-vue报告 v-modelp 元素上不受支持。查看valid-v-model规则。

截至撰写本文时,Vue 似乎并未直接支持您想要的内容。我将介绍两个通用解决方案:

直接在可编辑元素上使用输入事件

<template>
  <p
    contenteditable
    @input="onInput"
  >
    {{ content }}
  </p>
</template>

<script>
export default {
  data() {
    return { content: 'hello world' };
  },
  methods: {
    onInput(e) {
      console.log(e.target.innerText);
    },
  },
};
</script>

创建可重用的可编辑组件

Editable.vue

<template>
  <p
    ref="editable"
    contenteditable
    v-on="listeners"
  />
</template>

<script>
export default {
  props: {
    value: {
      type: String,
      default: '',
    },
  },
  computed: {
    listeners() {
      return { ...this.$listeners, input: this.onInput };
    },
  },
  mounted() {
    this.$refs.editable.innerText = this.value;
  },
  methods: {
    onInput(e) {
      this.$emit('input', e.target.innerText);
    },
  },
};
</script>

index.vue

<template>
  <Editable v-model="content" />
</template>

<script>
import Editable from '~/components/Editable';

export default {
  components: { Editable },
  data() {
    return { content: 'hello world' };
  },
};
</script>

为您的特定问题定制解决方案

经过多次迭代,我发现对于您的用例,通过使用单独的组件更容易获得可行的解决方案。 contenteditable 元素似乎非常棘手 - 特别是在列表中呈现时。我发现我必须在删除后手动更新每个 pinnerText 才能使其正常工作。我还发现使用 id 有效,但使用 refs 无效。

可能有一种方法可以在模型和内容之间实现完整的双向绑定(bind),但我认为这需要在每次更改后操纵光标位置。

<template>
  <div>
    <p
      v-for="(value, index) in content"
      :id="`content-${index}`"
      :key="index"
      contenteditable
      @input="event => onInput(event, index)"
      @keyup.delete="onRemove(index)"
    />
  </div>
</template>

<script>
export default {
  data() {
    return {
      content: [
        { value: 'paragraph 1' },
        { value: 'paragraph 2' },
        { value: 'paragraph 3' },
      ],
    };
  },
  mounted() {
    this.updateAllContent();
  },
  methods: {
    onInput(event, index) {
      const value = event.target.innerText;
      this.content[index].value = value;
    },
    onRemove(index) {
      if (this.content.length > 1 && this.content[index].value.length === 0) {
        this.$delete(this.content, index);
        this.updateAllContent();
      }
    },
    updateAllContent() {
      this.content.forEach((c, index) => {
        const el = document.getElementById(`content-${index}`);
        el.innerText = c.value;
      });
    },
  },
};
</script>

关于javascript - Vue 2 contentEditable with v-model,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53899676/

相关文章:

javascript - 访问内部属性名称以计算 ES6 中的新属性

vue.js - 将 v-transition 应用于 vue.js(v 1.0.1) router-view

javascript - 仅当数据可用时,才在 vuejs 中条件渲染另一个元素或父元素

ios - UIWebView 中的 contentEditable/designMode 时自动滚动

javascript - 在 Javascript 中查找 json 数据中的数据

javascript - Material Design Lite - 动画在 ng-view div 中不起作用

javascript - $(document).ready(...) 的调用堆栈是如何组装的?

javascript - 从另一个 react 对象获取字符串时如何保持 vue react 性

javascript - 比较范围之间的边界点

jquery - 如何防止 Mac Safari 在 contenteditable 区域右键单击选择文本