一、scoped
1.1 scoped作用域
在Vue中,scoped是一种CSS样式封装机制,用于将样式限制在当前组件范围内,防止样式泄露到全局或其他组件中。其原理是:当在Vue组件的<style>
标签上添加scoped属性时,Vue会为该组件中的每个元素添加一个唯一的属性(如data-v-12345678),并修改CSS选择器以仅匹配这些带有特定属性的元素。
如下面这个示例组件
javascript
<template>
<div class="container">
<h1>标题</h1>
<p>段落内容</p>
</div>
</template>
<style scoped>
.container {
background-color: #f0f0f0;
}
h1 {
color: blue;
}
p {
font-size: 14px;
}
</style>
Vue会将其编译为类似这样的内容
javascript
Html
<div class="container" data-v-12345678>
<h1 data-v-12345678>标题</h1>
<p data-v-12345678>段落内容</p>
</div>
Css
.container[data-v-12345678] {
background-color: #f0f0f0;
}
h1[data-v-12345678] {
color: blue;
}
p[data-v-12345678] {
font-size: 14px;
}
这样,样式就只会影响当前组件内的元素,不会影响其他组件。
1.2 scoped样式穿透
scoped样式穿透用于在使用scoped属性的样式中修改子组件的内部样式。通常情况下,Vue的scoped样式只会作用于当前组件的元素,但有时候后我们需要修改子组件的样式,这时就需要进行样式穿透。 上面我们说过当在组件中使用scoped时,Vue会自动为当前组件的所有元素添加一个唯一的属性,同时也会修改CSS选择器以匹配这些元素。这会导致无法直接修改子组件的样式,因为子组件的元素没有这个唯一属性。
1.2.1 如何进行样式穿透
javascript
在Vue3中,主要使用:deep()伪类选择器来实现样式穿透
.parent :deep(.child) {
color: red;
}
这将被编译为:
javascript
.parent[data-v-123456] .child {
color: red;
}
在src→components→RightToolbar→index.vue中
javascript
<style lang='scss' scoped>
:deep(.el-transfer__button) {
border-radius: 50%;
display: block;
margin-left: 0px;
}
:deep(.el-transfer__button:first-child) {
margin-bottom: 10px;
}
:deep(.el-dropdown-menu__item) {
line-height: 30px;
padding: 0 17px;
}
.check-line {
width: 90%;
height: 1px;
background-color: #ccc;
margin: 3px auto;
}
</style>
这里deep()选择器来修改Element Plus组件的内部样式,如.el-transfer__button和.el-dropdown-menu__item。
样式穿透主要用于以下场景: 修改第三方组件库的样式:如Element Plus、Ant Design Vue等 修改子组件的特定样式:当我们需要自定义子组件的外观时 覆盖组件库的默认样式:在不修改组件库源码的情况下改变其外观 注意事项: 谨慎使用:过度使用样式穿透可能会破坏组件封装性 优先使用组件提供的API:许多组件库提供了自定义样式的属性或插槽 避免深度嵌套:尽量只穿透一层,避免对深层嵌套的元素进行样式修改
二 路由
2.1 路由跳转的两种方式
什么是路由跳转? 路由跳转是指在单页应用(SPA)中,通过改变URL地址来切换不同页面内容的过程,而无需重新加载整个页面。Vue Router是Vue.js官方的路由管理器,提供了两种主要的路由跳转方式:声明式和编程式。
2.1.1 声明式路由跳转
声明式路由跳转是通过Vue Router提供的组件来实现的。它通过在模板中声明链接来触发路由跳转。
javascript
<router-link to="/path">链接文本</router-link>
在src→layout→components→Navbar.vue中即有声明式路由跳转的使用
javascript
<router-link to="/user/profile">
<el-dropdown-item>个人中心</el-dropdown-item>
</router-link>
其它用法:
- 使用对象形式
javascript
<router-link :to="{ path: '/user', query: { id: 123 }}">用户</router-link>
query参数会显示在url中,类似于GET请求的查询参数,其生成的URL为:代码会生成URL:/user?id=123,参数可以通过this.$route.query在目标组件中访问
- 使用命名路由
javascript
<router-link :to="{ name: 'user', params: { id: 123 }}">用户</router-link>
params一般不会显示在url中,需要通过命名路由(name)来使用,必须在路由配置中预先定义。 假设路由配置如下:
javascript
{
path: '/user/:id',
name: 'user',
component: UserComponent
}
上面生成的URL为:/user/123,参数可以通过this.$route.params来获取
- 带额外属性
javascript
<router-link :to="{ path: '/user' }" replace>用户</router-link>
使用replace来导航不会在浏览器历史记录中留下记录,适用于登录成功后跳转到主页的场景
2.1.2 编程式路由跳转
编程式路由跳转是通过JavaScript代码调用Vue Router实例的方法来实现路由跳转。这种方式更加灵活,可以在满足特定条件时进行跳转 基本语法
javascript
// 通过router实例进行跳转
this.$router.push('/path')
// 或者在Composition API中
import { useRouter } from 'vue-router'
const router = useRouter()
router.push('/path')
在src→components→HeaderSearch→index.vue中可以看到编程式路由跳转的使用:
javascript
function change(val) {
const path = val.path
const query = val.query
if (isHttp(path)) {
// http(s):// 路径新窗口打开
const pindex = path.indexOf("http")
window.open(path.substr(pindex, path.length), "_blank")
} else {
if (query) {
router.push({ path: path, query: JSON.parse(query) })
} else {
router.push(path)
}
}
}
编程式路由跳转的其他方法:
- router.push() - 导航到不同的URL
javascript
// 字符串路径
router.push('/users/123')
// 对象形式
router.push({ path: '/users', query: { id: 123 }})
router.push({ name: 'user', params: { id: 123 }})
// 带有查询参数,结果是 /user?id=123
router.push({ path: '/user', query: { id: 123 }})
// 带有hash,结果是 /user#team
router.push({ path: '/user', hash: '#team' })
- router.replace() - 导航到不同的URL,但不会向history添加新纪录
javascript
router.replace('/users/123')
- router.go(n) - 在浏览器历史记录中前进或后退
javascript
// 后退一步
router.go(-1)
// 前进一步
router.go(1)
// 后退一步
router.back()
// 前进一步
router.forward()
声明式和编程式路由跳转各有优势:
- 声明式路由适用于简单的、直接的页面跳转,在模板中就可以清晰地看到跳转目标
- 编程式路由适用于需要根据条件判断、处理复杂逻辑的跳转场景,提供了更大的灵活性 在实际开发中,我们会根据具体需求选择合适的跳转方式。对于简单的页面链接,使用
<router-link>
更加直观;对于需要条件判断、动态跳转的场景,编程式跳转更加合适。
2.2 动态路由的跳转方式
动态路由是指在应用运行时根据条件动态添加、删除或修改路由配置,而不是在应用初始化时就固定所有的路由。这种方式允许我们根据用户权限、角色或其他条件来动态决定用户可以访问哪些页面。 动态路由跳转本质上与普通路由跳转没有区别,都是使用声明式或编程式方式进行跳转。关键在于这些路由是在运行时动态生成和注册的。
2.2.1 动态路由跳转实例:
在src→api→menu.js中,通过getRouters接口从后端获取路由配置
javascript
// 获取路由
export const getRouters = () => {
return request({
url: '/getRouters',
method: 'get'
})
}
然后在src→permission.js中处理这些路由配置并动态添加到Vue Router中
javascript
usePermissionStore().generateRoutes().then(accessRoutes => {
// 根据roles权限生成可访问的路由表
accessRoutes.forEach(route => {
if (!isHttp(route.path)) {
router.addRoute(route) // 动态添加可访问路由表
}
})
next({ ...to, replace: true }) // hack方法 确保addRoutes已完成
})
动态路由跳转主要特点:
- 权限控制:用户只能看到和访问其有权限的路由
- 灵活性:可以根据不同用户显示不同的菜单和页面
在若依中,动态路由的实现主要依赖于:
- 后端提供用户权限相关的路由配置
- 前端根据权限动态生成和注册路由
- 通过Vue Router的addRoute方法动态添加路由
- 使用相同的声明式或编程式方式进行路由跳转