我有一个textarea
组件,其中包括html tag
,并且我想在此组件中以编辑方式获取html
。我使用Laravel
生成html。
<template>
<div>
<textarea
:value="content"
:name="name"
:id="id">
<slot></slot>
</textarea>
</div>
</template>
在刀片页面中,我曾经使用过此组件:
<my-component>
<p class="textbox">hello world</p>
</my-component>
当我将此组件放入页面时,在文本区域中显示标签<slot></slot>
。我该怎么办?您有我需要的解决方案吗?
谢谢
答案 0 :(得分:9)
<textarea>
组件被Vue渲染器视为静态组件,因此将它们放入DOM后,它们根本不会改变(因此,如果您检查DOM,就会看到{{1 }}放在<slot></slot>
中。
但是,即使它们确实发生了变化,也无济于事。只是因为<textarea>
中的HTML元素没有成为其价值。您必须设置TextArea element的<textarea>
属性才能使其正常工作。
无论如何,不要绝望。这是可行的,克服上述问题所需要做的就是发挥一个小的辅助组件的作用。
有很多方法可以实现这一目标,如下所示。它们在本质上有不同,您希望原始组件的模板是这样。
value
更改为<textarea>
组件您组件的模板现在将变为:
<textarea-slot>
如您所见,除了将<template>
<div>
<textarea-slot
v-model="myContent"
:name="name"
:id="id">
<slot></slot>
</textarea-slot>
</div>
</template>
替换为<textarea>
外,什么都没有改变。这足以克服Vue对<textarea-slot>
进行的静态处理。 <textarea>
的完整实现在下面的演示中。
<textarea-slot>
,但通过<textarea>
组件获取<slot>
的HTML 解决方案是创建一个帮助程序组件(以下称为<vnode-to-html>
),该组件会将您广告位的VNodes转换为HTML字符串。然后,您可以将此类HTML字符串设置为vnode-to-html
中的value
。您组件的模板现在将变为:
<textarea>
<template>
<div>
<vnode-to-html :vnode="$slots.default" @html="valForMyTextArea = $event" />
<textarea
:value="valForMyTextArea"
:name="name"
:id="id">
</textarea>
</div>
</template>
的用法保持不变:
my-component
<my-component>
<p class="textbox">hello world</p>
</my-component>
Vue.component('my-component', {
props: ["content", "name", "id"],
template: `
<div>
<textarea-slot
v-model="myContent"
:name="name"
:id="id">
<slot></slot>
</textarea-slot>
<vnode-to-html :vnode="$slots.default" @html="valueForMyTextArea = $event" />
<textarea
:value="valueForMyTextArea"
:name="name"
:id="id">
</textarea>
</div>
`,
data() { return {valueForMyTextArea: '', myContent: null} }
});
Vue.component('textarea-slot', {
props: ["value", "name", "id"],
render: function(createElement) {
return createElement("textarea",
{attrs: {id: this.$props.id, name: this.$props.name}, on: {...this.$listeners, input: (e) => this.$emit('input', e.target.value)}, domProps: {"value": this.$props.value}},
[createElement("template", {ref: "slotHtmlRef"}, this.$slots.default)]
);
},
data() { return {defaultSlotHtml: null} },
mounted() {
this.$emit('input', [...this.$refs.slotHtmlRef.childNodes].map(n => n.outerHTML).join('\n'))
}
});
Vue.component('vnode-to-html', {
props: ['vnode'],
render(createElement) {
return createElement("template", [this.vnode]);
},
mounted() {
this.$emit('html', [...this.$el.childNodes].map(n => n.outerHTML).join('\n'));
}
});
new Vue({
el: '#app'
})
故障:
<script src="https://unpkg.com/vue"></script>
<div id="app">
<my-component>
<p class="textbox">hell
o world1</p>
<p class="textbox">hello world2</p>
</my-component>
</div>
解析为VNode
s,并使它们在<slot>
属性中可用。自然,默认插槽位于this.$slots.SLOTNAME
中。this.$slots.default
传递的内容(作为<slot>
中的VNode)。现在的挑战变成了如何将这些VNode转换为HTML字符串?。这是一个复杂的still open, issue,将来可能会获得不同的解决方案,但是,即使有,{ {3}}。this.$slots.default
和template-slot
)都使用Vue的render函数将VNode渲染到DOM,然后拾取渲染的HTML。vnode-to-html
标签。<script>
作为事件返回,应由父(vnode-to-html
)拾取,该父事件使用传递的值来设置my-component
属性,该属性将设置为{{1 }}中的data
。:value
向父级声明自己为textarea
。这是一种更清洁的解决方案,但需要更多注意,因为您必须指定要传递给textarea-slot
内部创建的<textarea>
的属性。
但是,重要的是要知道,Vue在将声明的<textarea>
解析为textarea-slot
时会剥离一些格式信息,例如顶级组件之间的空格。同样,它会剥离<template>
标签(因为它们不安全)。这些是使用<slot>
(无论是否显示)的解决方案所固有的警告。所以要注意。
Vue的典型富文本编辑器通过使用<script>
(或<slot>
)属性将代码传递到组件中来完全解决此问题。
众所周知的例子包括:
他们在他们的网站上都有非常好的文档(如上链接),所以在这里重复它们对我没有多大用处,但仅作为示例,请看codemirror如何使用v-model
道具来传递代码:
value
这就是他们的做法。当然,如果value
(带有警告)适合您的用例,则也可以使用它们。
答案 1 :(得分:5)
简短的回答是不可能
您的广告位位于 textarea 标签内。 Textare标签只能在其框上显示文本内容。
因此,在需要一种“ HTML编辑模式”的情况下,您可能需要使用WYSIWYG编辑器,我建议您可以将CKEditor用于VueJS,甚至可以直接编辑HTML代码。
https://ckeditor.com/docs/ckeditor5/latest/builds/guides/integration/frameworks/vuejs.html
您的HTML
<div id="app">
<ckeditor :editor="editor" v-model="editorData" :config="editorConfig"></ckeditor>
</div>
您的组件
const app = new Vue( {
el: '#app',
data: {
editor: ClassicEditor,
editorData: '<p>Editable Content HTML</p>',
editorConfig: {
// The configuration of the editor.
}
}
} );
答案 2 :(得分:0)
您需要定义一个插槽。检查official guide上带有插槽的组件和内容分发。还建议您阅读this blog的使用方法
答案 3 :(得分:0)
如果您要编写自己的内容编辑器,可以将 div 与contenteditable =“ true”属性一起使用,而不要使用 textarea 。之后,您可以编写文本装饰方法... 带有laravel的生成的html存储在 myhtml 中,并在vue组件中使用它。
示例:我还上传到了codeandbox [Simple Vue Editor]
<template>
<div>
<button @click="getEditorCotent">Get Content</button>
<button @click="setBold">Bold</button>
<button @click="setItalic">Italic</button>
<button @click="setUnderline">Underline</button>
<button @click="setContent">Clear</button>
<div class="myeditor" ref="myeditor" contenteditable v-html="myhtml" @input="onInput"></div>
</div>
</template>
<script>
export default {
name: "HelloWorld",
props: {
msg: String
},
data: () => {
return {
myhtml:
"<h1>Simple editor</h1><p style='color:red'>in vue</p><p>Hello world</p>" // from laravel server via axios call
};
},
methods: {
onInput(e) {
// handle user input
// e.target.innerHTML
},
getEditorCotent() {
console.log(this.$refs.myeditor.innerHTML);
},
setBold() {
document.execCommand("bold");
},
setItalic() {
document.execCommand("italic");
},
setUnderline() {
document.execCommand("underline");
},
setContent() {
// that way set your html content
this.myhtml = "<b>You cleared the editor content</b>";
}
// PS. Good luck!
}
};
</script>
<style scoped>
.myeditor {
/* text-align: left; */
border: 2px solid gray;
padding: 5px;
margin: 20px;
width: 100%;
min-height: 50px;
}
</style>