javascript - 如何有条件地在作用域 Vue 组件中附加元素?
问题描述
我正在尝试为双击时可以编辑的标题创建一个组件。组件将应使用的 h-tag 和 title 作为 props,并应生成一个正常的 h-tag,双击后将变为输入字段。如果页面上只有一个标题,这已经有效,但是一旦在一页上使用了多个组件,它就会中断,因为组件的范围不正确。但我不知道怎么做。这是代码:
<template>
<div class="edit-on-click">
<input
:class="sizeClass"
type="text"
v-if="edit"
v-model="editedTitle"
@blur="finishEdit"
@keyup.enter="finishEdit"
v-focus="true"
/>
<span v-show="!edit" @dblclick.prevent="edit = true"></span>
</div>
</template>
安装的钩子我不知道如何确定范围:
mounted() {
let node = document.createElement(this.size); // Takes h-tag (h1, h2 etc.)
let titleText = document.createTextNode(this.finalTitle); // Takes title
node.appendChild(titleText);
node.classList.add("editable-title");
// This breaks the code once there are multiple components in the document
document.getElementsByTagName("span")[0].appendChild(node);
},
如何以有效的方式确定范围?非常感谢您!
解决方案
好吧,使用 Vue,您可能希望尽可能避免以“本机”方式创建 DOM 元素,因为您可能会遇到竞争条件,其中 Vue 不知道这些元素的存在,您可能希望在某些时候做出反应时间(在你的情况下,<span>
双击)。
相反,您可以做的可能是使用 this<component>
和v-bind:is
prop 动态地“在”这些不同的标题之间“切换”。考虑以下示例:
Vue.component('EditableHeading', {
template: '#editable-heading',
props: {
size: {
type: String,
default: 'h1'
},
value: {
type: String,
required: true
}
},
data() {
return {
editing: false
}
},
methods: {
confirm(e) {
this.$emit('input', e.target.value);
this.close();
},
start() {
this.editing = true;
this.$nextTick(() => {
this.$el.querySelector('input[type="text"]').select();
});
},
close() {
this.editing = false;
}
}
})
new Vue({
el: '#app',
data: () => ({
titleList: [],
text: 'New Title',
size: 'h3'
}),
methods: {
addNewTitle() {
this.titleList.push({
text: this.text,
size: this.size
});
}
}
})
.edit-on-click {
user-select: none;
}
.heading-size {
margin-top: 1rem;
width: 24px;
}
p.info {
background-color: beige;
border: 1px solid orange;
color: brown;
padding: 4px 5px;
margin-top: 2rem;
}
<script src="https://vuejs.org/js/vue.min.js"></script>
<div id="app">
<editable-heading
v-for="(title, index) of titleList" :key="index"
v-model="title.text"
:size="title.size">
</editable-heading>
<div>
<label>
Heading size:
<input v-model="size" class="heading-size" />
</label>
</div>
<div>
<label>
Title:
<input v-model="text" />
</label>
</div>
<div>
<button @click="addNewTitle()">Add new title</button>
</div>
<p class="info">
[double-click]: Edit <br />
[enter]: Confirm <br />
[esc/mouseleave]: Cancel
</p>
</div>
<script id="editable-heading" type="text/x-template">
<div class="edit-on-click">
<input
type="text"
v-if="editing"
:value="value"
@blur="close"
@keydown.enter="confirm"
@keydown.esc="close" />
<component :is="size" v-else @dblclick="start">{{value}}</component>
</div>
</script>
推荐阅读
- python - 如何让 Spyder 在打开现有项目时自动更改 python 解释器/环境?
- erlang - 在 Erlang 中应该如何解释 undef 错误?
- excel - 使用 VBA 获取主文件夹路径的最可靠方法是什么
- azure - 使用代码更改 edgeAgent 和 edgeHub 的“createOptions”
- javascript - 如何格式化 moment.js?
- vb.net - Page_Load 持续运行不止一次 VB.net
- vim - 如何解决 Atom 和 Vim 之间的制表符/空格问题
- node.js - 如何测量包括主机操作系统在内的 docker 内存使用情况?
- mule - 在 mule 3 中读取 json 有效负载数据
- angular - Angular 10 错误“找不到模块'@angular/core'或其相应的类型声明”