vue完整项目开发流程

您所在的位置:网站首页 课程开发流程图片 vue完整项目开发流程

vue完整项目开发流程

2024-07-16 02:07| 来源: 网络整理| 查看: 265

vue完整项目开发流程 1.创建项目,初始化项目2.配置多环境变量3.配置全局sass4.封装axios5.封装vuex6.按需引入我们需要的框架,(移动端:vant-ui)(后台管理:element-ui)7.路由封装8.封装组件9.代码优化:节流防抖,函数防抖,图片懒加载,keep-alive缓存不活动的组件10.打包上线 前言:

项目优化后最核心的是:之前是10mb,压缩好以后缩小到几百kb

1.创建项目,初始化项目 首先:开发这个项目我用的是vue脚手架3.0项目搭建好以后,我们需要初始化项目,安装需要的插件我们常用的有:axios(请求)、框架(后台管理系统安装element-ui,移动端安装vant),vuex-persistedstate(数据持久化插件),前期我们先安装这几个,后面根据项目的需要,在安装需要的插件 2.配置多环境变量

1.首先我们需要在根目录下创建三个.env的文件,根据环境的不同,配置不同的VUE_APP_ENV

.env.development.js文件:开发环境 NODE_ENV='development' # must start with VUE_APP_ VUE_APP_ENV = 'development' .env.staging文件:测试环境 NODE_ENV='staging' # must start with VUE_APP_ VUE_APP_ENV = 'staging' .env.production.js:文件:生产环境 NODE_ENV='production' # must start with VUE_APP_ VUE_APP_ENV = 'production'

2.在src根目录下面,创建一个config的文件,里面创建四个文件: env.development.js(定义开发环境)、env.production.js(定义生产环境)、env.staging.js(定义测试环境),index.js(根据环境的不同,引入不同配置,process.env.VUE_APP_ENV),config这个文件夹下面创建的env的文件,必须要跟上面三个.env的文件名一致

env.development.js文件:定义开发环境的公共路径(baseURL)、不同环境的(cdn加速)、不同环境图片的前缀路径 // 本地环境配置 module.exports = { title: 'backstage', baseUrl: 'http://120.53.31.103:84/api', // 项目地址 baseApi: 'https://test.xxx.com/api', // 本地api请求地址,注意:如果你使用了代理,请设置成'/' APPID: 'xxx', APPSECRET: 'xxx', $cdn: 'https://gimg2.baidu.com' } env.staging.js文件:定义测试环境的公共路径(baseURL)、不同环境的(cdn加速)、不同环境图片的前缀路径 // 测试环境 module.exports = { title: 'backstage', baseUrl: 'https://www.xxx.com/', // 正式项目地址 baseApi: 'https://www.xxx.com/api', // 正式api请求地址 APPID: 'xxx', APPSECRET: 'xxx', $cdn: 'https://www.sunniejs.cn/static' } env.production.js文件:定义开发环境的公共路径(baseURL)、不同环境的(cdn加速)、不同环境图片的前缀路径 // 生产环境 module.exports = { title: 'backstage', baseUrl: 'https://www.xxx.com/', // 正式项目地址 baseApi: 'https://www.xxx.com/api', // 正式api请求地址 APPID: 'xxx', APPSECRET: 'xxx', $cdn: 'https://www.sunniejs.cn/static' } 3.配置全局sass 首先需要安装两个插件 npm install --save-dev sass-loader npm install --save-dev node-sass

2.在assets这个文件夹下面创建一个css文件,在里面创建三个文件,index.scss文件,默认样式,清楚元素初始的样式,mixin.js文件:里面定义一些公用的代码块,variables.scss文件:里面定义全局样式变量,最后要把后面这两个文件引入到index.js这个文件里面

