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 特性,在重新赋值时要确保对象的结构一致,避免出现绑定路径断开的问题。

相关推荐
Mintopia2 小时前
领域适配 AIGC:垂直行业 Web 应用的微调技术实践
前端·javascript·aigc
Mintopia2 小时前
Next.js 内置后端能力扩展 —— 重定向与路由保护
前端·javascript·next.js
Olrookie2 小时前
若依前后端分离版学习笔记(十八)——页面权限,页签缓存以及图标,字典,参数的使用
vue.js·笔记·学习
IT_陈寒3 小时前
Python 3.12 性能暴增50%!这5个新特性让老项目直接起飞
前端·人工智能·后端
excel3 小时前
JavaScript 中的对象池:复用对象的高效方案
前端
excel3 小时前
Vue实例挂载的过程中发生了什么
前端
琹箐3 小时前
Aupload + vuedraggable实现 上传的文件可以拖拽排序
前端·vue.js
前端 贾公子3 小时前
Vue.js props mutating:反模式如何被视为一种良好实践。
前端·javascript·vue.js
Filotimo_9 小时前
2.CSS3.(2).html
前端·css