Vuevuevue专题

用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.htmlmeta标签一定要加,上代码

<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内就取到了数据。

至此,前期准备工作就做好了,就可以着手进行开发了。
祝愉快~

上一篇下一篇

猜你喜欢

热点阅读