index.scss:定义默认样式,清楚元素初始的样式 @import './variables.scss'; @import './mixin.scss'; body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,form,fieldset,input,textarea,p,blockquote,th,td{margin:0;padding:0}html,body,#app{width:100vw;height:100vh}ul,ol{list-style:none}a{text-decoration:none;color:#333333}a,span{vertical-align:top}img{border:0;vertical-align:middle}input,button,text{vertical-align:top;outline:none;border:none}button{padding:0;background:none;cursor:pointer}button::-moz-focus-inner{padding:0}textarea{outline:none;border:none;resize:none}input,textarea{box-sizing:content-box;outline:none;background:0 0;font-family:"Microsoft YaHei"}input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#acacac}input:-moz-placeholder,textarea:-moz-placeholder{color:#acacac}input::-moz-placeholder,textarea::-moz-placeholder{color:#acacac}input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#acacac}table tr td,table{border-collapse:collapse}body{font-size:16px;color:#000;font-family:"Microsoft YaHei"}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:"";line-height:0}.clearfix:after{clear:both}.lf{float:left}.rt{float:right}.db{display:inline-block}.mt10{margin-top:10px}.mt15{margin-top:15px}.mt20{margin-top:20px}.mr5{margin-right:5px}.mr10{margin-right:10px}.mr15{margin-right:15px}.mr20{margin-right:20px}.centerWidth{max-width:7.5rem;margin:0 auto} mixin.scss:定义公共样式 // mixin // 清除浮动 @mixin clearfix { &:after { content: ""; display: table; clear: both; } } // 多行隐藏 @mixin textoverflow($clamp:1) { display: block; overflow: hidden; text-overflow: ellipsis; -o-text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: $clamp; /*! autoprefixer: ignore next */ -webkit-box-orient: vertical; } //flex box @mixin flexbox($jc:space-between, $ai:center, $fd:row, $fw:nowrap) { display: flex; display: -webkit-flex; flex: 1; justify-content: $jc; -webkit-justify-content: $jc; align-items: $ai; -webkit-align-items: $ai; flex-direction: $fd; -webkit-flex-direction: $fd; flex-wrap: $fw; -webkit-flex-wrap: $fw; } variables.scss:定义全局样式变量 // variables $background-color: #f8f8f8; 在根目录下创建一个vue.config.js文件,在抛出的对象里面写入以下代码 css: { extract: IS_PROD, // 是否将组件中的 CSS 提取至一个独立的 CSS 文件中 (而不是动态注入到 JavaScript 中的 inline 代码)。 sourceMap: false, loaderOptions: { scss: { // 向全局sass样式传入共享的全局变量, $src可以配置图片cdn前缀 // 详情: https://cli.vuejs.org/guide/css.html#passing-options-to-pre-processor-loaders prependData: ` @import "assets/css/mixin.scss"; @import "assets/css/variables.scss"; $cdn: "${defaultSettings.$cdn}"; ` } } },

4.最后把index.scss这个文件引入到main,js全局文件里面引入,然后就可以用啦

// 引入全局样式 import '@/assets/css/index.scss' 4.封装axios

好处:axios的封装和api接口的统一管理,其实主要目的就是在帮助我们简化代码和利于后期的更新维护。

第一步:首先在src创建一个api的文件夹,然后创建三个js文件, 在这里插入图片描述

api.js:里面主要统一管理接口

