Vue在开发中的实战使用
解决SPA单页应用首屏加载慢
首屏时间(First Contentful Paint),指的是浏览器从响应用户输入网址地址,到首屏内容渲染完成的时间,此时整个网页不一定要全部渲染完成,但需要展示当前视窗需要的内容
在页面渲染的过程,导致加载速度慢的因素可能如下:
- 网络延时问题
- 资源文件体积是否过大
- 资源是否重复发送请求去加载了
- 加载脚本的时候,渲染内容堵塞了
常见的几种SPA首屏优化方式
1.减小入口文件体积
在vue-router
配置路由的时候,采用路由懒加载
//动态路由的使用
routes:[
path: 'Blogs',
name: 'ShowBlogs',
component: () => import('./components/ShowBlogs.vue')
]
2.静态资源本地缓存
后端返回资源问题:
- 采用
HTTP
缓存,设置Cache-Control
,Last-Modified
,Etag
等响应头
//axios设置HTTP缓存
axios.get('/api/data', {
headers: {
'Cache-Control': 'max-age=3600' // 设置缓存1小时
}
}).then(response => {
console.log(response.data);
});
axios.get('/api/data', {
headers: {
'Expires': new Date(Date.now() + 3600 * 1000).toUTCString() // 设置缓存1小时
}
}).then(response => {
console.log(response.data);
});
- 采用
Service Worker
离线缓存
前端合理利用localStorage
localStorage
具有以下特点:
- 容量为 5MB 左右,不同浏览器可能略有不同。
- 仅存储字符串类型的键值对,可以使用
JSON.stringify()
和JSON.parse()
来处理复杂的数据类型。 - 存储的数据是基于域名的,不同的域名有各自的存储空间,同一域名的不同页面可以共享
localStorage
数据。
//localStorage的使用
// 存储数据到 localStorage
localStorage.setItem('name', 'Alice');
localStorage.setItem('age', '28');
// 从 localStorage 中获取数据
const name = localStorage.getItem('name');
const age = localStorage.getItem('age');
console.log(`My name is ${name} and I am ${age} years old.`);
3.UI框架按需加载
//方案一 手动导入
import { Button, Input, Pagination, Table, TableColumn, MessageBox } from 'element-ui';
Vue.use(Button)
Vue.use(Input)
Vue.use(Pagination)
//方案二 使用插件
4.图片资源的压缩
使用canvas将图片压缩
- 将图片通过
FileReader
读取为Image
对象 - 创建一个
canvas
画布,并将图片绘制到画布中 - 使用
canvas
的toBlob
方法将画布内容导出为Blob
对象 - 将
Blob
对象转换成File
对象,以便上传到服务器
示例代码:
const compress = (file, maxWidth = 750) => {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = (e) => {
const img = new Image();
img.src = e.target.result;
img.onload = () => {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
let width = img.width;
let height = img.height;
if (width > maxWidth) {
height = height * (maxWidth / width);
width = maxWidth;
}
canvas.width = width;
canvas.height = height;
ctx.drawImage(img, 0, 0, width, height);
canvas.toBlob(
(blob) => {
const newFile = new File([blob], file.name, {
type: 'image/jpeg',
lastModified: Date.now()
});
resolve(newFile);
},
'image/jpeg',
0.7
);
};
};
reader.onerror = (e) => {
reject(e);
};
});
};
使用第三方库
compressorjs
:https://github.com/fengyuanchen/compressorjsimage-conversion
:https://github.com/alexcorvi/image-conversion
这些库都提供了简单易用的 API,可以快速地实现图片压缩功能。
5.组件重复打包
Webpack 在处理代码时,会将代码划分成多个 chunk,每个 chunk 可能包含多个 module,而每个 module 又可能引入多个组件和库。如果不加处理,Webpack 可能会将相同的组件或库打包进多个 chunk,导致代码冗余、体积增大,加载速度变慢。
为了避免组件和库的重复打包,Webpack 提供了 splitChunks
配置项,可以将相同的代码块提取出来,打包到一个单独的文件中。以下是一个示例配置:
module.exports = {
// ...
optimization: {
splitChunks: {
chunks: 'all',
minSize: 20000,
minChunks: 1,
maxAsyncRequests: 30,
maxInitialRequests: 30,
enforceSizeThreshold: 50000,
cacheGroups: {
defaultVendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10,
reuseExistingChunk: true
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true
}
}
}
}
}
6.开启GZip压缩
cnmp i compression-webpack-plugin -D
const CompressionPlugin = require('compression-webpack-plugin')
configureWebpack: (config) => {
if (process.env.NODE_ENV === 'production') {
// 为生产环境修改配置...
config.mode = 'production'
return {
plugins: [new CompressionPlugin({
test: /\.js$|\.html$|\.css/, //匹配文件名
threshold: 10240, //对超过10k的数据进行压缩
deleteOriginalAssets: false //是否删除原文件
})]
}
}
7.使用SSR
从头搭建一个服务端渲染是很复杂的,vue
应用建议使用Nuxt.js
实现服务端渲染
权限管理方案
Vue 的权限管理可以通过以下步骤来实现:
- 定义权限:首先需要定义用户角色和权限。用户角色可以根据其职能分为不同的组,例如管理员、编辑、普通用户等,每个组都有其对应的权限。权限可以定义为每个组能够执行的操作和访问的资源,例如读取、写入、删除等。
- 管理权限:在 Vue 应用程序中,可以使用 Vuex 管理权限。定义一个全局的状态来存储当前用户的角色和权限信息,并在应用程序的入口处检查用户是否有访问权限。可以在路由导航守卫中检查用户是否有访问权限,如果没有则重定向到登录页面或者其他错误页面。
- 组件级别的权限控制:对于需要控制访问权限的组件,可以通过在组件内部进行条件渲染来实现。例如,可以通过 v-if 指令控制组件的显示与隐藏,根据用户的角色和权限决定是否显示该组件。
- 指令级别的权限控制:对于一些需要控制操作权限的按钮或者输入框等,可以通过自定义指令来实现权限控制。例如,可以自定义一个 v-permission 指令,根据用户的权限来控制按钮是否可点击或者输入框是否可编辑。
总之,Vue 的权限管理可以通过定义角色和权限、管理权限、组件级别和指令级别的权限控制来实现。
具体的代码实现可以根据具体需求和项目结构进行设计,以下是一个基本的权限管理实现的示例代码:
- 定义权限信息
const roles = [
{
role: 'admin',
permissions: ['read', 'write', 'delete']
},
{
role: 'editor',
permissions: ['read', 'write']
},
{
role: 'user',
permissions: ['read']
}
]
- 管理权限
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
user: {
role: 'user',//角色
permissions: ['read']//权限数组
}
},
getters: {
hasPermission: (state) => (permission) => {//判断权限
return state.user.permissions.includes(permission)
},
isAdmin: (state) => {//判断角色
return state.user.role === 'admin'
}
}
})
- 组件级别的权限控制
<template>
<div v-if="$store.getters.hasPermission('read')">This is a component for users with read permission</div>
<div v-if="$store.getters.isAdmin">This is a component for admins</div>
</template>
- 指令级别的权限控制
Vue.directive('permission', {
bind: (el, binding) => {
if (!$store.getters.hasPermission(binding.value)) {
el.disabled = true
el.classList.add('disabled')
}
}
})
然后,在组件中可以这样使用:
<template>
<button v-permission="'write'">Submit</button>
</template>
组件封装的步骤
- 创建组件:首先,您需要创建一个Vue组件。在Vue.js中,可以使用Vue.component()方法来创建组件。这个方法接受两个参数:组件名称和一个包含组件选项的对象。
例如:
Vue.component('my-component', {
// 组件选项
})
- 定义模板:组件模板是组件输出的HTML代码。在组件选项中,您可以使用template属性来定义组件的模板。
例如:
Vue.component('my-component', {
template: '<div>这是我的组件</div>'
})
- 使用props传递数据:组件之间经常需要共享数据。在Vue.js中,可以使用props属性来定义接受的属性,父组件可以将数据传递给子组件。
例如:
Vue.component('my-component', {
props: ['message'],
template: '<div>{{ message }}</div>'
})
- 发布事件:子组件可能需要与父组件进行通信。在Vue.js中,您可以使用$emit()方法触发事件,父组件可以使用v-on指令来监听事件。
例如:
Vue.component('my-component', {
template: '<button @click="onClick">点击我</button>',
methods: {
onClick() {
this.$emit('clicked')
}
}
})
- 注册组件:一旦定义了组件,就需要在应用程序中注册它们。在Vue.js中,可以使用Vue实例的components属性来注册组件。
例如:
new Vue({
el: '#app',
components: {
'my-component': MyComponent
}
})
- 使用组件:一旦注册了组件,就可以在应用程序中使用它们了。您可以在HTML中使用组件名称作为自定义元素来渲染组件。
例如:
phpCopy code<div id="app">
<my-component message="Hello World"></my-component>
</div>
这就是封装Vue组件的基本步骤。通过将组件封装成自定义元素,您可以轻松地重用组件,并且可以帮助您在应用程序中保持一致性。
自定义指令的步骤
Vue 指令是 Vue.js 框架的一个重要特性,它们允许开发人员在 HTML 元素上添加特殊的行为。Vue.js 提供了多种内置指令,例如 v-if、v-show、v-for 等。同时,Vue.js 还允许开发人员创建自定义指令来满足项目特定需求。
以下是一个简单的自定义指令示例,用于将元素的背景色设置为指定的颜色:
Vue.directive('bg-color', {
bind: function (el, binding) {
el.style.backgroundColor = binding.value
}
})
这个自定义指令被命名为 "bg-color",它接受一个参数作为指令的值。当指令绑定到元素上时,它将元素的背景色设置为该值。例如,要将一个 div 元素的背景色设置为红色,可以这样使用:
<div v-bg-color="'red'">这是一个红色背景的 div 元素</div>
注意,指令的值需要用单引号或双引号括起来,因为它是一个 JavaScript 表达式。
除了 bind 钩子函数,Vue.js 还提供了其它钩子函数来处理指令的不同生命周期事件。例如,可以使用 inserted 钩子函数在元素插入到 DOM 中时执行特定操作。
自定义指令是 Vue.js 框架的一个强大功能,它们可以帮助开发人员更灵活地控制应用程序的行为。
Vue 自定义指令主要用于在 Vue.js 应用程序中处理 DOM 操作和事件处理。开发人员可以使用自定义指令来扩展 Vue.js 框架的功能,以满足应用程序的特定需求。
以下是一些使用自定义指令的常见场景:
- 操作 DOM:在某些情况下,Vue.js 内置指令无法完全满足需求。自定义指令可以用来执行一些更复杂的 DOM 操作,例如创建和更新 DOM 元素、设置样式和属性等。
- 处理输入格式化:自定义指令可以用来处理用户输入的格式,例如限制输入内容的长度、格式化输入内容等。
- 与第三方库集成:当使用第三方库(如 D3.js)时,自定义指令可以提供一种简单的方法来集成这些库并与 Vue.js 应用程序进行交互。
- 处理事件:自定义指令可以用来处理各种事件,例如点击、拖拽、滚动等。自定义指令可以将事件处理逻辑与模板分离,使代码更易于维护。
总之,自定义指令是 Vue.js 框架的一个重要功能,它可以帮助开发人员更灵活地控制应用程序的行为,处理 DOM 操作和事件处理等方面的问题。
以下是一些使用自定义指令的具体例子:
- 只允许输入数字的指令:
Vue.directive('number-only', {
bind: function (el) {
el.addEventListener('input', function () {
this.value = this.value.replace(/[^\d]/g, '')
})
}
})
这个指令会绑定到一个输入框上,当用户输入非数字字符时,它会自动将其替换为空字符串。使用方法如下:
<input v-number-only type="text">
- 自动聚焦输入框的指令:
Vue.directive('autofocus', {
inserted: function (el) {
el.focus()
}
})
这个指令会在元素被插入到 DOM 中时自动聚焦。使用方法如下:
<input v-autofocus type="text">
- 根据滚动位置动态改变元素样式的指令:
Vue.directive('scroll-class', {
bind: function (el, binding) {
window.addEventListener('scroll', function () {
if (window.scrollY > binding.value) {
el.classList.add('scrolled')
} else {
el.classList.remove('scrolled')
}
})
}
})
这个指令会在滚动窗口时根据滚动位置添加或删除指定的 CSS 类名。使用方法如下:
<div v-scroll-class="200"></div>
当滚动位置超过 200 像素时,元素将添加一个名为 "scrolled" 的 CSS 类名。
数据持久化方案
在 Vue.js 中实现数据的持久化可以通过以下几种方式:
- LocalStorage:LocalStorage 是浏览器提供的一种本地存储方案,可以将数据存储在用户的本地计算机上,即使用户关闭浏览器或重新打开页面,数据也不会丢失。在 Vue.js 中,可以通过以下方式将数据存储到 LocalStorage 中:
// 将数据存储到 LocalStorage 中
localStorage.setItem('data', JSON.stringify(this.data))
// 从 LocalStorage 中读取数据
var data = JSON.parse(localStorage.getItem('data'))
- SessionStorage:与 LocalStorage 类似,SessionStorage 也是浏览器提供的一种本地存储方案,不同的是 SessionStorage 中存储的数据会在用户关闭浏览器或者浏览器会话结束时被删除。在 Vue.js 中,可以通过以下方式将数据存储到 SessionStorage 中:
// 将数据存储到 SessionStorage 中
sessionStorage.setItem('data', JSON.stringify(this.data))
// 从 SessionStorage 中读取数据
var data = JSON.parse(sessionStorage.getItem('data'))
- Cookies:Cookies 是一种在客户端存储数据的技术,可以将数据存储在用户的计算机上,即使用户关闭浏览器或重新打开页面,数据也不会丢失。在 Vue.js 中,可以通过以下方式将数据存储到 Cookies 中:
// 将数据存储到 Cookies 中
document.cookie = 'data=' + JSON.stringify(this.data) + '; expires=' + expireDate.toGMTString()
// 从 Cookies 中读取数据
var data = JSON.parse(getCookie('data'))
// 获取 Cookies 的值
function getCookie(name) {
var arr, reg = new RegExp('(^| )' + name + '=([^;]*)(;|$)')
if (arr = document.cookie.match(reg)) {
return unescape(arr[2])
} else {
return null
}
}
- 后端存储:除了在客户端存储数据之外,还可以通过后端存储来实现数据的持久化。常见的后端存储方案有 MySQL、MongoDB、Redis 等。在 Vue.js 中,可以通过 Ajax 请求将数据发送到后端存储中,从而实现数据的持久化。
以上是几种常见的数据持久化方案,在实际项目中可以根据具体的需求选择合适的方案来实现数据的持久化。
父子组件之间的通信
Vue 实现父子组件间的通信的方法有以下几种:
- Props:父组件通过 props 向子组件传递数据,子组件通过 this.$props 访问这些数据。如果需要从子组件向父组件传递数据,可以通过在子组件中 $emit 一个事件,然后在父组件中监听这个事件并处理。
- $emit 和 $on:子组件通过 this.$emit 触发一个自定义事件,父组件通过在子组件上使用 @自定义事件名 监听这个事件,并通过 $event 获取子组件传递的数据。这种方式适用于需要从子组件向父组件传递数据的场景。
- $parent 和 $children:子组件可以通过 this.$parent 获取其父组件实例,从而调用父组件的方法或访问其数据。父组件可以通过 this.$children 获取其所有子组件实例,从而调用子组件的方法或访问其数据。
- $refs:父组件通过在子组件上使用 ref 属性为子组件指定一个引用 ID,在父组件中使用 this.$refs[引用 ID] 访问子组件实例,从而调用子组件的方法或访问其数据。这种方式适用于需要直接访问子组件实例的场景,但需要注意的是,这种方式可能会导致组件之间的耦合度增加。
以上是常用的几种父子组件间通信的方法,具体使用时需要根据实际情况选择合适的方式。
- Props
父组件:
<template>
<div>
<child :message="message"></child>
</div>
</template>
<script>
import Child from './Child.vue'
export default {
components: {
Child
},
data() {
return {
message: 'Hello from Parent'
}
}
}
</script>
子组件:
<template>
<div>
{{ message }}
</div>
</template>
<script>
export default {
props: {
message: {
type: String,
required: true
}
}
}
</script>
- $emit 和 $on
父组件:
<template>
<div>
<child @message="handleMessage"></child>
</div>
</template>
<script>
import Child from './Child.vue'
export default {
components: {
Child
},
methods: {
handleMessage(data) {
console.log(data)
}
}
}
</script>
子组件:
<template>
<div>
<button @click="sendMessage">Send Message</button>
</div>
</template>
<script>
export default {
methods: {
sendMessage() {
this.$emit('message', 'Hello from Child')
}
}
}
</script>
- $parent 和 $children
父组件:
<template>
<div>
<child></child>
</div>
</template>
<script>
import Child from './Child.vue'
export default {
components: {
Child
},
methods: {
callChildMethod() {
this.$children[0].childMethod()
}
}
}
</script>
子组件:
<template>
<div>
Child Component
</div>
</template>
<script>
export default {
methods: {
childMethod() {
console.log('Called from Parent')
}
}
}
</script>
- $refs
父组件:
<template>
<div>
<child ref="childComponent"></child>
</div>
</template>
<script>
import Child from './Child.vue'
export default {
components: {
Child
},
mounted() {
this.$refs.childComponent.childMethod()
}
}
</script>
子组件:
<template>
<div>
Child Component
</div>
</template>
<script>
export default {
methods: {
childMethod() {
console.log('Called from Parent')
}
}
}
</script>
以上是这些方法的简单实现代码,需要根据实际需求进行更改。
标签:实战,Vue,自定义,js,指令,开发,组件,data From: https://www.cnblogs.com/LiJunLin1231/p/17173718.html