基于yg_mobile开发的一款简单的h5商城页面
yg_mobile 自开发vue移动端的启动项目源码
yg_mobile项目的gitee地址:https://gitee.com/yango520/yg_mobile
yg_mobile方便往后自己开发vue移动端项目时候,不需要再做其他配置和造轮子等复杂工作
特别声明:UI是参考yoyo的设计,仅用于学习,非商业用途
项目gitee地址:https://gitee.com/yango520/yg_shop
YG商城预览地址: 传送门
查看预览图
项目创建环境:
- vue:v3.10.0
- node:v10.11.0
- npm: 6.14.8
项目创建过程:(阐述)
vue create yg_mobile
- Manually select featues 选择手动配置
- 选择所需要的依赖(按空格选择) Babel, Router, Vuex, CSS Pre-processors, Linter / Formatter
- Use history mode for router? 是否选择history模式(另外一个hash模式),这里选择是Y
- 选择预处理器,Sass/SCSS(with node-sass)
- 选择代码校验,ESLint+Prettier
- 选择校验时间,Lint on save, 保存就校验
- 选择配置文件,In package.json
- 最后是否选择以上配置为以后项目开发默认配置,这里可以选择否N
文档
1.需要安装的依赖
依赖库 | 说明 |
---|---|
Router | 路由配置 |
Vuex | 状态管理 |
SCSS | css预处理 |
axios | 网络请求 |
postcss-px2rem | 移动端适配rem |
lib-flexible | rem适配跟上面一起用 |
Vant | 移动端UI库:官网地址 |
fastclick | 处理移动端click事件300毫秒延迟 |
2. 创建配置vue配置文件
在根目录新建一个vue.config.js
的文件,用来配置vue的各项配置内容
module.exports = {
}
3. 配置服务器/代理相关配置
在vue.config.js里面添加
/**
* 服务器代理 相关配置
* port:启动端口号
* host:设置反问地址,默认'localhost','0.0.0.0'设置为允许ip访问
* open:浏览器自启动
* proxy:配置接口代理
*/
devServer: {
port: 8085,
host: '0.0.0.0',
open: true,
proxy: {
'/apis': {
target: '',
changeOrigin: true,
pathRewrite: {
'^/apis': '这里为接口api地址'
}
}
}
}
}
4. 配置 postcss-px2rem 和 lib-flexible 移动端适配rem
在vue.config.js中配置
/* css转换设置 */
css: {
loaderOptions: {
css: {},
postcss: {
plugins: [
require('postcss-px2rem')({
remUnit: 37.5, //这里将屏幕分为10分(10rem),也就是10*37.5=375px就等于屏幕100%,如果不需要被转化,在style中直接写PX大写
})
]
}
}
},
然后在main.js中注册引用
//移动端布局
import 'lib-flexible'
5. 全局引用vant UI库
在main.js中引入
//vant 库引用
import Vant from 'vant';
import 'vant/lib/index.css';
Vue.use(Vant);
6.处理移动端click事件300毫秒延迟问题
在main.js中引用
/* 300毫秒点击延迟问题的解决方案(尤其是移动端)优化用户体验 */
import fastClick from 'fastclick'
fastClick.attach(document.body)
7. 配置静态资源别名
在vue.config.js中配置。
Vue CLI 内部的 webpack 配置是通过 webpack-chain (链式操作)维护的。这个库提供了一个 webpack 原始配置的上层抽象,使其可以定义具名的 loader 规则和具名插件,并有机会在后期进入这些规则并对它们的选项进行修改。官网文档
//在输出外部
const path = require('path');
function resolve(dir) {
return path.join(__dirname, dir)
}
//在export内部
chainWebpack: (config) => {
//修改文件引入自定义路径
config.resolve.alias
.set('@', resolve('src'))
.set('styles', resolve('src/styles'))
},
如需要在style引入styles里的scss文件,则 @import '~styles/theme';
,注意如果在style中引入,需要在前面添加 ~
符号。
8. 配置打包静态资源路径问题
在vue.config.js中配置
//打包配置,解决页面空白的配置方案。
publicPath:process.env.NODE_ENV == "production" ? "./" : "/",
9. 封装路由跳转
在src/router/index.js配置
this.isleft
和this.isright
是配置跳转页面过渡动画- path为跳转地址
- par为跳转需要的参数对象
- 在页面js中调用
this.$router.togo(path: string, opt: object)
- 在标签可以直接调用
$router.togo(path: string, opt: object)
- 在页面获取页面传递过来的参数
this.$route.query
// 需要左方向动画的路由用this.$router.togo('****', opt)
VueRouter.prototype.togo = function (path, par) {
this.isleft = true
this.isright = false
this.push({
path: path,
query: par
})
}
// 跳转指定url路径,但是history栈中不会有记录,点击返回会跳转到上上个页面 (就是直接替换了当前页面),传参跟push一样
VueRouter.prototype.toReplace = function (path, par) {
this.isleft = true
this.isright = false
this.replace({
path: path,
query: par
})
}
// 需要返回按钮动画的路由用this.$router.goBack(),返回上一个路由
VueRouter.prototype.goBack = function (n) {
this.isright = true
this.isleft = false
this.go(n || -1)
}
// 点击浏览器返回按钮执行,此时不需要路由回退
VueRouter.prototype.togoback = function () {
this.isright = true
this.isleft = false
}
// 点击浏览器前进按钮执行
VueRouter.prototype.togoin = function () {
this.isright = false
this.isleft = true
}
10. 配置页面跳转动画
- 在src/routger/index.js路由跳转里配置动画方向
isright
和isleft
; - 在App.vue页面修改如下
<template>
<div id="app">
<transition :name="transitionName">
<router-view class="Router"></router-view>
</transition>
</div>
</template>
<script>
export default {
name: 'App',
data () {
return {
transitionName: ''
}
},
watch: {
$route () {
if (this.$router.isleft) {
this.transitionName = 'slideleft'
}
if (this.$router.isright) {
this.transitionName = 'slideright'
}
}
},
mounted () {
}
}
</script>
<style lang="scss">
$body-bg-color: #f0f0f0;
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #484848;
}
// 设置跳转页面过渡动画
.Router {
position: absolute;
top: 0;
left: 0;
right: 0;
width: 100%;
min-height: 100%;
background-color: $body-bg-color;
transition: all .3s ease;
-moz-transition: all .3s ease;
-webkit-transition: all .3s ease;
}
.slideleft-enter,
.slideright-leave-active {
opacity: 1;
transform: translate3d(80% 0, 0);
-webkit-transform: translate3d(80%, 0, 0);
-moz-transform: translate3d(80%, 0, 0);
}
.slideleft-leave-active,
.slideright-enter {
opacity: 1;
transform: translate3d(-80% 0, 0);
-webkit-transform: translate3d(-80%, 0, 0);
-moz-transform: translate3d(-80%, 0, 0);
}
</style>
11. 封装网络请求,配置axios
在vue.config.js配置代理
'/api': {
target: '',
changeOrigin: true,
pathRewrite: {
'^/api': '这里为接口api地址'
}
}
}
在src里新建一个api文件夹,包含3个文件 api.js, configApi.js, index.js
api.js 用于存放api接口文档
const Api = {
get_img: `/get_img`,
}
export default Api;
configApi.js 用去封装请求,拦截请求
/* eslint-disable */
import axios from 'axios'
import router from '@/router'
import { Toast } from 'vant'
import { Dialog } from 'vant'
/**
* 定义请求常量
* TIME_OUT、ERR_OK
*/
const TIME_OUT =38000; // 请求超时时间
const API_HOST = '/apis'
// 请求超时时间
axios.defaults.timeout = TIME_OUT
// 封装请求拦截
axios.interceptors.request.use(config => {
// 发起请求,取消掉当当前正在进行的相同请求
return config
},
error => {
return Promise.reject(error)
}
)
// 封装响应拦截,判断token是否过期
axios.interceptors.response.use(
response => {
return response
},
error => {
if (error.response) {
switch (error.response.status) {
case 400:
error.message = 'Status:400'
break;
case 401:
error.message = 'Status:401'
break;
case 403:
error.message = 'Status:403'
break;
case 404:
error.message = 'Status:404'
// router.toReplace('/error/404', {err: '内容不存在或者已被删除'})
break;
case 405:
error.message = 'Status:405'
break;
case 408:
error.message = 'Status:408'
break;
case 500:
error.message = 'Error:500'
// router.toReplace('/error/404', {err: '服务器出错咯!'})
break;
case 501:
error.message = 'Status:501'
break;
case 502:
error.message = 'Status:502'
break;
case 503:
error.message = 'Status:503'
break;
case 504:
error.message = 'Network Timeout 504'
break;
default:
error.message = `ERROR:${error.response.status}`
break;
}
}
else if(error.request){
// 捕获超时请求
error.message = 'TimeOut';
}
return Promise.reject(error);
}
)
// 封装请求
export function Axios(requestUrl, params, type = 'POST') {
return new Promise((resolve,reject) => {
axios({
url: API_HOST + requestUrl,
method: type,
data: params
}).then(res => {
resolve(res.data)
}).catch(err => {
Toast.clear()
Dialog({
message: '网络开小差啦~',
closeOnClickOverlay: true
})
reject(err);
})
})
}
index.js 封装各个请求方法
import Api from '@/api/api'
import { Axios } from './configApi'
class Http {
getImg(params){
return Axios(Api.get_img, params);
}
ALL(url, params, type){
return Axios(url, params, type);
}
}
export default new Http();