vue v-if对比当前时间与目标时间

本文探讨了在Vue.js中使用v-if指令结合Date.parse方法来判断当前时间是否晚于给定的开始时间。通过这一技巧可以实现在指定日期之前隐藏某些元素的逻辑。
v-if="Date.parse(scope.row.startTime)>new Date()"

Date.parse解析时间字符串

解释一下列ts语句的语法,纯文本输出.<!-- sy1\src\layout\components\Sidebar\SidebarItem.vue --> <template> <div> <!-- <div v-if=" !item.meta || !item.meta.hidden " :class="['menu-wrapper', isCollapse ? 'simple-mode' : 'full-mode', {'first-level': isFirstLevel}]" > --> <div v-if="!item.meta || !item.meta.hidden" :class="['menu-wrapper', 'full-mode', { 'first-level': isFirstLevel }]" > <template v-if="theOnlyOneChild && !theOnlyOneChild.children"> <sidebar-item-link v-if="theOnlyOneChild.meta" :to="resolvePath(theOnlyOneChild.path)" > <el-menu-item :index="resolvePath(theOnlyOneChild.path)" :class="{ 'submenu-title-noDropdown': isFirstLevel }" > <!-- <i v-if="theOnlyOneChild.meta.title==='工作台'" class="iconfont icon img-icon-sel" /> --> <!-- <svg-icon v-if="theOnlyOneChild.meta.title==='工作台'" name="dashboard" width="20" height="20"></svg-icon> --> <i v-if="theOnlyOneChild.meta.icon" class="iconfont" :class="theOnlyOneChild.meta.icon" /> <span v-if="theOnlyOneChild.meta.title" slot="title">{{ theOnlyOneChild.meta.title }}</span> </el-menu-item> </sidebar-item-link> </template> <el-submenu v-else :index="resolvePath(item.path)" popper-append-to-body> <template slot="title"> <i v-if="item.meta && item.meta.icon" class="iconfont" :class="item.meta.icon" /> <span v-if="item.meta && item.meta.title" slot="title">{{ item.meta.title }}</span> </template> <template v-if="item.children"> <sidebar-item v-for="child in item.children" :key="child.path" :item="child" :is-collapse="isCollapse" :is-first-level="false" :base-path="resolvePath(child.path)" class="nest-menu" /> </template> </el-submenu> </div> </div> </template> <script lang="ts"> import path from 'path' import { Component, Prop, Vue } from 'vue-property-decorator' import { UserModule } from '@/store/modules/user' import { Route, RouteConfig } from 'vue-router' import { isExternal } from '@/utils/validate' import SidebarItemLink from './SidebarItemLink.vue' @Component({ name: 'SidebarItem', components: { SidebarItemLink, }, }) export default class extends Vue { @Prop({ required: true }) private item!: RouteConfig @Prop({ default: false }) private isCollapse!: boolean @Prop({ default: true }) private isFirstLevel!: boolean @Prop({ default: '' }) private basePath!: string get showingChildNumber() { if (this.item.children) { const showingChildren = this.item.children.filter((item) => { if (item.meta && item.meta.hidden) { return false } return true }) return showingChildren.length } return 0 } get roles() { return UserModule.roles } get theOnlyOneChild() { if (this.showingChildNumber > 0) { return null } if (this.item.children) { for (let child of this.item.children) { if (!child.meta || !child.meta.hidden) { return child } } } // If there is no children, return itself with path removed, // because this.basePath already conatins item's path information return { ...this.item, path: '' } } private resolvePath(routePath: string) { if (isExternal(routePath)) { return routePath } if (isExternal(this.basePath)) { return this.basePath } return path.resolve(this.basePath, routePath) } } </script>
10-23
该代码是一个基于 Vue.js 和 TypeScript 编写的递归组件 `SidebarItem.vue`,用于在后台管理系统中动态渲染侧边栏菜单项。它配合 Vue Router 的路由配置,支持多级嵌套菜单、图标显示、外链识别、权限过滤等功能。 以下是对该 `.vue` 文件各部分语法的详细解释,纯文本输出。 --- ### 一、`<template>` 部分:视图结构 ```html <div> ``` - 根元素容器,包裹单个菜单项或子菜单组。 #### 条件渲染主容器 ```html <div v-if="!item.meta || !item.meta.hidden" :class="['menu-wrapper', 'full-mode', { 'first-level': isFirstLevel }]"> ``` - 只有当当前路由项没有 `meta` 或 `meta.hidden` 为假时才渲染(即不隐藏); - 动态绑定 CSS 类: - `'menu-wrapper'`: 基础样式类; - `'full-mode'`: 全模式(折叠简化模式对比,原注释中有 `simple-mode`); - `{ 'first-level': isFirstLevel }`: 如果是第一层级菜单,则添加 `first-level` 类。 > 注:被注释掉的部分原本支持折叠状态下的“简略模式”,但当前只保留完整模式。 --- #### 情况一:只有一个可见子项或无子项 → 渲染为 `el-menu-item` ```html <template v-if="theOnlyOneChild && !theOnlyOneChild.children"> <sidebar-item-link :to="resolvePath(theOnlyOneChild.path)"> <el-menu-item :index="resolvePath(theOnlyOneChild.path)" :class="{ 'submenu-title-noDropdown': isFirstLevel }"> <i v-if="theOnlyOneChild.meta.icon" class="iconfont" :class="theOnlyOneChild.meta.icon" /> <span v-if="theOnlyOneChild.meta.title" slot="title">{{ theOnlyOneChild.meta.title }}</span> </el-menu-item> </sidebar-item-link> </template> ``` ##### 判断条件 - `theOnlyOneChild && !theOnlyOneChild.children`: - 表示这个父菜单只有一个有效子菜单,且该子菜单本身不再有子菜单; - 此时将其提升为一级菜单项(避免出现仅含一个子项的下拉菜单),提升用户体验。 ##### `<sidebar-item-link>` - 自定义组件,封装 `<router-link>` 或 `<a>` 标签; -目标路径为外部链接则使用 `<a>`,否则使用 `<router-link>`。 ##### `<el-menu-item>` - Element UI 的菜单项组件; - `:index`:唯一标识,用于高亮匹配; - `slot="title"`:标题插槽,在折叠菜单时显示 Tooltip 内容。 ##### 图标和文字 - 使用 `iconfont` 字体图标,通过 `:class="item.meta.icon"` 动态绑定图标类名; - 显示 `meta.title` 作为菜单文字。 --- #### 情况二:多个子项或有嵌套 → 渲染为 `el-submenu` ```html <el-submenu v-else :index="resolvePath(item.path)" popper-append-to-body> <template slot="title"> <i v-if="item.meta && item.meta.icon" class="iconfont" :class="item.meta.icon" /> <span v-if="item.meta && item.meta.title" slot="title">{{ item.meta.title }}</span> </template> <template v-if="item.children"> <sidebar-item v-for="child in item.children" :key="child.path" :item="child" :is-collapse="isCollapse" :is-first-level="false" :base-path="resolvePath(child.path)" class="nest-menu" /> </template> </el-submenu> ``` ##### `<el-submenu>` - 下拉子菜单组件; - `:index`:必须设置,用于菜单展开/激活控制; - `popper-append-to-body`:是否将弹出层插入 body 中(防止样式错位)。 ##### `slot="title"` - 定义子菜单的标题区域,包含图标和文字。 ##### 递归渲染子菜单 - 使用 `v-for` 遍历 `item.children`; - 继续使用 `<sidebar-item>` 自身进行递归调用; - 传递参数: - `:item="child"`:当前子路由; - `:is-collapse="isCollapse"`:继承折叠状态; - `:is-first-level="false"`:非首层,影响样式的应用; - `:base-path="resolvePath(child.path)"`:拼接后的完整路径前缀; - `class="nest-menu"`:嵌套菜单的样式类。 --- ### 二、`<script lang="ts">` 部分:TypeScript 逻辑 #### 1. 导入依赖 ```ts import path from 'path' ``` - Node.js 内置模块 `path`,用于路径拼接(如 `path.resolve()`); - 在浏览器环境中由 Webpack 提供 polyfill。 ```ts import { Component, Prop, Vue } from 'vue-property-decorator' ``` - 使用装饰器语法开发 Vue 组件; - `Component`: 定义组件选项; - `Prop`: 定义接收的 props; - `Vue`: 基类。 ```ts import { UserModule } from '@/store/modules/user' ``` - Vuex 模块,用于获取用户角色信息(权限判断)。 ```ts import { Route, RouteConfig } from 'vue-router' ``` - Vue Router 类型定义: - `RouteConfig`: 路由配置对象类型(含 `path`, `meta`, `children` 等字段); - `Route`: 当前路由实例类型(运行时数据)。 ```ts import { isExternal } from '@/utils/validate' ``` - 工具函数,判断路径是否为外链(以 `http://` 或 `https://` 开头)。 ```ts import SidebarItemLink from './SidebarItemLink.vue' ``` - 子组件导入,用于包装链接行为。 #### 2. `@Component` 装饰器 ```ts @Component({ name: 'SidebarItem', components: { SidebarItemLink, }, }) ``` - 命名组件为 `'SidebarItem'`; - 注册局部组件 `SidebarItemLink`。 #### 3. 类定义 Props ```ts export default class extends Vue { @Prop({ required: true }) private item!: RouteConfig @Prop({ default: false }) private isCollapse!: boolean @Prop({ default: true }) private isFirstLevel!: boolean @Prop({ default: '' }) private basePath!: string } ``` | Prop 名 | 类型 | 默认值 | 说明 | |--------|------|--------|------| | `item` | `RouteConfig` | 必填 | 当前路由配置对象 | | `isCollapse` | `boolean` | `false` | 是否处于折叠状态 | | `isFirstLevel` | `boolean` | `true` | 是否为第一级菜单(影响样式) | | `basePath` | `string` | `''` | 基础路径前缀,用于拼接子路由 | > `!` 是非空断言操作符,告诉 TypeScript 该属性将在运行时被赋值。 --- #### 4. 计算属性(getters) ##### `showingChildNumber` ```ts get showingChildNumber() { if (this.item.children) { const showingChildren = this.item.children.filter((item) => { if (item.meta && item.meta.hidden) { return false } return true }) return showingChildren.length } return 0 } ``` - 计算当前菜单的有效可见子菜单数量; - 过滤掉 `meta.hidden === true` 的子项; - 用于判断是否应“提级”显示单一子菜单。 ##### `roles` ```ts get roles() { return UserModule.roles } ``` - 获取当前用户的角色列表(可用于更复杂的权限控制,但本文件未使用)。 ##### `theOnlyOneChild` ```ts get theOnlyOneChild() { if (this.showingChildNumber > 0) { return null } if (this.item.children) { for (let child of this.item.children) { if (!child.meta || !child.meta.hidden) { return child } } } return { ...this.item, path: '' } } ``` - 返回唯一有效的子菜单对象(如果只有一个可见子项); - 若无子菜单,则返回自身副本并清空 `path`(防止重复拼接); - 目的是让单一项直接作为菜单展示,而不是包裹在一个展开菜单里。 > 注意:这里的逻辑可以优化为先判断 `showingChildNumber === 1` 再返回那个 child。 --- #### 5. 方法 ##### `resolvePath` ```ts private resolvePath(routePath: string) { if (isExternal(routePath)) { return routePath } if (isExternal(this.basePath)) { return this.basePath } return path.resolve(this.basePath, routePath) } ``` - 解析最终跳转路径: - 如果是外链(如 `https://baidu.com`),直接返回; - 如果基础路径是外链,则返回基础路径(防止拼接错误); - 否则使用 `path.resolve(basePath, routePath)` 拼接相对路径。 > 示例: > - `basePath = '/system'`, `routePath = 'user'` → 结果 `/system/user` --- ### 三、关键技术点总结 | 技术 | 说明 | |------|------| | **递归组件** | `<sidebar-item>` 调用自身实现无限层级菜单 | | **动态路由解析** | 从 `vue-router` 的 `routes` 构建菜单树 | | **权限控制预留接口** | 通过 `meta.hidden` 控制菜单显隐,未来可扩展角色权限 | | **外链识别处理** | 使用 `isExternal()` 区分内外部链接 | | **路径拼接安全** | 使用 `path.resolve()` 正确处理相对路径 | | **提升用户体验** | 单一子菜单“提级”展示,避免冗余下拉 | --- ### 四、潜在问题优化建议 1. **`isFirstLevel` 默认为 `true`,但在递归调用时传入 `false`,合理但易误解** → 可改为 `level?: number` 更清晰表达层级深度。 2. **`theOnlyOneChild` 判断逻辑不够严谨** → 应先判断 `showingChildNumber === 1` 才返回那个 child,而不是只要 ≤1 就返回。 3. **未使用 `roles` 属性做权限过滤** → 可增强 `v-if` 条件,检查用户角色是否有权访问此菜单。 4. **`path` 模块在浏览器中存在兼容性风险** → 对于前端项目,可用字符串拼接替代 `path.resolve`,或确保 Webpack 正确配置 polyfill。 5. **`popper-append-to-body` 可能导致定位问题** → 在某些布局下需测试下拉菜单位置是否正确。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值