本篇为个人总结,有不对的地方请指正
一、创建项目
目前有两种常见的创建方式
1.控制台创建项目
//vue-cli 2.x+ 版本
vue init webpack '文件名'
//vue-cli 3.x+ 版本
vue create '文件名'
可能会出现以下问题
输入命令后出现错误:原因是脚手架在创建的时候从github里下载webpack失败了
解决方法:
采用离线创建项目:在github下载 vuejs-templates/ webpack 包,解压到用户目录。比如C:\Users\Administrator\.vue-templates\webpack
,没有.vue-templates\webpack
文件就自行创建
命令加上--offline
表示离线创建
vue init webpack '文件名' --offline
具体步骤参考:https://blog.csdn.net/qq_45731083/article/details/114921816
2.可视化创建项目
vue ui
3.vue-cli脚手架的区别
创建命令不一
//vue-cli 2.x+ 版本
vue init webpack '文件名'
//vue-cli 3.x+ 版本
vue create '文件名'
文件目录不一
vue-cli 2.x+ 版本:
vue-cli 3.x+ 版本:
还有很多区别,不做详细讲解…
二、初始化与运行
安装依赖
创建或下拉git
的项目第一件事就是安装依赖,以防项目跑不起来
新建终端,输入以下命令
npm install
命令
运行之前先要看package.json
文件里的scripts
运行命令是什么
以vue-lic 3.x+
为例:
在script里的有serve和build两个命令
- serve:运行命令
- build:打包命令
运行项目
npm run serve
// vue-lic 2.x+
// npm run dev 或 npm start
三、文件目录解析
以vue-cli2.x +为例,以下就项目文件夹中的各文件的作用进行介绍:
├── build/ # Webpack 配置目录
├── dist/ # build 生成的生产环境下的项目
├── config/ # Vue基本配置文件,可以设置监听端口,打包输出等
├── node_modules/ # 依赖包,通常执行npm i会生成
├── src/ # 源码目录(开发的项目文件都在此文件中写)
│ ├── assets/ # 放置需要经由 Webpack 处理的静态文件,通常为样式类文件,如css,sass以及一些外部的js
│ ├── components/ # 公共组件
│ ├── filters/ # 过滤器
│ ├── store/ # 状态管理
│ ├── routes/ # 路由,此处配置项目路由
│ ├── services/ # 服务(统一管理 XHR 请求)
│ ├── utils/ # 工具类
│ ├── views/ # 路由页面组件
│ ├── App.vue # 根组件
│ ├── main.js # 入口文件
├── index.html # 主页,打开网页后最先访问的页面
├── static/ # 放置无需经由 Webpack 处理的静态文件,通常放置图片类资源
├── .babelrc # Babel 转码配置
├── .editorconfig # 代码格式
├── .eslintignore # (配置)ESLint 检查中需忽略的文件(夹)
├── .eslintrc # ESLint 配置
├── .gitignore # (配置)在上传中需被 Git 忽略的文件(夹)
├── package.json # 本项目的配置信息,启动方式
├── package-lock.json # 记录当前状态下实际安装的各个npm package的具体来源和版本号
├── README.md # 项目说明(很重要,便于其他人看懂)
四、配置常见插件与工具类文件
vue项目常用三大插件:vuex、router、axios
vuex配置
安装
//具体安装命令看官方文档
npm install vuex
创建一个store目录,目录里创建一个index.js文件
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
//共享数据
},
getters: {
},
mutations: {
//同步
//通过commit调用
},
actions: {
//异步
//通过dispatch调用
},
modules: {
//其他vuex模块
}
})
实际项目中的基础配置:
import Vue from 'vue'
import Vuex from 'vuex' //vuex文件
import { queryByToken } from '@/api/user' //接口文件
import { Message } from 'element-ui' //element-ui
import route from '@/router/index' //route文件
Vue.use(Vuex)
export default new Vuex.Store({
state: {
loginInfo: { //用户登录信息
token: sessionStorage.getItem('token') ?? ''
},
},
getters: {
},
mutations: {
setLoginInfo(state, data) {
state.loginInfo = data
// console.log(data)
if (data.token) window.sessionStorage.setItem("token", data.token)
else state.loginInfo.token = window.sessionStorage.getItem("token")
},
},
actions: {
getLoginInfo(context) {
// 发送token验证请求
function toLogin(str = '') {
Message({ type: 'error', message: str || '登录超时' })
sessionStorage.removeItem("token")
route.push({name:'login'})
}
queryByToken().then(res => {
if (res.code == 200) context.commit('setLoginInfo', res.data)
else toLogin(res.msg)
}).catch(err => toLogin(err.response.data.msg || err.message))
},
},
modules: {
}
})
配置完vuex文件需要全局使用:
main.js文件中
import Vue from 'vue'
import App from './App.vue'
import router from './router' //引入store
import store from './store' //引入vuex
Vue.config.productionTip = false
import 'element-ui/lib/theme-chalk/index.css' //element-ui 样式
import ElementUI from 'element-ui' //element-ui
Vue.use(ElementUI) //全局使用
new Vue({
router, //全局使用
store, //全局使用
render: h => h(App)
}).$mount('#app')
router配置
安装
//具体安装命令看官方文档
npm install vue-router
创建一个router目录,目录里创建一个index.js文件
import Vue from 'vue'
import VueRouter from 'vue-router'
import HomeView from '../views/HomeView.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'home',
component: HomeView
},
{
path: '/about',
name: 'about',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue')
}
]
const router = new VueRouter({
routes
})
export default router
实际项目中的基础配置:
import Vue from 'vue'
import VueRouter from 'vue-router'
import store from '../store/index'
import { Message } from 'element-ui'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'login',
component: () => import('@/views/Login.vue')
},
{
path: '/home',
component: () => import('@/views/HomeView.vue'),
//局部路由拦截
beforeEnter: (to, from, next) => {
if (!store.state.loginInfo.token) {
Message({
type: 'warning',
message: '请先登录'
})
next({ name: 'login' })
} else
next()
},
children: []
}
]
const router = new VueRouter({
routes
})
//如果在局部路由拦截了就不要打开以下代码
//全局路由拦截
//router.beforeEach((to, from, next) => {
// if (!store.state.loginInfo.token) {
// Message({
// type: 'warning',
// message: '请先登录'
// })
// next({ name: 'login' })
// } else
// next()
//})
export default router
配置完router文件需要全局使用:
main.js文件中
import Vue from 'vue'
import App from './App.vue'
import router from './router' //引入store
import store from './store' //引入vuex
Vue.config.productionTip = false
import 'element-ui/lib/theme-chalk/index.css' //element-ui 样式
import ElementUI from 'element-ui' //element-ui
Vue.use(ElementUI) //全局使用
new Vue({
router, //全局使用
store, //全局使用
render: h => h(App)
}).$mount('#app')
axios配置
安装
//具体安装命令看官方文档
npm install axios
实际项目中的基础配置:
在src下创建api目录,创建axios.js文件
import axios from 'axios'
import store from '@/store/index'
axios.defaults.timeout = 1000 * 60 //最迟响应事件 60s
//请求拦截
axios.interceptors.request.use((config) => {
//把token放入请求头中
const token = store.state.token || window.sessionStorage.getItem('token') || ''
if (token) {
config.headers.token = token
return config
}
return config
})
//响应拦截
axios.interceptors.response.use((response) => {
if (response.status === 200) {
return Promise.resolve(response.data)
}
else {
return Promise.reject(response)
}
})
export default axios
使用
写接口:
在axios同级目录下,创建user.js文件
import axios from "./axios"; //引号里是刚刚配置的axios.js地址
import urls from '@/utils/urls' //基础地址,后续出详解
export const login = (data) => {
return axios.post(urls.baseUrl + '/ty-user/login', data)
}
使用接口:
import { login } from "@/api/user";
export defefault{
...,
methods:{
onSubmit(){
login(this.form).then((res) => {
res.data = res.data || {};
if (res.code == 200) {
let data = {
...res.data,
token: res.token,
};
//把token和usename保存到vuex
this.$store.commit("setLoginInfo", data);
//跳转路由
this.$router.push("/home");
this.$message({ message: '登录成功', type: "success", });
} else {
this.$message({ message: res.msg, type: "error", });
}
});
}
}
}
工具类文件
一般项目中会有一个工具类,是全局多次使用的,可以配置全局使用的。
├── src/ # 源码目录(开发的项目文件都在此文件中写)
│ ├── utils/ # 工具类
│ │ /──mixins/ # 混合文件
│ │ /──aixos.js # 网络请求拦截
│ │ /──urls.js # 路径配置(开发路径/打包路径等),用于接口/图片路径等
│ │ /──utils.js # 工具类
│ │ /──utils/ # 工具类文件
│ │ /──utils/13123.js # 个人工具类
│ │ /──utils/43242.js # 个人工具类
urls路径配置
在utils文件下,创建urls.js文件
// const location = window.location.protocol + '//' + window.location.host // 打包路径
const location='/api' //虚拟机 开发路径
const baseUrl = location + '/directory' //虚拟机 接口路径
const resources = location + '/upload/' // 资源路径
export default {
baseUrl, resources
}
在main.js文件下全局声明:
import urls from './utils/urls'
Vue.prototype.$urls = urls
使用:
//图片拼接
<img src="imgUrl?$urls.resources+imgUrl:'../../default.png'" alt="图片">
注意:全局使用仅包括在vue文件下,其他js文件中需单独引入后使用
utils工具类配置
在utils文件下,创建utils.js
文件
1.多人开发下的配置
function gutils(){
return this
}
const utils=new gutils()
export default utils
//妹子1的接口
import kUtils from "./utils/k_utils"
kUtils(utils)
//妹子2的接口
import tUtils from "./utils/t_utils"
tUtils(utils)
在utils文件下,创建utils/k_utils.js
文件
import urls from "../urls"
const kUtils = (utils) => {
// 打印
utils.printSomething = function (str) {
console.log(str)
return str
}
}
export default kUtils
同理可得utils/t_utils.js
文件。
在main.js文件下全局声明:
//全局方法
import gfn from "./utils/utils.js"
Vue.prototype.$gfn = gfn
使用:
export default{
...,
methods:{
toPrint(){
this.$gfn.printSomething('123')
}
}
}
2.单人开发配置
export default {
printSomething (str) {
console.log(str)
return str
},
}
在main.js文件下全局声明:
//全局方法
import utils from './utils/utils'
Vue.prototype.$utils = utils
使用:
export default{
...,
methods:{
toPrint(){
this.$urls.printSomething('123')
}
}
}
注意
- 不管是安装什么插件,需要注意当前
vue-cli
版本是否能支持,若不支持可考虑插件降级。 - 全局使用仅包括在vue文件下,其他js文件中需单独引入后使用
五、打包与部署
项目完成后进行打包部署前,需要修改url和webpck文件。
打包前的配置
1.修改url
在url文件中修改基础路径改为打包路径:
- 开发时路径
// const location = window.location.protocol + '//' + window.location.host // 打包路径
const location='/api' //虚拟机 开发路径
const baseUrl = location + '/directory' //虚拟机 接口路径
const resources = location + '/upload/' // 资源路径
export default {
baseUrl, resources
}
- 打包路径
const location = window.location.protocol + '//' + window.location.host // 打包路径
// const location='/api' //虚拟机 开发路径
const baseUrl = location + '/directory' //虚拟机 接口路径
const resources = location + '/upload/' // 资源路径
export default {
baseUrl, resources
}
2.webpack添加公共路径
在vue.config.js中添加publicPath: process.env.NODE_ENV === 'production' ? './' : '/'
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
publicPath: process.env.NODE_ENV === 'production' ? './' : '/',
},
devServer: {
//代理
proxy: {
'^/api': {
target: 'http://192.168.5.6',
ws: true,
changeOrigin: true,
pathRewrite: { // 重写路径: 去掉路径中开头的'/api'
'^/api': ''
},
},
}
}
})
打包
npm run build //命令不固定,根据package.json中的打包命令进行打包
打包后在根目录下生产dist文件,把文件放在虚拟机的Nginx的html下。
六、其他配置
代理
在vue.config.js中添加devServer
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
publicPath: process.env.NODE_ENV === 'production' ? './' : '/',
},
devServer: {
//代理
proxy: {
'^/api': {
target: 'http://192.168.5.6',
ws: true,
changeOrigin: true,
pathRewrite: { // 重写路径: 去掉路径中开头的'/api'
'^/api': ''
},
},
}
}
})
Vuex刷新页面数据丢失
在App.vue的created周期中:
//刷新后获取本地缓存中的数据
if (window.sessionStorage.getItem("list") ) {
this.$store.replaceState(Object.assign({},this.$store.state,JSON.parse(window.sessionStorage.getItem("list"))))
}
//监听刷新前beforeunload事件,把数据存储到本地缓存
window.addEventListener("beforeunload",()=>{
window.sessionStorage.setItem("list",JSON.stringify(this.$store.state))
})
可参考资料:https://blog.csdn.net/qq_51441159/article/details/128047610
页面刷新的token验证及用户信息存储
在App.vue的watch中:
watch: {
$route: {
handler(newV) {
let routerList = ["/login"];
if (routerList.indexOf(newV.path) == -1) {
this.init();
}
},
deep: true,
},
}
methods中:
methods: {
init() {
let token = window.sessionStorage.getItem("token");
if (token) {
this.$store.dispatch("getLoginInfo");
}
},
},
在vuex中:
import Vue from 'vue'
import Vuex from 'vuex'
import { queryByToken } from '@/api/user'
import { Message } from 'element-ui'
import route from '@/router/index'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
loginInfo: {
token: sessionStorage.getItem('token') ?? ''
},
},
getters: {
},
mutations: {
//个人信息存储到本地
setLoginInfo(state, data) {
state.loginInfo = data
if (data.token) window.sessionStorage.setItem("token", data.token)
else state.loginInfo.token = window.sessionStorage.getItem("token")
},
},
actions: {
// 发送token验证请求,获取个人信息
getLoginInfo(context) {
function toLogin(str = '') {
Message({ type: 'error', message: str || '登录超时' })
sessionStorage.removeItem("token")
route.push({name:'login'})
}
queryByToken().then(res => {
if (res.code == 200) context.commit('setLoginInfo', res.data)
else toLogin(res.msg)
}).catch(err => toLogin(err.response.data.msg || err.message))
},
},
modules: {
}
})