跨域问题(Cross-Origin Resource Sharing, CORS)是指在浏览器中,当一个资源试图从一个不同的源请求另一个资源时所遇到的限制。这种限制是浏览器为了保护用户安全而实施的一种同源策略(Same-origin policy)。同源指的是协议、域名以及端口号三者都相同。如果这三者中的任何一个不同,那么它们就被认为是不同的源。
解决跨域问题的方法有几种:
CORS配置:最直接的方式是在服务器端设置适当的CORS头。例如,在Express.js应用中可以通过安装并使用cors
中间件来快速实现。
const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors());
app.get('/data', (req, res) => {
res.json({message: 'This is CORS-enabled for all origins!'});
});
app.listen(8080, () => console.log('Server running on port 8080'));
JSONP:这是一种较老的技术,仅支持GET请求。它的工作原理是动态创建一个标签,并将跨域请求的URL指定为该标签的
src
属性值。服务器端需要返回一段JavaScript代码,这段代码调用一个客户端预先定义好的回调函数,并以参数的形式传递请求结果。由于现代浏览器支持CORS,这种方法现在较少使用。
使用代理:可以设置一个代理服务器,前端向这个代理服务器发送请求,代理服务器再向目标服务器转发请求并将响应返回给前端。这样就不存在跨域问题了,因为请求都是在同一源内发生的。
在开发环境中,可以通过配置Vue CLI提供的vue.config.js
文件来设置代理,以解决开发时的跨域问题。这将使得开发服务器能够转发请求到指定的目标服务器,从而避免了浏览器的同源策略限制。
module.exports = {
devServer: {
proxy: {
'/api': {
target: 'http://your-backend-server.com', // 目标服务器地址
changeOrigin: true,
pathRewrite: {
'^/api': '' // 重写路径,去掉/api前缀
}
}
}
}
}
在这个例子中,所有以/api
开头的请求都会被代理到target
指定的服务器上 。
在Vue.js中,过滤器(Filters)主要用于对文本进行格式化操作。虽然从Vue 3开始,官方已经移除了过滤器这一特性,推荐使用计算属性(Computed Properties)或方法(Methods)来替代它们,但在Vue 2中,过滤器仍然是一个有效的功能,尤其是在需要对文本进行简单转换而不修改原始数据的情况下。
本质上,过滤器是定义为函数的形式,接受一个值作为输入参数,然后返回一个新的值。这个过程不会修改原始值,而是基于原始值创建一个新的值用于显示或其他用途。
定义全局过滤器
可以在main.js
中定义全局过滤器,这样所有组件都可以使用这些过滤器:
Vue.filter('capitalize', function(value) {
if (!value) return '';
value = value.toString();
return value.charAt(0).toUpperCase() + value.slice(1);
});
Vue.filter('currency', function(value) {
if (typeof value !== "number") {
return value;
}
var formatter = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
});
return formatter.format(value);
});
定义局部过滤器
也可以在单个组件内定义过滤器,仅该组件可以使用:
export default {
// ...
filters: {
capitalize(value) {
if (!value) return '';
value = value.toString();
return value.charAt(0).toUpperCase() + value.slice(1);
},
currency(value) {
if (typeof value !== "number") {
return value;
}
var formatter = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
});
return formatter.format(value);
}
}
}
一旦定义了过滤器,就可以在模板中使用管道符号|
应用过滤器:
{{ message | capitalize }}
{{ amount | currency }}
虚拟DOM(Virtual DOM)是一种编程概念,它指的是在Web应用中,使用JavaScript对象来模拟真实的DOM树。每个虚拟DOM节点对应着真实DOM树中的一个元素。通过这种方式,可以有效地减少直接操作真实DOM的次数,从而提高性能。
虚拟DOM的主要目的是优化用户界面的更新过程。当数据模型发生变化时,不是立即更新真实DOM,而是先更新虚拟DOM。然后通过比较新旧两个虚拟DOM树的差异(这个过程称为Diff算法),找出需要更新的部分,并将这些变化批量地应用到真实DOM上。这样做的好处是可以最小化重绘和回流,提高渲染效率。
①创建虚拟dom:
function createElement(type, props = {}, ...children) {
return { type, props, children };
}
②渲染虚拟dom为真实dom:
function render(vnode){
...
return node
}
③使用diff算法最小化更新
④更新真实dom
在 Vue 项目中实现权限管理是一个常见的需求,通常涉及路由权限、按钮权限和接口权限的控制。
核心思路是 动态管理路由 和 全局权限校验
路由权限是指根据用户角色或权限动态加载可访问的路由。
实现步骤:
定义路由表:
将路由分为公共路由(所有用户可访问)和权限路由(根据用户角色动态加载)。
// publicRoutes.js
export const publicRoutes = [
{ path: '/login', component: () => import('@/views/Login.vue') },
{ path: '/404', component: () => import('@/views/404.vue') },
];
// privateRoutes.js
export const privateRoutes = [
{ path: '/dashboard', component: () => import('@/views/Dashboard.vue'), meta: { role: 'admin' } },
{ path: '/user', component: () => import('@/views/User.vue'), meta: { role: 'user' } },
];
根据用户角色从后端获取权限列表,动态添加路由。
import { publicRoutes, privateRoutes } from './routes';
import router from './router';
const addRoutes = (role) => {
const allowedRoutes = privateRoutes.filter(route => route.meta.role === role);
allowedRoutes.forEach(route => router.addRoute(route));
};
// 登录成功后调用
addRoutes('admin');
使用 beforeEach
钩子检查用户是否有权限访问目标路由。
router.beforeEach((to, from, next) => {
const userRole = localStorage.getItem('userRole'); // 从本地存储获取用户角色
if (to.meta.role && to.meta.role !== userRole) {
next('/404'); // 无权限则跳转到 404
} else {
next();
}
});
按钮权限是指根据用户角色或权限动态显示或隐藏页面中的按钮。
实现步骤:
自定义指令:
创建一个自定义指令 v-permission
,用于控制按钮的显示和隐藏。
// main.js
Vue.directive('permission', {
inserted(el, binding, vnode) {
const userRole = localStorage.getItem('userRole');
if (binding.value !== userRole) {
el.parentNode.removeChild(el); // 无权限则移除按钮
}
},
});
在按钮上使用 v-permission
指令。
接口权限是指根据用户角色或权限控制用户能否调用某些接口。
实现步骤:
后端控制:
后端接口根据用户角色返回不同的数据或状态码(如 403 无权限)。
前端拦截:
在请求拦截器中检查用户权限。
axios.interceptors.request.use((config) => {
const userRole = localStorage.getItem('userRole');
if (config.url === '/admin/data' && userRole !== 'admin') {
return Promise.reject(new Error('无权限访问'));
}
return config;
});
用户登录:
用户登录后,后端返回用户角色和权限列表。
前端将角色和权限信息存储在 localStorage
或 Vuex
中。
动态路由加载:
根据用户角色动态加载路由。
路由守卫:
在路由跳转时检查用户权限。
按钮权限:
使用自定义指令控制按钮的显示和隐藏。
接口权限:
在请求拦截器中检查用户权限。
1. 代码分割(Code Splitting)
SplitChunksPlugin
或 Vite 的自动分割,将代码拆分成多个小块。2. 路由懒加载
import()
)实现按需加载路由组件。3. Tree Shaking
package.json
中设置 "sideEffects": false
。4. 压缩代码
TerserPlugin
压缩 JS,CssMinimizerPlugin
压缩 CSS。1. 图片压缩与格式优化
2. 字体文件优化
font-display: swap;
避免字体加载阻塞渲染。3. 开启 Gzip/Brotli 压缩
1. 强缓存(Cache-Control)
2. 版本号哈希
app.3a87f.js
),确保内容变更后缓存失效。1. 服务端渲染(SSR)
2. 预渲染(Prerendering)
vue-cli-plugin-prerender-spa
、react-snap
。3. 骨架屏(Skeleton Screen)
1.资源预加载(Preload/Prefetch)
提前加载关键资源。在前端开发中,回流(Reflow) 和重绘(Repaint) 是浏览器渲染机制的关键概念,直接影响页面性能。以下是详细解析:
回流(Reflow)
重绘(Repaint)
color
、background-color
、visibility
等。1. 批量 DOM 操作
DocumentFragment
或离线 DOMconst fragment = document.createDocumentFragment();
for (let i = 0; i < 100; i++) {
const node = document.createElement("div");
fragment.appendChild(node);
}
document.body.appendChild(fragment);
通过 display: none
隐藏元素,操作完成后再显示
2. 避免频繁读取布局属性
3. 使用 CSS 优化
transform
和 opacity
实现动画4. 避免表格布局和复杂选择器
display: table
)易触发连锁回流。CSS 预处理器(CSS Preprocessor)通过扩展 CSS 的功能,提供了更高效、更灵活的样式编写方式。以下是主流 CSS 预处理器(Sass、Less、Stylus)的区别与特点总结。
变量
支持定义变量,方便复用和维护样式
$primary-color: #3498db; // Sass
@primary-color: #3498db; // Less
primary-color = #3498db // Stylus
支持嵌套规则,减少代码冗余。
.container {
.item {
color: red;
}
}
支持定义可复用的样式块。
@mixin border-radius($radius) { // Sass
border-radius: $radius;
}
.box { @include border-radius(10px); }
// Less
.alert {
font-weight: 700;
}
.highlight(@color: red) {
font-size: 1.2em;
color: @color;
}
.heads-up {
.alert;
.highlight(red);
}
支持模块化,将样式拆分为多个文件
@import "variables"; // Sass/Less/Stylus
.scss
语法。