<template>
<div>
<button @click="toggleElement">切换显示</button>
<div v-if="showElement" class="bg-blue-100 p-4">
这是一个通过v-if控制的动态元素
</div>
<div v-show="showElement" class="bg-green-100 p-4 mt-2">
这是一个通过v-show控制的动态元素
</div>
</div>
</template>
<script>
export default {
data() {
return {
showElement: false
}
},
methods: {
toggleElement() {
this.showElement = !this.showElement;
}
}
}
</script>
v-if
:完全销毁和重建元素,适合不常切换的场景v-show
:通过CSS控制显示隐藏,适合频繁切换的场景<template>
<div>
<button @click="addItem">添加项目</button>
<ul>
<li v-for="(item, index) in items" :key="item.id">
{{ item.text }}
<button @click="removeItem(index)">删除</button>
</li>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
items: [
{ id: 1, text: '项目1' },
{ id: 2, text: '项目2' }
]
}
},
methods: {
addItem() {
const newId = this.items.length > 0 ? Math.max(...this.items.map(item => item.id)) + 1 : 1;
this.items.push({ id: newId, text: `项目${newId}` });
},
removeItem(index) {
this.items.splice(index, 1);
}
}
}
</script>
<template>
<div>
<button @click="setComponent('ComponentA')">显示组件A</button>
<button @click="setComponent('ComponentB')">显示组件B</button>
<component :is="currentComponent"></component>
</div>
</template>
<script>
import ComponentA from './components/ComponentA.vue';
import ComponentB from './components/ComponentB.vue';
export default {
data() {
return {
currentComponent: ComponentA
}
},
methods: {
setComponent(component) {
this.currentComponent = component === 'ComponentA' ? ComponentA : ComponentB;
}
}
}
</script>
const AsyncComponent = () => import('./components/AsyncComponent.vue');
export default {
data() {
return {
currentComponent: null
}
},
methods: {
loadAsyncComponent() {
this.currentComponent = AsyncComponent;
}
}
}
<template>
<div>
<button @click="createElement">创建元素</button>
<div ref="container" class="mt-4 p-4 border border-gray-300"></div>
</div>
</template>
<script>
export default {
methods: {
createElement() {
const div = document.createElement('div');
div.textContent = '这是手动创建的元素';
div.className = 'bg-yellow-100 p-2 mb-2';
// 添加点击事件
div.addEventListener('click', () => {
alert('元素被点击了');
});
// 添加到容器
this.$refs.container.appendChild(div);
}
}
}
</script>
import Vue from 'vue';
import NotificationComponent from './NotificationComponent.vue';
export const showNotification = (options) => {
// 创建组件构造器
const NotificationConstructor = Vue.extend(NotificationComponent);
// 创建实例并传递props
const instance = new NotificationConstructor({
propsData: {
message: options.message || '默认消息',
type: options.type || 'info'
}
});
// 挂载实例
instance.$mount();
// 添加到DOM
document.body.appendChild(instance.$el);
// 设置自动关闭
if (options.duration !== 0) {
setTimeout(() => {
instance.close();
}, options.duration || 3000);
}
return instance;
};
<template>
<div>
<button @click="showSuccess">显示成功通知</button>
<button @click="showError">显示错误通知</button>
</div>
</template>
<script>
import { showNotification } from '@/utils/Notification';
export default {
methods: {
showSuccess() {
showNotification({
message: '操作成功!',
type: 'success',
duration: 2000
});
},
showError() {
showNotification({
message: '发生错误!',
type: 'error',
duration: 4000
});
}
}
}
</script>
<template>
<div class="dynamic-form">
<slot name="header"></slot>
<div class="form-fields">
<div v-for="(field, index) in fields" :key="field.id" class="form-field">
<input
v-model="field.value"
:type="field.type"
:placeholder="field.placeholder"
>
<button v-if="canRemove(index)" @click="removeField(index)">删除</button>
</div>
</div>
<button @click="addField">添加字段</button>
<button @click="submitForm">提交</button>
<slot name="footer"></slot>
</div>
</template>
<script>
export default {
props: {
initialFields: {
type: Array,
default: () => []
},
fieldType: {
type: String,
default: 'text'
}
},
data() {
return {
fields: this.initialFields.map((field, index) => ({
id: field.id || `field-${index}`,
type: field.type || this.fieldType,
value: field.value || '',
placeholder: field.placeholder || `字段 ${index + 1}`
}))
}
},
methods: {
addField() {
const newId = `field-${this.fields.length}`;
this.fields.push({
id: newId,
type: this.fieldType,
value: '',
placeholder: `字段 ${this.fields.length + 1}`
});
},
removeField(index) {
this.fields.splice(index, 1);
},
canRemove(index) {
return this.fields.length > 1;
},
submitForm() {
this.$emit('submit', this.fields.map(field => ({
id: field.id,
value: field.value
})));
}
}
}
</script>
<template>
<div>
<h3>使用动态表单组件</h3>
<DynamicForm
:initial-fields="[{ value: '预设值' }]"
@submit="handleSubmit"
>
<template #header>
<h4>请填写以下信息</h4>
</template>
<template #footer>
<p class="text-sm text-gray-500">点击添加字段可增加更多输入框</p>
</template>
</DynamicForm>
</div>
</template>
<script>
import DynamicForm from './components/DynamicForm.vue';
export default {
components: {
DynamicForm
},
methods: {
handleSubmit(formData) {
console.log('表单提交数据:', formData);
// 处理表单数据
}
}
}
</script>
<template>
<div v-if="visible" class="popup-overlay" @click.self="close">
<div class="popup-content" :class="`popup-${type}`">
<div class="popup-header">
<h3>{{ title }}</h3>
<button @click="close" class="close-btn">×</button>
</div>
<div class="popup-body">
<slot>{{ content }}</slot>
</div>
<div class="popup-footer">
<button v-if="showCancel" @click="close" class="cancel-btn">取消</button>
<button @click="confirm" class="confirm-btn">{{ confirmText }}</button>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
title: {
type: String,
default: '提示'
},
content: {
type: String,
default: ''
},
type: {
type: String,
default: 'info',
validator: value => ['info', 'success', 'warning', 'error'].includes(value)
},
showCancel: {
type: Boolean,
default: true
},
confirmText: {
type: String,
default: '确定'
}
},
data() {
return {
visible: false
}
},
methods: {
open() {
this.visible = true;
this.$emit('open');
},
close() {
this.visible = false;
this.$emit('close');
},
confirm() {
this.visible = false;
this.$emit('confirm');
}
},
emits: ['open', 'close', 'confirm']
}
</script>
import Popup from '../components/Popup.vue';
export const PopupPlugin = {
install(app) {
// 注册组件
app.component('Popup', Popup);
// 添加全局方法
app.config.globalProperties.$popup = {
show(options) {
return new Promise((resolve, reject) => {
// 创建容器
const container = document.createElement('div');
document.body.appendChild(container);
// 创建应用实例
const popupApp = app.createApp({
data() {
return {
popupOptions: options
}
},
methods: {
onConfirm() {
resolve();
this.$destroy();
document.body.removeChild(container);
},
onClose() {
reject();
this.$destroy();
document.body.removeChild(container);
}
},
template: `
<Popup
v-bind="popupOptions"
@confirm="onConfirm"
@close="onClose"
/>
`
});
// 挂载应用
popupApp.mount(container);
// 打开弹窗
const popupInstance = popupApp.\_instance.proxy;
popupInstance.open();
});
},
// 快捷方法
confirm(message, options = {}) {
return this.show({
title: '确认操作',
content: message,
type: 'warning',
...options
});
},
success(message, options = {}) {
return this.show({
title: '操作成功',
content: message,
type: 'success',
showCancel: false,
...options
});
},
error(message, options = {}) {
return this.show({
title: '操作失败',
content: message,
type: 'error',
showCancel: false,
...options
});
}
};
}
};
<template>
<div>
<button @click="showConfirm">显示确认弹窗</button>
<button @click="showSuccess">显示成功提示</button>
</div>
</template>
<script>
export default {
methods: {
async showConfirm() {
try {
await this.$popup.confirm('确定要删除这个项目吗?此操作不可撤销。');
console.log('用户确认删除');
// 执行删除操作
} catch {
console.log('用户取消删除');
}
},
showSuccess() {
this.$popup.success('操作已成功完成!', { duration: 2000 });
}
}
}
</script>
<template>
<div class="dynamic-loader">
<div v-if="loading" class="loader">加载中...</div>
<div v-else-if="error" class="error">加载失败: {{ error }}</div>
<component v-else :is="component"></component>
</div>
</template>
<script>
export default {
props: {
componentLoader: {
type: Function,
required: true
}
},
data() {
return {
component: null,
loading: true,
error: null
}
},
async mounted() {
try {
const loadedComponent = await this.componentLoader();
this.component = loadedComponent.default || loadedComponent;
} catch (err) {
this.error = err.message;
console.error('加载组件失败:', err);
} finally {
this.loading = false;
}
}
}
</script>
2. **使用示例**<template>
<div>
<button @click="loadComponent">加载组件</button>
<DynamicLoader
v-if="shouldLoad"
:component-loader="componentLoader"
/>
</div>
</template>
<script>
import DynamicLoader from './components/DynamicLoader.vue';
export default {
components: {
DynamicLoader
},
data() {
return {
shouldLoad: false
}
},
methods: {
loadComponent() {
this.shouldLoad = true;
},
componentLoader() {
return import('./components/HeavyComponent.vue');
}
}
}
</script>
async addMultipleItems() {
// 先更新数据
for (let i = 0; i < 10; i++) {
this.items.push({ id: i, text: `项目${i}` });
}
// 等待DOM更新完成
await this.$nextTick();
// 执行DOM操作
console.log('DOM更新完成');
}
<div v-show="isVisible" class="frequently-toggled-element">
这个元素会频繁显示/隐藏
</div>
3. **懒加载大型组件**// 使用异步组件实现懒加载
const HeavyComponent = () => import('./components/HeavyComponent.vue');
export default {
components: {
HeavyComponent
}
}
this.$refs.container.innerHTML = '<div>新内容</div>';
// 推荐:使用Vue的响应式系统
this.content = '<div>新内容</div>';
destroyComponent() {
this.$refs.dynamicComponent.$destroy();
this.$refs.container.removeChild(this.$refs.dynamicComponent.$el);
}
mounted() {
window.addEventListener('resize', this.handleResize);
},
beforeDestroy() {
window.removeEventListener('resize', this.handleResize);
}
通过上述方法,您可以在Vue项目中灵活地实现动态添加HTML元素的功能:
在实际开发中,建议优先使用Vue提供的声明式方法(如v-if、v-for、动态组件),只有在必要时才使用手动操作DOM的方式。同时,合理封装组件可以提高代码的可维护性和复用性。
Vue, 动态添加 HTML 元素,组件封装,前端开发,JavaScript,Web 开发,Vue 组件化,动态组件,HTML 元素操作,Vue 指令,组件通信,Vue 生命周期,前端框架,动态渲染,组件复用
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。