d40: vue杂项问题

导航

    1. Vue 中使用 HTML 原生属性的问题
    1. el-dialog 与父组件交互的异步问题
    1. 动态路由机制中关于根路由的小问题
    1. refdep 特性

1. Vue 中使用 HTML 原生属性的问题

在 Vue 项目中,我们可能会不小心使用 HTML 原生事件属性,例如:

html 复制代码
<div onclick="profileVisible = true">点击我</div>

这看起来没什么问题,但实际上,这种方式存在很大的隐患。当 onclick 被触发时,浏览器会在 全局作用域 (即 window 对象)下执行这句 JS 代码。它会寻找一个名为 window.profileVisible 的变量并将其设置为 true,而完全不知道 Vue 组件实例的存在,更不知道你定义在组件 data 中的那个 profileVisible

Vue 指令与原生 HTML 属性的对比

特性 @click (Vue 指令) onclick (原生 HTML 属性)
执行上下文 Vue 组件实例 (this) 全局作用域 (window)
响应式 能触发 Vue 的响应式更新 不能触发 Vue 的响应式更新
数据访问 可以访问 data, props, computed 只能访问全局变量
方法调用 可以调用 methods 中定义的方法 只能调用全局函数
推荐用法 在 Vue 项目中必须使用 在 Vue 项目中应避免使用

结论

在 Vue 项目中,始终 应该使用 Vue 的事件处理指令(如 @click, @input, @submit 等)来处理 DOM 事件,而不是原生的 HTML 事件属性。

2. el-dialog 与父组件交互的异步问题

在使用 el-dialog 组件时,我们可能会遇到子组件与父组件交互的异步问题。例如,我们有以下代码:

vue 复制代码
<LinkPermissionDialog
        v-model:open="openLinkPermission"
        :role="linkedRole"
        :permissions="linkedPermissions"
        :all-permissions="allPermissions"
        @confirm="submitCheckedPermission"
        @close="openLinkPermission = false"
    />

当我们试图向子组件传输 allPermissions 等数据,并在 handleOpen 方法中将 allPermissions 处理为树时,发现子组件生成的树还是上一次的数据。这是因为 el-dialogopen 事件在 DOM 更新前触发,而父组件异步拉取新权限后才将 props.permissions 改掉。因此,当 handleOpen 同步执行时,新数据还没下来,我们处理的其实是上一次的数据。

解决方案

此时,应该使用 watch 监听 allPermissions 的变化,并进行同步:

javascript 复制代码
watch(
    () => props.allPermissions,
    () => {
        tableData.value = handleTree(props.allPermissions);
    },
    { immediate: true }   // 立即执行一次
);

3. 动态路由机制中关于根路由的小问题

在动态路由机制中,我们可能会遇到一些关于根路由的小问题。例如,原来的动态路由机制会将无 component 的组件(即目录)用 LayoutView 来兜底。这样做的问题是,如果出现目录嵌套目录的情况,就会对 Layout 进行重复渲染。

解决方案

这个问题其实很好解决,只需要将目录的 component 置为 null,并整体上添加 LayoutView 作为根路由即可:

javascript 复制代码
/**
 * 获取路由列表
 */
export const buildRoutes = async (menus) => {
    const children = buildNestedRoutes(menus);
    const route = {
        path: '/',
        redirect: '/index',
        component: LayoutView,
        children: children,
        meta: {}
    };
    return route;
};

在这个过程中,我们意识到了重复定义相同的根路由可能会带来一些问题。Vue Router 的路由匹配机制是通过路径 + 其他属性(如 namecomponent)来判断路由是否"重复"的。为了避免奇奇怪怪的隐式覆盖问题,最好统一一个根路由:

javascript 复制代码
/**
 * 加入到 Layout 中的静态路由
 */
export const staticChildren = [
    {
        path: 'index',
        component: () => import('@/views/home/index.vue'),
        name: 'Index',
        meta: {
            title: '首页',
            hidden: false,
        }
    }
];

/**
 * 获取路由列表
 */
