用vue来写一个新项目,建好脚手架之后<-->开发之前的准备动作
2019-08-21 本文已影响0人
风中凌乱的男子
前言:
拿到一个新项目,着手开发之前,我习惯先把准备工作准备充分,至于什么准备工作,我写的是移动端,首当其冲的就是设置rem单位转换(ps:我习惯用rem)直接看我这两篇文章
< px2rem-loader(Vue:将px转化为rem,适配移动端)>
< vue移动端中使用lib-flexible和px2rem,再引入第三方UI库导致第三方UI库的样式也变小的问题 >
我一般直接引入第二篇文章中的插件,插件配置完成后在App.vue中加上这段代码。
才会动态变化布局大小样式。
document.addEventListener("DOMContentLoaded", setFontSize);
window.addEventListener("resize", setFontSize);
function setFontSize() {
const html = document.querySelector("html");
let fontSize = window.innerWidth / 10;
fontSize = fontSize > 65 ? 65 : fontSize;
html.style.fontSize = fontSize + "px";
}
第二个,既然是移动端,
index.html
中meta
标签一定要加,上代码
<meta name="viewport" content="width=device-width,minimum- scale=1.0,maximum-scale=1.0,user-scalable=no" />
第三个,安装所需要的插件依赖,比如
axios
,vuex
,vue-wechat-title
,vue-totop
,element-ui
,vant
等等,看自己所需,vue-wechat-title
是改变路由页面title的插件,vue-totop
是返回顶部的插件。安装命令如下:
cnpm install axios --save
cnpm install vuex --save
cnpm install vue-wechat-title --save
cnpm install vue-totop --save
cnpm install element-ui --save
cnpm install vant --save
第四个,既然安装了依赖接下来就是配置依赖了。一个一个说,没有提到的可以大家可以百度下。
先说 `vue-wechat-title`
上面已经安装好了,直接在`main.js`内引用
//改变页面的title插件
import VueWechatTitle from 'vue-wechat-title'
Vue.use(VueWechatTitle)
使用的话就在`router`文件夹的`index.js`中这样使用
//index.js
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
const router = new Router({
routes: [
{
path: "/",
redirect: "/index"
},//重定向
{
path: "/index",
component: () => import('../pages/index.vue'),
meta: {
showFooter: true, //这个是控制底部导航菜单显示不显示,用法很简单,
//直接在底部导航菜单组件上这样使用就行了
//<!--底部导航开始-->
// <tabBar v-show="$route.meta.showFooter"></tabBar>
// <!--底部导航结束-->
title:"医佰康云课堂" //在这里使用
}
},
]
})
export default router;
然后在App.vue中
<router-view v-wechat-title='$route.meta.title'></router-view>
这样就实现了路由页面的title属性动态变化。
再说`vue-totop`
也是在`main.js中全局引用`
//返回顶部插件
import vueToTop from 'vue-totop'
Vue.use(vueToTop)
然后在需要的页面中就可以这样用了
<!-- 返回顶部插件 -->
<div class="toTop" @click="show"> //show方法下面会提到
<vueToTop
:type="config.type"
:top="config.top"
:right="config.right"
:size="config.size"
color="#5dd6c7"
bottom="250"
:duration="config.duration"
></vueToTop>
</div>
export default {
name: "Index",
inject: ["reload"],//这个是无感刷新当前页面的方法,下面会讲到
data() {
return {
value: "",
config: {
type: 4,
right: "0",
top: "200",
size: "40",
duration: "1" //这里返回顶部速度为1毫秒,是为了解决ios手机返回顶部后立即下滑出现的抖动闪烁现象。
}
};
},
}
具体用法建议大家参考这个教程
[https://github.com/1006008051/vue-totop](https://github.com/1006008051/vue-totop)
----------------------------------------------------------------------------------------
下面说一说 `inject: ["reload"]`,//这个无感刷新当前页面的方法的用法
----------------------------------------------------------------------------------------
在需要的.vue组件文件中,像上面一样那样写好,注意是和data同级。
使用之前在`App.vue`中,和`data`同级,这样写:
//无感刷新当前页面
provide() {
return {
reload: this.reload
};
},
`data`中这样写:
data() {
return {
isRouterAlive: true
};
},
`methods`中这样写:
//无感刷新当前页面
reload() {
this.isRouterAlive = false;
this.$nextTick(function() {
this.isRouterAlive = true;
});
},
`router-view`改写成这样:
<router-view class="Router" v-if="isRouterAlive" v-wechat-title='$route.meta.title'></router-view>
无感刷新当前页面的方法配置完了,在需要的.vue组件文件中,这样写:
//注意是和data同级。
inject: ["reload"],
data:{
return{
.....
}
}
然后在需要调用的方法中这样写:
methods: {
//show方法是上面提到的为了解决ios设备上的那个bug
因为没有很好的办法可以解决,如果大家解决了,麻烦告诉下小弟,感激不尽~
show() {
setTimeout(() => {
this.reload(); //这样调用就行了
}, 2);
}
}
----------------------------------------------------------------------------------------
移动端交互路由跳转加上左滑动右滑动的效果我觉得挺好的,具体实现,代码这样写:
1. 在main.js中这样写:
//监测页面的进退,实现动画效果
window.addEventListener('popstate', function (e) {
router.isBack = true
}, false)
2. 在App.vue中这样写:
watch: {
$route(to, from) {
// 切换动画
let isBack = this.$router.isBack; // 监听路由变化时的状态为前进还是后退
if (isBack) {
this.transitionName = "slide-left";
} else {
this.transitionName = "slide-right";
}
this.$router.isBack = false;
}
},
data中加上这个:
data() {
return {
transitionName: "slide-right", //初始过渡动画方向
};
},
router-view 改成这样:
<transition :name="transitionName">
<router-view class="Router" v-if="isRouterAlive" v-wechat-title='$route.meta.title'></router-view>
</transition>
css样式这样写:
<style>
body,
html,
#app {
width: 100%;
}
#app {
overflow-x: hidden;
}
.Router {
position: absolute;
height: 100%;
transition: all 0.377s ease;
will-change: opacity;
top: 0;
backface-visibility: hidden;
/* perspective: 1000; */ /* 这里如果打开的话就会引起fiexd固定定位失效,不要打开 */
}
.slide-left-enter,
.slide-right-leave-active {
opacity: 0;
transform: translate3d(-100%, 0, 0);
}
.slide-left-leave-active,
.slide-right-enter {
opacity: 0;
transform: translate3d(100%, 0, 0);
}
</style>
--------------------------------------------------------------------
接下来说说element-ui和vant-ui的按需加载引入
前面已经安装过element-ui和vant,想要按需加载他们, 就要安装两个插件
cnpm install babel-plugin-component -D
cnpm install babel-plugin-import -D
安装完毕后,在.babelrc中这样配置:
{
"presets": [
[
"env",
{
"modules": false,
"targets": {
"browsers": [
"> 1%",
"last 2 versions",
"not ie <= 8"
]
}
}
],
"stage-2"
],
"plugins": [
"transform-vue-jsx",
"transform-runtime",
[
"import",
{
"libraryName": "vant",
"libraryDirectory": "es",
"style": true
}
],
[
"component",
{
"libraryName": "element-ui",
"styleLibraryName": "theme-chalk"
}
]
]
}
在`src`目录下新建两个文件夹`element`和`vant`
文件夹内新建俩`index.js`文件分别这样写:
`element` > `index.js`
// 导入自己需要的组件
import { Select, Option, OptionGroup, Input, Tree, Dialog, Row, Col, Button, Message ,Loading} from 'element-ui'
const element = {
install: function (Vue) {
Vue.use(Select)
Vue.use(Option)
Vue.use(OptionGroup)
Vue.use(Input)
Vue.use(Tree)
Vue.use(Dialog)
Vue.use(Row)
Vue.use(Col)
Vue.use(Button),
Vue.prototype.$loading = Loading.service
Vue.prototype.$message = Message
}
}
export default element
`vant` > `index.js`
// 导入自己需要的组件
import { Button, Search, Icon, Swipe, SwipeItem, Lazyload, Row, Col, Image ,Divider,NoticeBar,Dialog,Tab, Tabs,Pagination } from 'vant';
const vant = {
install: function (Vue) {
Vue.use(Button)
Vue.use(Search)
Vue.use(Icon)
Vue.use(Swipe)
Vue.use(SwipeItem)
Vue.use(Lazyload)
Vue.use(Row)
Vue.use(Col)
Vue.use(Image);
Vue.use(Divider);
Vue.use(NoticeBar);
Vue.use(Dialog);
Vue.use(Pagination);
Vue.use(Tab).use(Tabs);
}
}
export default vant;
然后在main.js中这样引入
import vant from './vant/index'
Vue.use(vant)
// css样式还是需要全部引入
import 'element-ui/lib/theme-chalk/index.css'
import element from './element/index'
Vue.use(element)
这样就打包后就是按需加载的了。
下面就是封装ajax,重头戏来了。用到了axios,作为请求工具。
在 `src`目录下新建api文件夹,内新建ajax.js,和 index.js,里面的代码如下
/* ajax.js */
/*
ajax 请求函数模块
*/
import { showLoading, hideLoading } from '../assets/js/loading';
//Loading加载,需要的loading.js文件写在下面
import axios from 'axios'
/**
* 向外部暴漏一个函数 ajax
* @param {*} url 请求路径,默认为空
* @param {*} data 请求参数,默认为空对象
* @param {*} type 请求方法,默认为GET
*/
export default function ajax(url = '', data = {}, type = 'GET') {
// 返回值 Promise对象 (异步返回的数据是response.data,而不是response)
return new Promise(function (resolve, reject) {
// (利用axios)异步执行ajax请求
let promise // 这个内部的promise用来保存axios的返回值(promise对象)
if (type === 'GET') {
// 准备 url query 参数数据
let dataStr = '' // 数据拼接字符串,将data连接到url
Object.keys(data).forEach(key => {
dataStr += key + '=' + data[key] + '&'
})
if (dataStr !== '') {
dataStr = dataStr.substring(0, dataStr.lastIndexOf('&'))
url = url + '?' + dataStr
}
// 发送 get 请求
promise = axios.get(url)
} else {
// 发送 post 请求
promise = axios.post(url, data)
}
promise.then(response => {
// 成功回调resolve()
resolve(response.data)
})
.catch(error => {
// 失败回调reject()
reject(error)
})
})
}
/* 请求拦截器(请求之前的操作) */
axios.interceptors.request.use((req) => {
showLoading();
return req;
}, err => Promise.reject(err));
/* 请求之后的操作 */
axios.interceptors.response.use((res) => {
hideLoading();
return res;
}, (err) => {
hideLoading();
return Promise.reject(err);
});
/* loading.js */
import { Loading } from 'element-ui';
let loadingCount = 0;
let loading;
const startLoading = () => {
loading = Loading.service({
lock: true,
text: '加载中……',
background: 'rgba(0, 0, 0, 0.7)'
});
};
const endLoading = () => {
loading.close();
};
export const showLoading = () => {
if (loadingCount === 0) {
startLoading();
console.log(loadingCount)
}
loadingCount += 1;
console.log(loadingCount)
};
export const hideLoading = () => {
if (loadingCount <= 0) {
return;
}
loadingCount -= 1;
if (loadingCount === 0) {
endLoading();
}
};
/* index.js ,这里封装后端接口*/
/*
与后台交互模块 (依赖已封装的ajax函数)
*/
import ajax from './ajax'
const BASE_URL = 'https://ky.xxxxxx.com'
// const BASE_URL = '/api'
/**
* 获取首页数据信息
*/
export const reqHomePageData = mod_id => ajax(`${BASE_URL}/api/5d5a1d39efef1`, { mod_id }, 'POST'); //首页数据接口
/**
* 获取热门搜索数据接口
*/
export const reqHotSearch = () => ajax(`${BASE_URL}/api/5d5b87de18afa`, {}, 'POST');
/**
* 发送请求查询证书信息
*/
export const reqBook = content => ajax(`${BASE_URL}/api/5d4cd3e8d80f9`, { content }, 'POST');
/**
* 发送请求查询导师列表
*/
export const reqTeacherList = page => ajax(`${BASE_URL}/api/5d5bd91cb748c`, { page }, 'POST');
接下来配置vuex
1. 在`src`目录下新建一个文件夹store,在该文件夹内新建
`index.js`
`state.js`
`mutation-types.js`
`mutations.js`
`getters.js`
`actions.js`
文件
//index.js内的代码如下:
/*
vuex最核心的管理对象store
组装模块并导出 store 的地方
*/
// 首先引入Vue及Vuex
import Vue from 'vue'
import Vuex from 'vuex'
// 引入四个基本模块
import state from './state'
import mutations from './mutations'
import actions from './actions'
import getters from './getters'
// 一定要声明使用插件
Vue.use(Vuex)
// 把 store 对象提供给 “store” 选项,这可以把 store 的实例注入所有的子组件
export default new Vuex.Store({
state,
mutations,
actions,
getters
})
/*state.js*/
/*
State:状态对象
*/
export default {
mod_id: '1313',
swiper: {}, // 轮播图数据
}
/*mutation-types.js*/
/*
包含n个mutation的type名称常量
*/
export const GET_SWIPER = 'get_swiper' // 接收轮播图数据
/*mutations.js*/
import { GET_SWIPER } from './mutation-types'
// [方法名](state,{param}){}
export default {
[GET_SWIPER](state, { swiper }) {
state.swiper = swiper
},
}
/*actions.js*/
/*
Action:通过操作mutation间接更新state的多个方法的对象
*/
import {
GET_SWIPER
} from './mutation-types'
import {
reqHomePageData
} from '../api'
export default {
// 异步获取首页数据
async getHomePageData({ commit, state }) {
// 从state状态中获取到mod_id用来设置reqHomePageData的参数
const mod_id = state.mod_id
// 1. 发送异步ajax请求
const result = await reqHomePageData(mod_id)
// 2. 提交一个mutation,获取到轮播图数据
// console.log(result)
const swiper = result[2]
commit(GET_SWIPER, { swiper })
}
/*getters.js*/
暂时没有东西
——————————————————————————————————
vuex中的数据要根据自己的实际情况来写
下面我总结了一点流程,希望对你有所帮助。
——————————————————————————————————
封装接口请求操作步骤
1. 在api.js中新增接口
export const reqHotSearch = () => ajax(`${BASE_URL}/api/5d5b87de18afa`); //这是get请求的写法
export const reqHomePageData = mod_id => ajax(`${BASE_URL}/api/5d5a1d39efef1`, { mod_id }, 'POST’);//这是post请求的写法
2. 在state.js中新增一个状态对象容器
hotSearch:{ } //热门搜索数据
3. 在mutation-types.js中新增常量
export const GET_HOTSEARCH = 'get_hotSearch' // 接收热门搜索数据
4. 在mutations.js中引入第三步的常量
import { GET_HOTSEARCH } from './mutation-types'
暴露一个方法
[GET_HOTSEARCH](state, { hotSearch }) {
state.hotSearch = hotSearch
},
5. 在actions.js中引入第三步的常量和第一步的接口
import { GET_HOTSEARCH } from './mutation-types'
import { reqHotSearch } from '../api'
然后在异步发起请求——-post传参的写法,固定的参数在state中提前定义好
// 异步获取首页数据
async getHomePageData({ commit, state }) {
// 从state状态中获取到mod_id用来设置reqHomePageData的参数
const mod_id = state.mod_id //这里获取参数
// 1. 发送异步ajax请求
const result = await reqHomePageData(mod_id)
// 2. 提交一个mutation,获取到轮播图数据
// console.log(result)
const swiper = result[2]
commit(GET_SWIPER, { swiper })
}
// 异步获取食品分类列表
async getHotSearch({ commit }) {
// 发送异步ajax请求
const result = await reqHotSearch()
// 提交一个mutation
if (result.code === 0) {
const hotSearch = result.data
commit(GET_HOTSEARCH, { hotSearch })
}
},
传参数的请求,在需要发送请求的页面这样写:
在methods中:
async query() {
if (this.number == "") {
this.$message.error("请输入证书编号");
} else {
//异步获取证书信息
const result = await reqBook(this.number);
console.log(result)
}
},
},
点击调用,或者在mounted中自动调用根据需求来做。
this.query();
调用actions.js中的方法和取vuex中的数据这样写:
调用:
引入 import { mapActions, mapState } from "vuex";
在methods中:
...mapActions(["getHotSearch"])
然后点击调用this.getHotSearch(),或者在mounted中自动调用根据需求来做。
取数据:
computed: {
...mapState(["hotSearch"])
}
这样hotSearch内就取到了数据。
至此,前期准备工作就做好了,就可以着手进行开发了。
祝愉快~