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

相关推荐
2601_94959365几秒前
React Native 鸿蒙跨平台开发:LinearGradient 渐变动画效果
javascript·react native·react.js
黄筱筱筱筱筱筱筱2 分钟前
7.适合新手小白学习Python的异常处理(Exception)
java·前端·数据库·python
qq_177767373 分钟前
React Native鸿蒙跨平台音乐播放器涉及实时进度更新、播放控制、列表交互、状态管理等核心技术点
javascript·react native·react.js·ecmascript·交互·harmonyos
QQ17958063963 分钟前
基于springboot+vue的hive的歌曲音乐筛选推荐系统网站(源码+lw+部署文档+讲解等)
vue.js·hive·spring boot
2501_920931706 分钟前
React Native鸿蒙跨平台实现了简单的商品图片轮播功能,为用户提供了直观的商品图片浏览体验,帮助用户全面了解商品外观
javascript·react native·react.js·ecmascript·harmonyos
Yeats_Liao9 分钟前
微调决策树:何时使用Prompt Engineering,何时选择Fine-tuning?
前端·人工智能·深度学习·算法·决策树·机器学习·prompt
晚霞的不甘10 分钟前
Flutter for OpenHarmony 实现 iOS 风格科学计算器:从 UI 到表达式求值的完整解析
前端·flutter·ui·ios·前端框架·交互
陈希瑞13 分钟前
OpenClaw Chrome扩展使用教程 - 浏览器中继控制
前端·chrome
m0_7482331716 分钟前
Laravel+Vue:全栈开发终极指南
vue.js·php·laravel
雨季66617 分钟前
Flutter 三端应用实战:OpenHarmony “呼吸灯”——在焦虑时代守护每一次呼吸的数字禅修
开发语言·前端·flutter·ui·交互