d40: vue杂项问题

导航

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

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-dialog 的 open 事件在 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 的路由匹配机制是通过路径 + 其他属性(如 name、component)来判断路由是否"重复"的。为了避免奇奇怪怪的隐式覆盖问题,最好统一一个根路由:

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. ref 的 dep 特性

在使用 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 实际上不存在,所以悄悄地对其赋值为 undefined。queryParams.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. 注意 ref 的 dep 特性,在重新赋值时要确保对象的结构一致,避免出现绑定路径断开的问题。

相关推荐
子兮曰3 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰3 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
前端小万3 天前
写公众号赚了 3000 块后,我做了一款叫 "一键成稿" 的软件
前端·微信小程序
爱勇宝3 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
A黄俊辉A3 天前
uniapp webview中实现 app和内嵌的H5双向通信
vue.js·json
三十而立洋3 天前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
卡布鲁3 天前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
李少兄3 天前
JavaScript 隐式全局变量解析
javascript
honkun63 天前
vue 表格组件 vxe-table 配置 ajax 请求自动加载数据与表单查询
vue.js·vxe-table
kybs19913 天前
全球灾害数据分析可视化 毕业设计-附源码66794
vue.js·spring boot·mysql·安全·django·c#·asp.net