创建基于vue的H5
技术选型
公司现在需要开发移动端的h5,使用现在比较流行的vue 2.0开发,使用的脚手架是Vant2,网络访问使用的是axios,路由跳转使用的是vue-router,开发工具是vscode,
vue cli
vue
vuex
vue中使用axios最详细教程
vue router
环境搭建
引入库
我这里已经安装好了nodejs,并且已经配置好了淘宝镜像
npm config set registry https://registry.npm.taobao.org
vscode不能直接在工具里创建项目,要先创建一个空文件夹,然后通过vscode打开文件夹。
在E:\vueProject文件夹下创建VueForBlog文件夹,使用vscode打开(vscode默认只能打开一个项目,如果想打开多个,可以使用ctrl+shift+n),点击工具栏终端,新建终端,正式开始创建项目
终端输入
npm i vant@latest-v2 -S
npm install -g @vue/cli
创建脚手架项目
vue create first-vue
选择vue 2
创建完成以后,会是这个样子
记住,后边要cd到工程里,否则还是在工程外创建引用之类的
下边用同样的方法,引入axios,router,还有vant需要使用的 postcss-px-to-viewport,postcss-pxtorem,lib-flexible
npm install vue-router@3.0.7
npm install axios
npm install vuex
npm i -S amfe-flexible
npm install postcss postcss-pxtorem --save-dev
npm install postcss-px-to-viewport --save-dev
npm install --save less-loader less
配置环境
配置vant 的基础样式,方便引用vant的组件。在first\src\assets\style\下创建theme.less,内容
// Color Palette
@black: #000;
@white: #fff;
@gray-1: #f7f8fa;
@gray-2: #f2f3f5;
@gray-3: #ebedf0;
@gray-4: #dcdee0;
@gray-5: #c8c9cc;
@gray-6: #969799;
@gray-7: #646566;
@gray-8: #323233;
@red: #ee0a24;
@blue: #1989fa;
@orange: #ff976a;
@orange-dark: #ed6a0c;
@orange-light: #fffbe8;
@green: #07c160;// Gradient Colors
@gradient-red: linear-gradient(to right, #ff6034, #ee0a24);
@gradient-orange: linear-gradient(to right, #ffd01e, #ff8917);// Component Colors
@text-color: @gray-8;
@active-color: @gray-2;
@active-opacity: 0.7;
@disabled-opacity: 0.5;
@background-color: @gray-1;
@background-color-light: #fafafa;
@text-link-color: #576b95;// Padding
@padding-base: 4px;
@padding-xs: @padding-base * 2;
@padding-sm: @padding-base * 3;
@padding-md: @padding-base * 4;
@padding-lg: @padding-base * 6;
@padding-xl: @padding-base * 8;// Font
@font-size-xs: 10px;
@font-size-sm: 12px;
@font-size-md: 14px;
@font-size-lg: 16px;
@font-weight-bold: 500;
@line-height-xs: 14px;
@line-height-sm: 18px;
@line-height-md: 20px;
@line-height-lg: 22px;
@base-font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue',Helvetica, Segoe UI, Arial, Roboto, 'PingFang SC', 'miui', 'Hiragino Sans GB','Microsoft Yahei', sans-serif;
@price-integer-font-family: Avenir-Heavy, PingFang SC, Helvetica Neue, Arial,sans-serif;// Animation
@animation-duration-base: 0.3s;
@animation-duration-fast: 0.2s;
@animation-timing-function-enter: ease-out;
@animation-timing-function-leave: ease-in;// Border
@border-color: @gray-3;
@border-width-base: 1px;
@border-radius-sm: 2px;
@border-radius-md: 4px;
@border-radius-lg: 8px;
@border-radius-max: 999px;
同样目录下,创建一个public.css,内容
body {background-color: #f8f8f9;min-height: 100vh;min-width: 100vw;
}
.padding-lr10 {padding: 0 10px;
}
.phoneContant header .van-nav-bar {text-align: center;line-height: 56px;background: #68c2bd;
}
h3 {font-size: 16px;
}
.phoneContant header .van-nav-bar .van-icon {font-size: 20px;color: #fff;
}
.phoneContant header .van-nav-bar__title {color: #fff;
}
.contant {padding: 0 10px;
}
.re {position: relative;
}
.cardContant {background: #f5f5f5;height: 78vh;width: 100%;clear: both;padding: 8px 0;
}
.hosImg {width: 60px !important;height: 60px !important;border-radius: 50%;
}
这里的内容,是根据项目中需要的样式自定义的
在vue.config.js里进行配置
访问资源路径,有个快捷方法,设置一个符号,用来直接指定到src目录下,比用.或者…方便,还不容易出错,同样在vue.config.js里,@就代表src目录
chainWebpack: (config) => {config.resolve.alias.set("@", resolve("src"));config.plugin("html").tap((args) => {args[0].minify = false;return args;});},
vue.config.js
const path = require("path");
// const CompressionWebpackPlugin = require("compression-webpack-plugin");
// // 定义压缩文件类型
// const productionGzipExtensions = ["js", "css"];
// let timeStamp = new Date().getTime();function resolve(dir) {return path.join(__dirname, dir);
}
module.exports = {// 基本路径publicPath: "./",// 输出文件目录 不写则默认根目录outputDir: "dist",assetsDir: "static", // 静态资源目录 (js, css, img, fonts)lintOnSave: false,// eslint-loader 是否在保存的时候检查// lintOnSave: 'error',// devServer: {// // development server port 8000// port: 8000,// // If you want to turn on the proxy, please remove the mockjs /src/main.jsL11// proxy: {// '/api/': {// target: process.env.VUE_APP_APIUrl,// changeOrigin: true// }// }// },// /assets/style/public.css.lesscss: {loaderOptions: {less: {lessOptions: {modifyVars: {// 或者可以通过 less 文件覆盖(文件路径为绝对路径)hack: `true; @import "@/assets/style/theme.less";`,},},},},},devServer: {// 设置主机地址// 设置默认端口port: 8080,// // 设置代理// proxy: {// "/": {// // target: "http://198.166.21.56:8080/",// ws: true, // 支持ws协议;websocket的缩写;// changeOrigin: true, // 是否跨域// pathRewrite: {// // 路径替换// "^/api": "",// },// },// },},// use the full build with in-browser compiler?// https://vuejs.org/v2/guide/installation.html#Runtime-Compiler-vs-Runtime-only// compiler: false,// webpack配置// see https://github.com/vuejs/vue-cli/blob/dev/docs/webpack.md webpack链接API,用于生成和修改webapck配置//部署打包html带引号chainWebpack: (config) => {config.resolve.alias.set("@", resolve("src"));config.plugin("html").tap((args) => {args[0].minify = false;return args;});},//压缩打包文件大小configureWebpack: (config) => {if (process.env.NODE_ENV === "Production") {// config.output.filename = `assets/js/[name].${timeStamp}.js`;// config.output.chunkFilename = `assets/js/[name].${timeStamp}.js`;config.plugins.push(new CompressionWebpackPlugin({algorithm: "gzip",test: new RegExp("\\.(" + productionGzipExtensions.join("|") + ")$"),threshold: 10240,minRatio: 0.8,}));}config.externals = {// 'vue': 'Vue',// 'vuex': 'Vuex',// 'vue-router': 'VueRouter',// 'element-ui': 'ELEMENT',// 'Axios': 'axios',// 'jquery': '$',// 'moment': 'moment',// 'js-cookie': 'Cookies',// 'echarts': 'echarts',// 'tinymce/tinymce': 'tinymce'};// }},// configureWebpack: (config) => {// webpack配置,值位对象时会合并配置,为方法时会改写配置// if (debug) { // 开发环境配置// config.devtool = 'cheap-module-eval-source-map'// } else { // 生产环境配置// }// Object.assign(config, { // 开发生产共同配置// resolve: {// alias: {// '@': path.resolve(__dirname, './src')//设置路径别名// //...// }// }// })// },// vue-loader 配置项// https://vue-loader.vuejs.org/en/options.html// vueLoader: {},// 生产环境是否生成 sourceMap 文件productionSourceMap: false,// css相关配置 配置高于chainWebpack中关于css loader的配置// css: {// // 是否使用css分离插件 ExtractTextPlugin// extract: true,// // 开启 CSS source maps?是否在构建样式地图,false将提高构建速度// sourceMap: false,// // css预设器配置项// loaderOptions: {},// // 启用 CSS modules for all css / pre-processor files.// modules: false// },// use thread-loader for babel & TS in production build// enabled by default if the machine has more than 1 cores 构建时开启多进程处理babel编译//parallel: require('os').cpus().length > 1,// 是否启用dll// See https://github.com/vuejs/vue-cli/blob/dev/docs/cli-service.md#dll-mode// dll: false,// PWA 插件相关配置// see https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-pwa//pwa: {},// webpack-dev-server 相关配置// devServer: {// open: process.platform === 'darwin',// host: '0.0.0.0',// port: 8080,// https: false,// hotOnly: false,// proxy: null, // 设置代理// before: app => { }// },// 第三方插件配置pluginOptions: {// ...},
};
lintOnSave: false,这个的意思就是关闭语法检查,要不然会很多报错,运行不起来
在first-vue目录下,新建一个.postcssrc.js,在里边配置postcss
module.exports = {plugins: {//...autoprefixer: {browsers: ["Android >= 4.0", "iOS >= 7"],},"postcss-pxtorem": {rootValue: 37.5, //vant-UI的官方根字体大小是37.5propList: ["*"],},},
};
底部安全区适配
在public目录下的index.html文件配置底部安全区适配
<!DOCTYPE html>
<html lang="en"><head><meta base="/" id="base" /><meta charset="utf-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><metaname="viewport"content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, viewport-fit=cover,user-scalable=no"/><link rel="icon" href="<%= BASE_URL %>favicon.ico" /><title>首页</title></head><body><!-- 开启顶部安全区适配 --><van-nav-bar safe-area-inset-top /><div id="app"></div><!-- built files will be auto injected --><!-- 开启底部安全区适配 --><van-number-keyboard safe-area-inset-bottom /></body>
</html>
<script></script>
src目录下,新建router目录,下边新建index.js,对router进行配置
import Vue from "vue";
//路由
import VueRouter from "vue-router";
import { asyncRouterMap } from "@/config/router.config";
Vue.use(VueRouter);
const routes = []const router = new VueRouter({routes: routes.concat(asyncRouterMap),mode: "hash",});export default router;
在src的config目录下,新建router.config,这个对应路由和相应的页面
export const asyncRouterMap = [{path: "/",component: () => import("@/components/Header.vue"),meta: { title: "首页" },// redirect: '/dashboard/workplace',redirect: "/home",children: [{path: "/home",name: "home",component: () => import("@/views/Home.vue"),hidden: true,meta: { title: "首页" },},{path: "/second",name: "second",component: () => import("@/views/Second.vue"),hidden: true,meta: { title: "第二页" },},],},{path: "*",redirect: "/home",hidden: true,},
];
src目录下,新建store目录,下边新建index.js,对vuex进行配置
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)const state = {openId:'',userStat:'0',identification:'',userInfo:{},active:'1',
}
const mutations = {setOpenid(state,payload){state.openId = payloadsessionStorage.setItem("openId", payload);},setUserStat(state,payload){state.userStat = payloadsessionStorage.setItem("userStat", payload);},setNumber(state,index) {state.active = index;}
}const action = {}
export default new Vuex.Store({state,mutations,action,
})
对App.vue进行修改
<template><div id="app"><router-view></router-view></div>
</template><script>export default {name: 'App',}
</script><style>
#app {height: 100%;
}
.el-header,
.el-footer {background-color: #b3c0d1;color: #333;text-align: center;line-height: 60px;
}body > .el-container {margin-bottom: 40px;
}
</style>
我现在需要对一个头部组件进行封装,因为每个页面都有头部导航栏,所以封装成一个组件
在components目录里,新建Header.vue
<template><div class="phoneContant"><header><van-nav-barclass="personheader":fixed="true":placeholder="true":safe-area-inset-top="true":title="$route.meta.title"left-text="":left-arrow="true"@click-left="back"/></header><router-view></router-view></div>
</template><script>var config = {isAndroid: /Android/i.test(navigator.userAgent), //判断是否为移动端isIos: !!navigator.userAgent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/), //判断是否为IOS
};export default {name: "Headers",//import引入的组件需要注入到对象中才能使用components: {},data() {//这里存放数据return {title: "",};},//监听属性 类似于data概念computed: {},//监控data中的数据变化watch: {$route: {handler(newRouter, fromRouter) {},immediate: true,},},//方法集合methods: {back() {this.$router.go(-1);return false;},},//生命周期 - 创建完成(可以访问当前this实例)created() {let cont = window.history.length;console.log("window.history.length-----------------roomstep");console.log(cont);},//生命周期 - 挂载完成(可以访问DOM元素)mounted() {},beforeCreate() {}, //生命周期 - 创建之前beforeMount() {}, //生命周期 - 挂载之前beforeUpdate() {}, //生命周期 - 更新之前updated() {}, //生命周期 - 更新之后beforeDestroy() {}, //生命周期 - 销毁之前destroyed() {}, //生命周期 - 销毁完成activated() {}, //如果页面有keep-alive缓存功能,这个函数会触发
};
</script>
在main.js里进行引入vant和css样式,以及其他组件
import Vue from 'vue'
import App from './App.vue'
import "@/assets/style/public.css";
import router from "@/router";
import Vant from "vant";
import store from './store'
import Vuex from 'vuex'
import "vant/lib/index.less";
import "@/assets/style/public.css";
Vue.config.productionTip = false
import {GET,GETRESET,POST,PUT,DELETE,POSTJSON,PUTJSON
} from './service/index'
Vue.prototype.$http = {GET,GETRESET,POST,PUT,DELETE,POSTJSON,PUTJSON
};
Vue.use(Vant);
Vue.use(Vuex);
new Vue({router,render: h => h(App),
}).$mount('#app')
在src下创建一个views文件夹,新建两个vue,Home.vue和Second.vue,内容很简单
Home.vue
<template><div class="phoneContant"><van-button type="warning" @click="goToNext">进入下一页</van-button></div>
</template><script>export default {name: "Home",data() {return {msg: "我是首页",};},methods: {goToNext() {this.$router.push("/second");},},
};
</script><style>
</style>
Second.vue
<template>
<div>{{msg}}
</div></template><script>
export default {data(){return{msg:"第二页"}}
}
</script><style></style>
运行
命令行输入npm run serve
网络封装
对axios进行封装一下,方便使用。在src下新建service文件夹,utils下新建index.js
import axios from "axios";
import { Notify } from "vant";
import QS from 'qs'
import router from "@/router";const baseURL =BaseUrl// process.env.NODE_ENV === "development" ? "/api" : window.productionUrl;
//创建axios实例
const service = axios.create({baseURL, // api的base_url window.productionUrlwithCredentials: true,timeout: 30000, // 请求超时时间
});// 发送请求拦截器
service.interceptors.request.use((config) => {const Nonce =Math.ceil(+new Date() / 1000) + "" + Math.ceil(Math.random() * 10000);const CurTime = Math.floor(+new Date() / 1000).toString();config.headers["Content-Type"] = "application/json;charset=UTF-8";return config;},(error) => {return Promise.reject(error);}
);//发送请求响应拦截
service.interceptors.response.use((response) => {const res = JSON.parse(CryptoJS.decrypt(response.data));// 错误的status情况// console.log(res);if (!res.result) {Notify({ type: "danger", message: res.message || "error" });return Promise.reject(res.message || "error");} else {return res;}},(error) => {Notify({ type: "danger", message: error.message || "error" });return Promise.reject(error);}
);
/*** get方法,对应get请求GET * @param {String} url [请求的url地址]* @param {Object} params [请求时携带的参数]*/
export function GET(url, params) {url = serviceAdapter(url);return new Promise((resolve, reject) => {axios.get(url, {params: params,paramsSerializer: function (params) {return QS.stringify(params, {arrayFormat: 'repeat'})}}, ).then(res => {// console.log(res)// if (!res.data && typeof (res.data) != "undefined") {// res.data.data.rows = []// }// if (!res.data.data && typeof (res.data.data) != "undefined" && res.data.data != 0) {// res.data.data = []// }resolve(res);}).catch(err => {reject(err)})});
}
export function GETRESET(url, params) {url = serviceAdapter(url);return new Promise((resolve, reject) => {axios.get(url, {params: params,paramsSerializer: function (params) {return QS.stringify(params, {arrayFormat: 'repeat'})}}, ).then(res => {// if (res.data.data === null) {// res.data.data = " "; //返回值是null的// }// if (!res.data.data.rows && typeof (res.data.data.rows) != "undefined" && res.data.data.rows != 0) {// res.data.data.rows = []// }// if (!res.data.data && typeof (res.data.data) != "undefined" && res.data.data != 0) {// res.data.data = []// }resolve(res);}).catch(err => {reject(err)})})
}/*** post方法,对应post请求* @param {String} url [请求的url地址]* @param {Object} params [请求时携带的参数]*/
export function POST(url, params) {url = serviceAdapter(url);return new Promise((resolve, reject) => {axios.post(url, QS.stringify(params, {arrayFormat: 'repeat'})).then(res => {resolve(res);}).catch(err => {reject(err)})});
}/*** postJson方法,对应post请求* @param {String} url [请求的url地址]* @param {Object} params [请求时携带的参数]*/
export function POSTJSON(url, params) {url = serviceAdapter(url);return new Promise((resolve, reject) => {axios.post(url, params).then(res => {resolve(res);}).catch(err => {reject(err)})});
}/*** put方法,对应put请求* @param {String} url [请求的url地址]* @param {Object} params [请求时携带的参数]*/
export function PUT(url, params) {url = serviceAdapter(url);return new Promise((resolve, reject) => {axios.put(url, QS.stringify(params, {arrayFormat: 'repeat'})).then(res => {resolve(res);}).catch(err => {reject(err)})});
}/*** PUTJSON方法,对应put请求* @param {String} url [请求的url地址]* @param {Object} params [请求时携带的参数]*/
export function PUTJSON(url, params) {url = serviceAdapter(url);return new Promise((resolve, reject) => {axios.put(url, params).then(res => {resolve(res);}).catch(err => {reject(err)})});
}/*** delete方法,对应delete请求* @param {String} url [请求的url地址]* @param {Object} params [请求时携带的参数]*/
export function DELETE(url, params) {url = serviceAdapter(url);return new Promise((resolve, reject) => {axios.delete(url, {params: params,paramsSerializer: params => {return QS.stringify(params, {indices: false})}}).then(res => {resolve(res);}).catch(err => {reject(err)})});
}
export default service;
结语
现在只是搭建了工程,如果没有缺少步骤的话,应该是可以运行起来的,剩下的还有很多工作要做。。。
补充
是因为版本问题,是你安装了最新的vuex 4 以上导致:
解决办法:安装3系列的:
先卸载 安装的 4 版本的vuex
npm uninstall vuex
安装 3.6.2版本的
npm install --save vuex@3.6.2
创建基于vue的H5相关推荐
- vue 微信公众号支付接口_基于vue的h5项目之支付宝支付与微信支付
本文仅记录基于vue开发h5项目过程中使用支付宝和微信支付过程中的重点与槽点,仅为前端部分,如有疏漏不正之处,请于文末评论探讨.注意:标红部分灰常重要,仔细阅读官方文档非常重要,耐心非常重要,细心非常 ...
- html5快速开发模板生成器,推荐一个基于Vue 的 H5 快速开发模板
本项目以基于 vue-cli4 和 Vant-ui 搭建的,进行移动端开发中的一些最佳实践方案 模板地址 动动你的小手点颗star 样式适配 在移动端网页开发时,样式适配始终是一个绕不开的问题.对此目 ...
- vue lang_推荐一个基于Vue 的 H5 快速开发模板
关注 Vue社区,回复"加群" 加入我们一起学习,天天进步 praise juejin.im/post/5e612534e51d4527017971a2 模板基于 vue-cli4 ...
- 基于vue 的h5微信分享
之前一直都是使用的html,jquery,js等做的微信分享,现在项目都改用vue做了,但是微信分享还是要接入的,这里简单分享一下移动端vue如何接入微信分享. 1.首先安装微信分享依赖 npm in ...
- linux 使用ssr客户端_【第一期】基于 @vue/cli3 与 koa 创建 ssr 工程
什么是基于同构代码的 SSR 服务(Server-side rendering based on isomorphic code) 首先,我们需要先明白什么是 spa (single page app ...
- Vue-app之H5基于Vue初始化一个移动端项目H5APP
Web App,顾名思义是指基于Web的应用,基本采用Html5语言写出,不需要下载安装.类似于现在所说的轻应用.基于浏览器运行的应用,基本上可以说是触屏版的网页应用. 一个web app如何拔地而起 ...
- 音乐、视频播放模式切换实现方案及原理解析(基于vue、vuex、h5 audio)
音乐.视频播放模式切换实现方案及原理解析(基于vue.vuex.h5 audio) 播放模式有三种: 顺序播放 随机播放 单曲循环 定义为一个playMode对象并向外暴露,内含三种播放模式,即为: ...
- 创建基于webpack打包的vue项目
创建基于webpack打包的vue项目 结合win7.element-ui.vue(vue-router.vue-cli).webpack等技术,完成了项目的基础工作.难则不会,会则不难:贵在经验总结 ...
- vue.js毕业设计,基于vue.js前后端分离教室预约系统(H5移动项目) 开题报告
毕业论文 基于Vue.js的教室预约系统(H5) 开题报告 学 院: 专 业: 年 级: 学生姓名: 指导教师: 黄菊华 XXXX大学本科生毕业论文(设计)开题报告书 姓 ...
最新文章
- 12岁AI开发者现身DuerOS发布会:得开发者得天下
- Android基础--tools:context=.TestActivity作用
- shiro之AuthenticationStrategy
- Chinese savior crepe
- ajax获取后台数据出错parsererror
- 设计师应该尊重技术的限制
- matlab butter 低通,matlab butter 用法
- 我用 Python 抓取了 7000 多本电子书
- Listary一款不只是程序员需要的软件
- Ragel State Machine Compiler 的速度测试
- 油田智能化远程监控系统_油气田长停井图像远程传输监控系统
- QT——连接腾讯云物联网平台
- Revit出图问题:打印机中新建纸张尺寸?批量导出图纸?
- osgEarth示例分析——osgearth_graticule
- Win10系统程序以管理员身份开机自启动配置
- 什么是 FOUC(无样式内容闪烁)?你如何来避免 FOUC?
- am335x uboot启动流程分析
- 驴途网--技术小结1
- Android开发之漫漫长途 XIX—HTTP
- J2SE简单的数据库连接池