vue2项目构建
1.安装vue-cli
npm install -g @vue/cli
yarn global add @vue/cli
如需升级全局的 Vue CLI 包,请运行:
npm update -g @vue/cli
# 或者
yarn global upgrade --latest @vue/cli
2.使用vue-cli生成vue2项目
运行以下命令来创建一个新项目:
vue create vue2-demo
运行结果选择:
Default([vue 2]babel,eslint)
生成完毕之后
|-- vue2-demo
|-- .gitignore
|-- babel.config.js
|-- jsconfig.json
|-- package.json
|-- README.md
|-- vue.config.js
|-- yarn.lock
|-- public
| |-- favicon.ico
| |-- index.html
|-- src
|-- App.vue
|-- main.js
|-- assets
| |-- logo.png
|-- components
|-- HelloWorld.vue
至此vue2基础的项目生成
3.配置vue.config.js
vue.config.js文件
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
// 保存时检查语法
lintOnSave: false,
// 配置别名
configureWebpack: {
resolve: {
alias: {
"src": "@"
}
}
}
})
4.配置eslint
根目录新建 .eslintrc.js文件
yarn add eslint-plugin-vue eslint-plugin-html -D
编辑 .eslintrc.js
module.exports = {
root: true,
parserOptions: {
sourceType: 'module'
},
// required to lint *.vue files
plugins: [
'html'
],
extends: ['plugin:vue/essential', 'eslint:recommended'],
// add your custom rules here
'rules': {
"vue/multi-word-component-names": 'off',
'space-before-function-paren': 'off',
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
}
}
项目根目录新增 .eslintignore 文件,将不检查相关文件语法
vue.config.js
.eslintrc.js
babel.config.js
node_modules/
jsonconfig.json
5.配置jsconfig.json
jsconfig.json文件
{
"compilerOptions": {
"target": "es5",
"module": "esnext",
"baseUrl": "./",
"moduleResolution": "node",
// 跳转@路径的问题
"paths": {
"@/*": [
"src/*"
]
},
"lib": [
"esnext",
"dom",
"dom.iterable",
"scripthost"
],
// 解决prettier对于装饰器语法的警告
"experimentalDecorators": true,
// 解决.jsx文件无法快速跳转的问题
"jsx": "preserve"
},
//提高 IDE 性能
"exclude": [
"node_modules",
"dist",
"build"
]
}
6. 引入全局事件总线
在全局main.js中的beforeCreate生命周期新增Vue.prototype.$bus = this
new Vue({
render: h => h(App),
beforeCreate() {
Vue.prototype.$bus = this //安装全局事件总线,$bus就是当前应用的vm
},
}).$mount('#app')
全局事件总线的使用:
6.1.注册全局事件
使用this.$bus.$on(全局事件名称,事件回调函数)
methods(){
callbackFn(data){
console.log(data);
}
},
mounted() {
this.$bus.$on('topic1',this.callbackFn)
}
6.2.触发全局事件
使用this.$bus.$emit(全局事件名称,事件数据)
this.$bus.$emit('topic1',data)
7. 引入Vuex
安装Vuex3.0(匹配Vue2.0)
yarn add vuex@3
7.1 创建Vuex的store
在目录SRC中新建 src/store/index.js
|-- src
|-- main.js
|-- store
|-- index.js
store/index.js中添加count的options
import Vue from 'vue';
import Vuex from "vuex";
Vue.use(Vuex);
const countOptions = {
namespaced: true,
state: { countNum: 0 },
actions: {
addCount(context, data) {
context.commit('addCount', data);
},
multiCount(context, data) {
context.commit('multiCount', data);
},
subCount(context, data) {
context.commit('subCount', data);
},
divCount(context, data) {
context.commit('divCount', data);
},
},
mutations: {
addCount(state, data) {
state.countNum += data;
},
multiCount(state, data) {
state.countNum *= data;
},
subCount(state, data) {
state.countNum -= data;
},
divCount(state, data) {
state.countNum /= data;
},
},
getters: {
countNumMul10(state) {
return state.countNum * 10
}
}
}
const store = new Vuex.Store({
modules: {
count: countOptions
}
})
export default store;
7.2 全局引入store
在src/main.js中引入store,加入vue的options
import Vue from 'vue'
import App from './App.vue'
import store from './store';
Vue.config.productionTip = false
new Vue({
render: h => h(App),
store, // 配置vuex store
beforeCreate() {
Vue.prototype.$bus = this //安装全局事件总线,$bus就是当前应用的vm
},
}).$mount('#app')
至此vuex的store全部配置完毕,在组建中新增子属性this.$store。
7.3 使用vuex
在src/components/count.vue中使用vuex
<template>
<div>
<div>countNum:{{ countNum }}</div>
<div>countNum乘以10:{{ countNumMul10 }}</div>
<button @click="add(1)">add1</button>
<button @click="multi(2)">multi2</button>
<button @click="sub(1)">sub1</button>
<button @click="div(2)">div2</button>
</div>
</template>
<script>
import { mapState, mapActions, mapMutations, mapGetters } from "vuex";
export default {
name: "Count",
components: {},
mixins: [],
props: {},
data() {
return {};
},
computed: {
...mapState("count", ["countNum"]),
...mapGetters("count", ["countNumMul10"]),
},
watch: {},
mounted() {},
methods: {
...mapActions("count", { add: "addCount" }),
...mapMutations("count", { multi: "multiCount" }),
sub(count) {
this.$store.dispatch("count/subCount", count);
},
div(count) {
this.$store.commit("count/divCount", count);
},
},
};
</script>
<style lang="" scoped></style>
8. 引入vue-router
8.1 安装vue-router3.0
yarn add vue-router@3
8.2 main.js引入vue-router
src/main.js
import Vue from 'vue';
import router from './router';
import VueRouter from 'vue-router';
Vue.use(VueRouter);
new Vue({
router
}).$mount('#app')
8.3 编辑vue-router
8.3.1 新建基础的route
src/router/index.js
import VueRouter from 'vue-router';
import About from '@/pages/About';
import Login from '@/pages/Login';
const router = new VueRouter({
routes: [
{
path: '/admin',
name: "admin",
component: Admin,
meta: { loginRequired: true }
},
{
name: "login",
path: '/login',
component: Login
}
]
})
export default router;
8.3.2 在增加admin的子路由chidren
routes: [
{
path: '/admin',
name: "admin",
component: Admin,
// 如果需要登录才能进入的页面,需要加 meta:{loginRequired:true}
meta: { loginRequired: true },
children: [
{
name: 'home',
path: 'home',
component: Home,
meta: { loginRequired: true }
},
{
name: 'about',
path: 'about',
component: About,
meta: { loginRequired: true },
children: [
{
name: 'products',
path: "products",
component: Products,
meta: { loginRequired: true },
// 单独进入此路由时的前置守卫
beforeEnter(to, from, next) {
console.log(to, from, next);
next();
}
},
{
name: 'productDetail',
path: "productDetail",
component: ProductDetail,
// props通过返回函数传递
props($route) {
return { id: $route.query.id, name: $route.query.name }
},
meta: { loginRequired: true },
},
{
name: 'orderDetail',
path: "orderDetail/:id/:name",
component: OrderDetail,
props: true, // params映射为props传给组件
meta: { loginRequired: true },
},
{
name: 'order',
path: "order",
component: Order,
meta: { loginRequired: true },
}
]
}
]
},
{
name: "login",
path: '/login',
component: Login
}
]
8.3.3 增加全局导航守卫
// 全局路由前置守卫,更改路由之前调用
router.beforeEach((to, from, next) => {
console.log(to, from, next);
if (!to.meta.loginRequired) {
next();
}
// 判断是否登录,如果需要登录才能进入的页面,需要加 meta:{loginRequired:true}
if (!localStorage.getItem('userInfo')) {
// 无登录缓存,直接跳转登录页面
next({ name: "login" })
}
next();
})
// 全局路由后置守卫
router.afterEach((to, from) => {
console.log('afterEach', to, from);
})
8.3.4 增加组件内部导航守卫
beforeRouteEnter进入路由前守卫,beforeRouteLeave离开路由前守卫
export default {
name: "ProductDetail",
data() {
return {};
},
props: ["id", "name"],
methods: {},
computed: {},
mounted() {},
beforeRouteEnter(to, from, next) {
console.log("beforeRouteEnter", to, from, next);
next();
},
//离开守卫:通过路由规则,离开该组件时被调用
beforeRouteLeave(to, from, next) {
alert("暂未保存,是否要离开?");
console.log("beforeRouteEnter", to, from, next);
next();
},
};
8.4 router-link跳转
路由携带params参数时,若使用to的对象写法,则不能使用path配置项,必须使用name配置!
通过name与params跳转
localhost:8081/#/admin/about/orderDetail/001/001-order
<div v-for="order in orderList" :key="order.id">
<router-link
:to="{
name: 'orderDetail',
params: { id: order.id, name: order.name },
}"
>{{ order.name }}</router-link
>
</div>
通过name与query参数跳转:
localhost:8081/#/admin/about/productDetail?id=001&name=001product
<div v-for="product in products" :key="product.id">
<router-link
:to="{
name: 'productDetail',
query: { id: product.id, name: product.name },
}"
>{{ product.name }}</router-link
>
</div>
8.5 编程式路由跳转
//$router的两个API
this.$router.push({
name:'productDetail',
params:{
id:'001',
title:'001-product'
}
})
this.$router.replace({
name:'productDetail',
params:{
id:'001',
title:'001-product'
}
})
this.$router.forward() //前进
this.$router.back() //后退
this.$router.go() //可前进也可后退
8.6 路由缓存
<keep-alive include="Products">
<router-view></router-view>
</keep-alive>
两个新的生命周期钩子
作用:路由组件所独有的两个钩子,用于捕获路由组件的激活状态。
具体名字:
activated
路由组件被激活时触发。deactivated
路由组件失活时触发。
使用场景:列表页,点进详情页,缓存列表,保留用户搜索的结果与滑动的位置,提高用户体验
export default {
name: "Products",
data() {
return {
products: [
{ id: "001", name: "001product" },
{ id: "002", name: "002product" },
{ id: "003", name: "003product" },
],
};
},
methods: {},
computed: {},
mounted() {},
activated() {
console.log("products-activated");
},
deactivated() {
console.log("products-deactivated");
},
};
9. 使用less
9.1 安装less所需依赖
# 安装less以及less-loader
yarn add less less-loader@5 -D
# 安装 style-resources-loader vue-cli-plugin-style-resources-loader
yarn add style-resources-loader vue-cli-plugin-style-resources-loader -D
9.2 更改vue.config.js的配置
首选在vue.config.js中加入less配置
const { defineConfig } = require('@vue/cli-service')
+ const path = require('path'); //引入less
module.exports = defineConfig({
transpileDependencies: true,
// 保存时检查语法
lintOnSave: false,
// 配置别名
configureWebpack: {
resolve: {
alias: {
"src": "@"
}
}
},
+ pluginOptions: {
+ 'style-resources-loader': {
+ preProcessor: 'less',
+ patterns: [
+ path.join(__dirname, './src/assets/styles/variables.less'),
+ path.join(__dirname, './src/assets/styles/mixins.less')
+ ]
+ }
}
})
添加src/assets/styles/variables.less文件
@red-color: #F00;
添加src/assets/styles/mixins.less文件
9.3 组件中使用less变量
比如在组件中使用@red-color变量,style的lang='less'
<style scoped lang="less">
.red {
color: @red-color;
}
</style>