适合有点基础的人看,完整的移动端项目构建,包括路由组件、vuex管理、axios封装、登录持久化、权限等
重点不是业务,是项目的架构和思路
vue create vue-project // 创建项目
1. 配置scss
- 在assets文件夹中新增common.scss文件,配置一些公共样式
$color: #fff;
$background: #2a2a2a;
- 安装插件,自动加载scss资源,这样不用每个页面都 @import 导入文件
vue add style-resources-loader
// 后续选择:
y
scss
- 配置信息
// vue.config.js
const path = require('path')
module.exports = {
pluginOptions: {
"style-resources-loader": {
preProcessor: "scss", // 在每个页面自动引入scss变量
patterns: [path.resolve(__dirname, 'src/assets/common.scss')],
},
},
};
- 验证使用
// App.vue
<template>
<div id="app">hello</div>
</template>
<style lang="scss">
#app {
color: $color;
background: $background;
}
</style>
2. 移动端适配
- 安装插件
npm i postcss-plugin-px2rem lib-flexible
- 配置文件
// main.js
import 'lib-flexible'; // 对应设置根的字体
// App.vue
// width 根据vue.config.js中配置的写,37.5
<style lang="scss">
* {
padding: 0;
margin: 0;
}
#app {
color: $color;
background: $background;
width: 375px;
}
</style>
// vue.config.js 新增以下css部分代码 (配置完后,重启服务)
module.exports = {
css: {
loaderOptions: {
postcss: {
plugins: [
require("postcss-plugin-px2rem")({
rootValue: 37.5, // 表示设计稿的大小 375,750 设置 75rem
})
]
}
}
}
};
3. 安装vant 和 axios
npm i vant axios
// main.js
// 全局加载,实际开始最好按需加载
import Vant from 'vant';
import 'vant/lib/index.css';
Vue.use(Vant);
4. 配置路由
- 创建页面
// views 文件夹下新增:home/index.vue lesson/index.vue profile/index.vue
// 三个index.vue分别写一个简单的模板
<template>
<div>home</div>
</template>
- 配置路由
// router/index.js 新增以下代码
import Home from '@/views/home/index.vue'
// 自动生成路由 不建议路由自动配置,可配置性比较低(批注、钩子)
const routes = [
{
path: '/',
name: 'home',
component: Home
},
{
path: '/lesson',
name: 'lesson',
component: () => import('@/views/lesson/index.vue')
},
{
path: '/profile',
name: 'profile',
component: () => import('@/views/profile/index.vue')
}
];
// App.vue 文件添加 router-view
<div id="app">
<router-view />
</div>
访问:http://localhost:8080/lesson 验证
5. 处理加载状态
- 配置loading组件
// src/components/loading.vue
<template>
<van-loading type="spinner" />
</template>
- 处理加载
// src/utils/loadable.js
import LoadingComponent from '@/components/loading.vue'
const loadable = (asyncFunc) => {
let component = () => ({ // 最终切换的时候会采用这个组件
component: asyncFunc(),
loading: LoadingComponent, // 只是为了增加loading效果
})
return { // loadable 执行完毕后,返回一个组件
render(h) {
return h(component)
}
}
}
// 路由切换,异步加载的loading,处理白屏问题
export default loadable
- 路由设置
// src/router/index.js
import loadable from '@/utils/loadable';
{
path: '/lesson',
name: 'lesson',
component: loadable(() => import('@/views/lesson/index.vue'))
},
{
path: '/profile',
name: 'profile',
component: loadable(() => import('@/views/profile/index.vue'))
}
- 验证
把网络设置Fast 3G,切换页面,可以看到加载效果
6. 头部组件实现
- 头部组件
// src/views/home/home-header.vue 子组件
<template>
<div class="home-header">
<img src="@/assets/logo.png" alt="" />
<van-dropdown-menu>
<van-dropdown-item
:value="value"
:options="categories"
@change="change"
/>
</van-dropdown-menu>
</div>
</template>
<script>
export default {
props: {
value: Number,
},
data() {
return {
categories: [
{ text: "全部课程", value: -1 },
{ text: "node", value: 0 },
{ text: "react", value: 1 },
{ text: "vue", value: 2 },
],
};
},
methods: {
change(newValue) {
this.$emit("input", newValue);
},
},
};
</script>
<style lang="scss">
.home-header {
display: flex;
justify-content: space-between;
align-items: center;
height: 48px;
background: $background;
padding: 0 20px;
img {
width: 30px;
height: 30px;
}
}
</style>
- home组件
// src/views/home/index.vue 父组件
<template>
<div>
<!-- v-model 相当于 :value="value" @input="change" -->
<HomeHeader v-model="value"></HomeHeader>
</div>
</template>
<script>
import HomeHeader from "./home-header";
export default {
components: {
HomeHeader,
},
data() {
return {
value: -1, // 全部 -1, node 0, react 1, vue 2
};
},
};
</script>
7. vuex模块状态分类
- 模块分类
新增文件夹和文件
src
store
modules
home
actions.js
mutations.js
state.js
lesson
state.js
user
state.js
// src/store/modules/home/actions.js
const homeActions = {
}
export default homeActions
// src/store/modules/home/mutations.js
const homeMutations = {
}
export default homeMutations
// src/store/modules/home/state.js
const homeState = {
category: -1
}
export default homeState
- 模块集中处理导出
// src/store/modules/index.js
// webpack内置的
const files = require.context('.', true, /\.js$/) // 第一个参数表示目录,第二个参数表示是否搜索子目录,第三个匹配正则
const modules = {}
files.keys().forEach(key => {
const path = key.replace(/\.\/|\.js/g, '') // 去掉 ./ 和 .js
if (path === 'index') return // 自己不做任何处理
let [namespace, type] = path.split('/')
if (!modules[namespace]) {
modules[namespace] = {
namespaced: true // 都增加了命名空间
}
}
// {home: { "namespace": true, "actions": {}, "mutations": {}, "state": {}}, user: {}}
modules[namespace][type] = files(key).default // 获取文件导出的结果
})
export default modules
- 公共管理
// src/store/index.js
import Vue from "vue";
import Vuex from "vuex";
import modules from './modules/index.js'
Vue.use(Vuex);
const store = new Vuex.Store({
state: { // 公共的状态
},
mutations: {
},
actions: {},
modules: {
...modules
},
});
console.log(store.state) // 验证
export default store
8. vuex中的状态管理
- 问题:首页选择课程后,切换到我的课程页面,再返回,课程恢复到了默认状态。我们想返回时,依然是之前的状态。使用vuex管理状态
- 设置常量
// src/store/action-types.js
// 所有的名字都列在这里
export const SET_CATEGORY = 'SET_CATEGORY'
- 同步修改
// src/store/modules/home/mutations.js
import * as Types from '@/store/action-types'
const homeMutations = {
[Types.SET_CATEGORY](state, payload) { // 修改分类状态
state.category = payload
}
}
export default homeMutations
- 使用
// src/views/home/index.vue
<template>
<div>
<!-- v-model 相当于 :value="value" @input="change" -->
<HomeHeader v-model="currentCategory"></HomeHeader>
</div>
</template>
<script>
import HomeHeader from "./home-header.vue";
import { createNamespacedHelpers } from "vuex";
import * as Types from "@/store/action-types";
// 这里拿到的是 home 模块下的
let { mapState: mapHomeState, mapMutations } = createNamespacedHelpers("home");
export default {
methods: {
...mapMutations([Types.SET_CATEGORY]),
},
computed: {
...mapHomeState(["category"]), // 获取vuex中的状态绑定到当前的实例
currentCategory: {
get() {
// 取值
return this.category;
},
set(value) {
// 修改状态,默认会调用mutation更改状态
this[Types.SET_CATEGORY](value);
},
},
},
components: {
HomeHeader,
},
data() {
return {
value: -1, // 全部 -1, node 0, react 1, vue 2
};
},
};
</script>
- 验证
选择不同的课程,切换底部导航页面,返回时状态依然保留
- 验证