我尝试使用Vue 2进行可编辑的组件。它应该在任何标记中使用contenteditable
属性,替换正常输入。我想给它一个占位符功能,以便在用户没有提供时显示值,但我似乎无法使其正常工作。
我正在观看组件的当前值,并在没有用户内容时将data.isEmpty
设置为true
。然后该组件应显示占位符值,但目前它没有显示任何内容。
如果我console.log
render
方法的结果,它将显示占位符子节点已正确实例化,但由于某种原因它只是在最终HTML上显示。< / p>
这是一个JSFiddle:https://jsfiddle.net/dy27fa8t/
为喜欢它的用户提供了一个嵌入代码段:
Vue.component('editable-content', {
props: {
initial: {
type: String
},
placeholder: {
type: String,
required: false
}
},
data() {
return {
value: this.initial,
isEmpty: this.initial === ''
}
},
render: function(createElement) {
const self = this
return createElement(
'div', {
attrs: {
contenteditable: true
},
on: {
input: function(event) {
self.value = event.target.innerHTML
self.$emit('edited', event.target.value)
}
}
},
this.isEmpty ? this.placeholder : this.value
)
},
watch: {
value(to, from) {
this.isEmpty = to === ''
}
}
})
new Vue({
el: '#app',
components: [
'editable-content'
]
})
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.0/vue.min.js"></script>
<div id="app">
<editable-content initial="Initial value" placeholder="Placeholder" />
</div>
&#13;
答案 0 :(得分:2)
显然渲染contenteditable
不会以直观的方式工作。而是在内容为空时直接使用占位符设置innerHTML
。然后在keydown
(在输入事件之前),如果内容当前标记为空,则删除占位符。在keyup
上(在输入事件之后),如果div仍然没有内容,请将其标记为空(这就是Shift键不会清除占位符)。
我冒昧地使v-model
兼容并为占位符设置样式。
Vue.component('editable-content', {
props: {
value: {
type: String
},
placeholder: {
type: String,
required: false
}
},
data() {
return {
isEmpty: this.value === ''
};
},
methods: {
setEmpty() {
this.$el.innerHTML = `<div contenteditable="false" class="placeholder">${this.placeholder}</div>`;
this.isEmpty = true;
},
clearEmpty() {
this.$el.innerHTML = '';
this.isEmpty = false;
}
},
mounted() {
if (this.$el.innerHTML === '') {
this.setEmpty();
}
},
watch: {
value(newValue) {
if (newValue === '') {
this.setEmpty();
}
}
},
render: function(createElement) {
return createElement(
'div', {
attrs: {
contenteditable: true
},
on: {
keydown: () => {
if (this.isEmpty) {
this.clearEmpty();
}
},
input: (event) => {
this.$emit('input', event.target.textContent);
},
keyup: () => {
if (this.$el.innerHTML === '') {
this.setEmpty();
}
}
}
},
this.value
)
}
});
new Vue({
el: '#app',
data: {
startingBlank: '',
editedValue: 'initial value'
},
components: [
'editable-content'
]
})
.placeholder {
color: rgba(0,0,0, 0.5);
}
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.3.0/vue.min.js"></script>
<div id="app">
<editable-content v-model="startingBlank" placeholder="Placeholder"></editable-content>
<editable-content v-model="editedValue" placeholder="Placeholder"></editable-content>
</div>
答案 1 :(得分:2)
最后,我使用:empty
伪类来解决混合JS和CSS解决方案。仅仅Vue的解决方法看起来太笨重了,所以这感觉就像一个健康的妥协。我甚至觉得不再需要跟踪value
了。
值得注意的是,对于单文件组件,我可以使用范围CSS,因此它更好,因为CSS对组件核心功能至关重要。
Vue.component('editable-content', {
props: {
initial: {
type: String
},
placeholder: {
type: String,
required: false
}
},
data() {
return {
value: this.initial
}
},
render: function(createElement) {
const self = this
return createElement(
'div', {
attrs: {
contenteditable: true,
'data-placeholder': this.placeholder
},
on: {
input: function(event) {
self.$emit('edited', event.target.value)
}
}
},
this.value
)
}
})
new Vue({
el: '#app',
components: [
'editable-content'
]
})
[data-placeholder]:empty::after {
content: attr(data-placeholder);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.0/vue.min.js"></script>
<div id="app">
<editable-content initial="Initial value" placeholder="Placeholder" />
</div>
答案 2 :(得分:1)
如果你没有将initial
道具传递给组件,它将是未定义的。因此,您应该检查是否未定义:
data() {
return {
value: this.initial,
isEmpty: typeof this.initial === 'undefined'
}
},