export default { // 头部 HEADER: "/menu/info", //登陆 LOGIN:"/adminUser/login", } http.js:里面主要封装的是核心文件,用params封装request,设置请求拦截和响应拦截,在请求拦截里面我们可以设置请求头,设置loading动画,在响应拦截里面我们可以根据后台返回的状态码,对不同的状态码做一些操作,最后设置不同的请求方式,我一般设置的请求方式有get、post、put,等需要其它的时候,在封装也可以 import axios from 'axios'; import { Message, Loading } from 'element-ui'; import _ from 'lodash'; import { baseUrl } from '@/config'; import store from '@/store' import QS from 'qs' console.log(baseUrl) const request = axios.create({ baseURL: baseUrl, //设置请求的base url timeout: 40000 //超时时长 }); //loading对象 let loading; //当前正在请求的数量 let needLoadingRequestCount = 0; //显示loading function showLoading(target) { // 后面这个判断很重要,因为关闭时加了抖动,此时loading对象可能还存在, // 但needLoadingRequestCount已经变成0.避免这种情况下会重新创建个loading if (needLoadingRequestCount === 0 && !loading) { loading = Loading.service({ lock: true, text: 'Loading', spinner: 'el-icon-loading', background: 'rgba(0, 0, 0, 0.7)', target: target || "body" }); } needLoadingRequestCount++; } //隐藏loading function hideLoading() { needLoadingRequestCount--; needLoadingRequestCount = Math.max(needLoadingRequestCount, 0); //做个保护 if (needLoadingRequestCount === 0) { //关闭loading toHideLoading(); } } //防抖:将 300ms 间隔内的关闭 loading 便合并为一次。防止连续请求时, loading闪烁的问题。 let toHideLoading = _.debounce(() => { loading.close(); }, 300); //添加请求拦截器 request.interceptors.request.use(config => { //判断当前请求是否设置了不显示Loading if (config.headers.showLoading !== false) { showLoading(config.headers.loadingTarget); } if (store.state.token || localStorage.getItem('token')) { const token = store.state.token || localStorage.getItem('token'); token && (config.headers.authorization = 'Bearer '+token); } return config; }, err => { //判断当前请求是否设置了不显示Loading if (config.headers.showLoading !== false) { hideLoading(); } Message.error('请求超时!'); return Promise.resolve(err); }); //响应拦截器 request.interceptors.response.use( response => { //判断当前请求是否设置了不显示Loading(不显示自然无需隐藏) if (response.config.headers.showLoading !== false) { hideLoading(); } if (response.status == 200) { return Promise.resolve(response); } else { Message.error(response.message); return Promise.reject(response); } }, error => { //判断当前请求是否设置了不显示Loading(不显示自然无需隐藏) if (error.config.headers.showLoading !== false) { hideLoading(); } if (error.response && error.response.data && error.response.data.message) { var jsonObj = JSON.parse(error.response.data.message); Message.error(jsonObj.message); } else { Message.error(error.message); } return Promise.reject(error); } ); export default { /** * get方法,对应get请求 * @param {String} url [请求的url地址] * @param {Object} params [请求时携带的参数] */ get(url, data) { let params = data || '' return new Promise((resolve, reject) => { request .get(url, params) .then(res => { resolve(res.data) }) .catch(err => { reject(err.data) }) }) }, /** * post方法,对应post请求 * @param {String} url [请求的url地址] * @param {Object} params [请求时携带的参数] */ post(url, data) { let params = data || '' return new Promise((resolve, reject) => { request .post(url, QS.stringify(params)) .then(res => { resolve(res.data) }) .catch(err => { reject(err.data) }) }) }, /** * upload方法,对应upload请求 * @param {String} url [请求的url地址] * @param {Object} params [请求时携带的参数] */ upload(url, data) { let params = data || '' return new Promise((resolve, reject) => { request .upload(url, QS.stringify(params)) .then(res => { resolve(res.data) }) .catch(err => { reject(err.data) }) }) }, /** * download方法,对应download请求 * @param {String} url [请求的url地址] * @param {Object} params [请求时携带的参数] */ download(url, data) { let params = data || '' return new Promise((resolve, reject) => { request .download(url, QS.stringify(params)) .then(res => { resolve(res.data) }) .catch(err => { reject(err.data) }) }) }, /** * put方法,对应put请求 * @param {String} url [请求的url地址] * @param {Object} params [请求时携带的参数] */ put(url, data) { let params = data || '' return new Promise((resolve, reject) => { request .put(url, QS.stringify(params)) .then(res => { resolve(res.data) }) .catch(err => { reject(err.data) }) }) }, /** * delete方法,对应delete请求 * @param {String} url [请求的url地址] * @param {Object} params [请求时携带的参数] */ delete(url, data) { let params = data || '' return new Promise((resolve, reject) => { request .delete(url, QS.stringify(params)) .then(res => { resolve(res.data) }) .catch(err => { reject(err.data) }) }) } } index.js:主要定义方法,一个接口对应一个方法,要把前面封装号的两个文件引入到这个文件里面,然后引入到main.js全局文件里面,注册全局 import api from "./api"; // 导入接口域名列表 import http from "./http"; // 导入http中创建的axios实例 export default { install(Vue) { Vue.prototype.$http = this; }, //头部接口 HEADER(params = "") { return http.post(api.HEADER, params); }, //登陆接口 LOGIN(params) { return http.post(api.LOGIN, params); }, STUDENT(params) { return http.get( api.STUDENT + `?page=${params.page_num}&limit=${params.page_size}&status=${params.status}&nickname=${params.nickname}&mobile=${params.mobile}&` ); }, //详情接口 DETAIL(params) { return http.get(api.DETAIL + `/${params}?`); }, //禁用接口 FORBIDDEN(params) { return http.put(api.FORBIDDEN + `/${params}`); }, DELETE(params) { return http.delete(api.DELETE + `/${params}`); }, //省市区接口 PROVINCE(id) { return http.get(api.PROVINCE + `/${id}`); }, //上传头像接口 IMG(file) { return http.post(api.IMG ,file); }, }; 5.封装vuex

前言:什么是vuex

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式,相当于是一个仓库,存放公共数据的,任何组件都可以使用存放在仓库里面的数据

1.vuex由五大部分组成

state:定义数据,使用方法是通过:this.$store.state.xxx(方法名)actions:可以包含异步操作,使用方法是通过: this.$store.dispatch.xxx(方法名)mutations:唯一可以修改state数据的场所,使用方法是通过:this.$store.commit.xxx(方法名)getters:类似于vue组件中的计算属性,对state数据进行计算(会被缓存),使用方法是:this.$store.getters.xxx(方法名)modules:模块化管理store(仓库),每个模块拥有自己的 state、mutation、action、getter

2.下面说下封装vuex的核心

第一步:在src文件夹下面创建store的文件夹,然后在这个文件夹下面创建四个js文件state:定义公共数据actions:操作异步的数据mutations:操作同步的数据,也是唯一一个可以直接改变state里面定义的数据getters:类似于vue组件中的计算属性,对state数据进行计算(会被缓存)index:把前面封装好的文件都引入到这个文件里面,然后抛出 import Vue from 'vue' import Vuex from 'vuex' import state from './state'; import mutations from './mutations'; import actions from './actions'; import vuexPersist from "vuex-persist"; Vue.use(Vuex) export default new Vuex.Store({ state, mutations, actions, plugins: [ new vuexPersist({ storage: window.localStorage, }).plugin, ], })

下面说下封装vuex的好处和具体的思路

我们在用vue脚手架3.0创建项目的时候,他会自动帮我们在src这个文件夹下面生成一个store文件夹,下面有一个index.js这个文件,index.js这个文件里面有5个属性,就是我们用vuex的时候,所用到的5个属性,把这5个属性放在同一个文件里面,适合开发中小型项目的时候使用,因为需要公用的数据不多,写在一个文件里面就可以,但是开发一个中大型项目的话,我们需要在vuex里面定义的数据比较多,所以我们就把需要的5个属性拆分出来,拆分成单独的文件,这样能在以后项目的维护,或者修改的时候比较方便,每个文件定义不同的数据,下面我们来分析一下

在这里插入图片描述

state:可以把项目中需要定义在state里面的数据,都定义在这个文件里面action:他是一个异步的操作,把项目中异步的请求全部放在这个文件里面,如果要修改state里面定义的数据,必须要通过commit来调用mutations里面的方法,才能修改state里面的数据,不能直接修改,在组件里面需要action里面的数据,可以通过tthis.$store.dispatch+需要调用的方法名来获取mutations:他是一个同步的操作,也是唯一一个可以直接修改state里面定义的数据,可以把项目中同步的数据放在这个文件里面,在组件中需要通过this.$store.commit+需要调用的方法名来获取getters:计算属性,可以把项目中需要计算的数据放在这个文件里面,统一管理,在组建中通过this.$store.getters+调用的方法名可以获取到数据 6.按需引入我们需要的框架,(移动端:vant-ui)(后台管理:element-ui)

-vant-ui:移动端

安装指令

npm i babel-plugin-import -D

在babel.config.js 设置 // 对于使用 babel7 的用户,可以在 babel.config.js 中配置 const plugins = [ [ 'import', { libraryName: 'vant', libraryDirectory: 'es', style: true }, 'vant' ] ] module.exports = { presets: [['@vue/cli-plugin-babel/preset', { useBuiltIns: 'usage', corejs: 3 }]], plugins } 在src文件夹下面创建一个plugins文件夹,然后下面创建一个index.js文件,里面统一管理我们需要用的组件 // 按需全局引入 vant组件 import Vue from 'vue' import { Button, List, Cell, Tabbar, TabbarItem } from 'vant' Vue.use(Button) Vue.use(Cell) Vue.use(List) Vue.use(Tabbar).use(TabbarItem) 然后在main.js全局文件里面引入,抛出,在全局就可以用啦 import './plugins/vant.js'

后台管理系统

注意:必须要在搭建项目以后,别的什么都不操作,都还没有操作的情况下,才能使用,否则安装完别的依赖,在安装下面这个指令的话,就用不了

vue add element

在src文件夹下面创建一个plugins文件夹,然后下面创建一个index.js文件,里面统一管理我们需要用的组件 import Vue from 'vue' import { Pagination, Dialog, Autocomplete, Dropdown, DropdownMenu, DropdownItem, Menu, Submenu, MenuItem, MenuItemGroup, Input, InputNumber, Radio, RadioGroup, RadioButton, Checkbox, CheckboxButton, CheckboxGroup, Switch, Select, Option, OptionGroup, Button, ButtonGroup, Table, TableColumn, DatePicker, TimeSelect, TimePicker, Popover, Tooltip, Breadcrumb, BreadcrumbItem, Form, FormItem, Tabs, TabPane, Tag, Tree, Alert, Slider, Icon, Row, Col, Upload, Progress, Badge, Card, Rate, Steps, Step, Carousel, CarouselItem, Collapse, CollapseItem, Cascader, ColorPicker, Transfer, Container, Header, Aside, Main, Footer, Loading, MessageBox, Message, Notification } from 'element-ui' Vue.use(Pagination) Vue.use(Dialog) Vue.use(Autocomplete) Vue.use(Dropdown) Vue.use(DropdownMenu) Vue.use(DropdownItem) Vue.use(Menu) Vue.use(Submenu) Vue.use(MenuItem) Vue.use(MenuItemGroup) Vue.use(Input) Vue.use(InputNumber) Vue.use(Radio) Vue.use(RadioGroup) Vue.use(RadioButton) Vue.use(Checkbox) Vue.use(CheckboxButton) Vue.use(CheckboxGroup) Vue.use(Switch) Vue.use(Select) Vue.use(Option) Vue.use(OptionGroup) Vue.use(Button) Vue.use(ButtonGroup) Vue.use(Table) Vue.use(TableColumn) Vue.use(DatePicker) Vue.use(TimeSelect) Vue.use(TimePicker) Vue.use(Popover) Vue.use(Tooltip) Vue.use(Breadcrumb) Vue.use(BreadcrumbItem) Vue.use(Form) Vue.use(FormItem) Vue.use(Tabs) Vue.use(TabPane) Vue.use(Tag) Vue.use(Tree) Vue.use(Alert) Vue.use(Slider) Vue.use(Icon) Vue.use(Row) Vue.use(Col) Vue.use(Upload) Vue.use(Progress) Vue.use(Badge) Vue.use(Card) Vue.use(Rate) Vue.use(Steps) Vue.use(Step) Vue.use(Carousel) Vue.use(CarouselItem) Vue.use(Collapse) Vue.use(CollapseItem) Vue.use(Cascader) Vue.use(ColorPicker) Vue.use(Container) Vue.use(Header) Vue.use(Aside) Vue.use(Main) Vue.use(Footer) Vue.use(Loading.directive) Vue.prototype.$loading = Loading.service Vue.prototype.$msgbox = MessageBox Vue.prototype.$alert = MessageBox.alert Vue.prototype.$confirm = MessageBox.confirm Vue.prototype.$prompt = MessageBox.prompt Vue.prototype.$notify = Notification Vue.prototype.$message = Message 最后也是在main.js全局文件里面引入,然后抛出就可以啦 import './plugins/element.js' 7.路由封装

前言:大家都知道,我们在搭建好项目以后,src文件夹下面会生成一个router这个文件夹,然后下面有一个index.js这个文件,这个里面就是我们做项目需要放路由的地方,如果我们的项目比较大,跳转的页面比较多的话,把全部的路由都放在这一个文件里面,后期优化不好优化,在做项目的时候需要找路由的时候也不好找,或者说在后期我们需要改路由的时候也不好改,所以我们就选择路由封装是最好不过的啦。。。注意:如果项目比较小,跳转的页面不是很多的情况下,就没必要封装路由

下面说下路由封装的思路,这个很简单,大家一看就会

我一般在做项目时候,遇到跳转页面多的时候呢,我会把路由分成几个文件来封装,比如现在我做的这个后台管理系统,有10个页面,每个页面里面肯定有很多需要跳转的页面,这时候我会在router这个文件夹下面创建10个文件,然后每个文件对应一个页面,比如现在首页的这个页面,就在router这个文件夹下面创建一个home.js文件,然后把首页需要跳转的的路由全部写在这个文件里面,然后把他引入到index.js这个文件里面就可以啦,这样呢,在做项目,或者以后优化的时候就比较好找,如果以后我们要优化项目,需要优化首页的时候,在我们需要优化首页这个页面路由的时候,我们就可以去home.js这个文件里面去找就可以啦 8.封装组件

前言:大家都知道,vue项目都是单页面,都是组件拼接起来的,如果说我们在做中大型项目的时候,页面比较多,如果我们把这些页面都写在一个文件里面,就比较麻烦,修改的时候、找的时候、或者在优化项目的时候找起来比较麻烦,所以我们就把页面分成一个一个的组件,封装起来,然后引入到渲染的页面,这样的话,在我们写项目、修改。以后优化项目的时候,就比较方便

封装组件的话分为两种

一个是页面组件的封装一个是公共组件的封装 9.代码优化:节流防抖,函数防抖,图片懒加载,keep-alive缓存不活动的组件 10.打包上线


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3