export const buildRoutes = async (menus) => {
    const dynamicChildren = buildNestedRoutes(menus);
    // 合并静态路由和动态路由
    const allChildren = mergeChildren(staticChildren, dynamicChildren);
    // 创建根路由
    const rootRoute = {
        path: '/',
        component: LayoutView,
        name: 'Layout',
        redirect: '/index',
        children: allChildren,
        meta: {}
    };
    // 防止重复添加
    if (router.hasRoute('Layout')) router.removeRoute('Layout');

    return rootRoute;
};

我们可以通过 map 来简单地去重,这里就不展示了。

4. refdep 特性

在使用 ref 时,我们可能会遇到一些关于 dep 特性的问题。例如,我们有以下代码:

javascript 复制代码
export const AllPages = {
    pageNum: 1,
    pageSize: 1000000
};

现在有两段类似的代码:

javascript 复制代码
queryParams.value = { pageNum: 1, pageSize: 10};
queryParams.value = AllPages;

我们将其用于对 createdAt 字段进行重置:

vue 复制代码
<el-form-item label="创建时间">
    <el-date-picker v-model="queryParams.createdAt" type="date" placeholder="起始日期" clearable/>
</el-form-item>

第一段代码顺利完成了,但是第二段代码还残留着之前的 createdAt 数据,这是为什么呢?

原因分析

queryParams 中,我们一开始没有 createdAt 这个字段。而在第一次添加 createdAt 后,dep 列表里会添加这个字段的槽位。我们对其重新赋值 { pageNum: 1, pageSize: 10} 后,Vue 的 proxy 会保留引用关系。因为 createdAt 实际上不存在,所以悄悄地对其赋值为 undefinedqueryParams.value = AllPages; 这一步相当于把 ref 重新赋值了一个普通对象,这个对象里面又没有关于 createdAt 的信息,v-model 绑定的路径直接断了(变成访问一个非响应式的、根本不存在的属性),DatePicker 内部监听不到"从有到无"的变动,于是面板里依旧显示旧值。

解决方案

AllPages 对象展开 { ...AllPages },这样就和 { pageNum: 1, pageSize: 10} 等价了。


以上就是我们在使用 Vue.js 过程中遇到的一些常见问题及其解决方案。希望这些内容能对大家有所帮助。


注意事项

  1. 在 Vue 项目中,始终 使用 Vue 的事件处理指令(如 @click, @input, @submit 等)来处理 DOM 事件,而不是原生的 HTML 事件属性。
  2. 使用 watch 监听 props 的变化,以解决子组件与父组件交互的异步问题。
  3. 在动态路由机制中,避免重复定义相同的根路由,统一一个根路由可以避免很多问题。
  4. 注意 refdep 特性,在重新赋值时要确保对象的结构一致,避免出现绑定路径断开的问题。

相关推荐
朱 欢 庆1 小时前
云服务器附件备份到本机内网服务器
运维·服务器·前端·经验分享
支支დ7 小时前
VO by Vercel 前端特定优势:为什么它是构建 AI 应用的新范式
前端·人工智能
香芋芋圆7 小时前
AI 冲击内卷之下,普通前端如何破局?WebGIS—— 低门槛突围赛道
前端·javascript·人工智能·学习·职场发展
INS_KF7 小时前
【编程笔记】成员函数中两个 const 的区别(const Data &getData() const;)
前端·javascript·笔记
宿6748 小时前
vue3-async
前端·javascript·vue.js
YXWik68 小时前
记录前端请求接口在浏览器请求响应的Preview和Response展示的一样的问题
前端
2501_928996228 小时前
GPT-4o换DeepSeek迁移成本多少?中科热备解析API聚合平台技术账本
前端·数据库·人工智能
东风破_8 小时前
从跨域到 WebSocket:前端跨域方案、SSE 与双向实时通信详解
前端·后端
原则猫8 小时前
TS 类型工具
前端
excel9 小时前
Nuxt + Twin CSS 中宽度超过屏幕时底部出现空白的原因与解决方案
前端·javascript