zoukankan      html  css  js  c++  java
  • 【实战】Vue全家桶(vue + axios + vue-router + vuex)搭建移动端H5项目

    使用Vue全家桶开发移动端页面。
    本博文默认已安装node.js。
    github链接

    一.准备工作

    • 安装vue
    npm install vue
    
    • 安装脚手架vue-cli
    npm install -g @vue/cli
    
    • 创建webpack项目
    vue init webpack my-app
    

    image

    • 运行
    cd my-app
    npm run dev
    

    运行效果
    按照提示,在浏览器打开http://localhost:8082/,效果如下:
    展示效果

    • 安装状态管理vuex
    npm install vuex --save-dev
    
    • 目录结构
      项目初始目录如下:
      目录结构.jpg

    至此,准备工作已就绪,接下来将进行项目整体的结构设计。

    二.项目设计

    1.项目目录设计

    • assets目录下创建imagesjscss文件夹。

      • images文件夹下创建index文件夹,用于存放 首页图片(模块化,让项目结构一目了然)。
        assets.jpg
    • src目录下创建pages目录,用户存放不同的功能页面。

      • 再在pages目录下创建index首页目录。
        首页.jpg
      • index目录下创建index.vue主文件。
        你好首页.jpg
    • 修改router

      • 修改index.js
      import Vue from 'vue'
      import Router from 'vue-router'
      import Index from '@/pages/index'
      
      Vue.use(Router)
      
      export default new Router({
        routes: [
          {
            path: '/',
            name: 'Index',
            component: Index
          }
        ]
      })
      
      • 浏览器效果
        你好首页2.jpg
    • 删除components目录下的文件,将此目录作为页面组件文件夹,在此目录下创建index文件夹,存放index首页的组件。
      首页组件.jpg

    • pages/index/index.vue中引入header组件

    <template>
      <div class="index-wrap">
        <comHeader />
        你好,首页
      </div>
    </template>
    
    <script>
    import header from '@/components/index/header'
    
    export default {
      data() {
        return {
    
        }
      },
      components: {
        comHeader: header
      }
    }
    
    </script>
    
    <style scoped>
    
    </style>
    

    至此,项目的整个结构被重新设计完成,接下来让我们引入rem.jsless来让我们开发起来更舒服。

    2.移动端适配和less编译,让开发变得快乐起来。

    • 移动端适配 rem
      assets/js文件夹下创建common文件夹存放公共js,再在common文件夹下创建rem适配文件js。并在main.js中引入。
    // rem.js
    ;(function (designWidth, maxWidth) {
        var doc = document,
            win = window;
        var docEl = doc.documentElement;
        var tid;
        var rootItem, rootStyle;
    
        function refreshRem() {
            var width = docEl.getBoundingClientRect().width;
            if (!maxWidth) {
                maxWidth = 540;
            }
            ;
            if (width > maxWidth) {
                width = maxWidth;
            }
            //与淘宝做法不同,直接采用简单的rem换算方法1rem=100px
            var rem = width * 100 / designWidth;
            //兼容UC开始
            rootStyle = "html{font-size:" + rem + 'px !important}';
            rootItem = document.getElementById('rootsize') || document.createElement("style");
            if (!document.getElementById('rootsize')) {
                document.getElementsByTagName("head")[0].appendChild(rootItem);
                rootItem.id = 'rootsize';
            }
            if (rootItem.styleSheet) {
                rootItem.styleSheet.disabled || (rootItem.styleSheet.cssText = rootStyle)
            } else {
                try {
                    rootItem.innerHTML = rootStyle
                } catch (f) {
                    rootItem.innerText = rootStyle
                }
            }
            //兼容UC结束
            docEl.style.fontSize = rem + "px";
        };
        refreshRem();
    
        win.addEventListener("resize", function () {
            clearTimeout(tid); //防止执行两次
            tid = setTimeout(refreshRem, 300);
        }, false);
    
        win.addEventListener("pageshow", function (e) {
            if (e.persisted) { // 浏览器后退的时候重新计算
                clearTimeout(tid);
                tid = setTimeout(refreshRem, 300);
            }
        }, false);
        if (doc.readyState === "complete") {
            
            doc.body.style.fontSize = "16px";
        } else {
            doc.addEventListener("DOMContentLoaded", function (e) {
                doc.body.style.fontSize = "16px";
            }, false);
        }
    })(360, 750); // 360为设计图的尺寸,请按照实际设计图修改
    
    // main.js
    import Vue from 'vue'
    import App from './App'
    import router from './router'
    import '@/assets/js/common/rem.js' // 引入rem.js
    
    Vue.config.productionTip = false
    
    new Vue({
      el: '#app',
      router,
      components: { App },
      template: '<App/>'
    })
    

    至此,rem适配已完成,在写style时便可直接按照 (设计图尺寸 / 100) rem,例如设计图给到元素height为200px,那么用rem则为height: 2rem;

    • less 编译,在写style时,为了高效开发,我们选用less编译。
    // 安装less和依赖
    npm install less less-loader style-loader --save-dev
    

    以header.vue为例

    <template>
      <div class="header-wrap">
        我是头头头
        <div class="title">
          title
        </div>
      </div>
    </template>
    
    <script>
    
    </script>
    
    <style scoped lang="less">
    .header-wrap{
      height: 1rem;
      background-color: #252627;
      .title{
        color: #fff;
        height: .5rem;
      }
    }
    </style>
    

    至此就可以开始页面的开发了。

    3.状态管理store

    • 安装 vuex
    npm install vuex --save
    
    • 创建store目录结构,至于store原理望大家自已学习掌握。
      store.jpg

      • index.js
      /**
       * 组装模块并导出 store
       */
      
      import Vue from 'vue'
      import Vuex from 'vuex'
      import game from './modules/game'
      import * as actions from './actions'
      import mutations from './mutations'
      import getters from './getters'
      
      Vue.use(Vuex)
      
      const debug = process.env.NODE_ENV !== 'production'
      
      const state = {
        userInfo:{}
      }
      
      export default new Vuex.Store({
        state: state,
        actions: actions,
        mutations: mutations,
        getters:getters,
        modules: {
          game,
        },
        strict: debug
      })
      
      
    • 使用store

    this.$store.dispatch('getData', response.data.data)
    

    4.数据请求 axios

    • src目录下穿件utils目录用于存放工具js。在utils下创建request.jsaxios请求进行封装。
    import axios from 'axios'
    import { Message, MessageBox } from 'element-ui'
    import config from '../../config/config'
    import toast from './toast'
    
    import store from '@/store'
    
    const service = axios.create({
      baseURL: 'www.baidu.com', 
      timeout:0// request timeout
    })
    service.interceptors.request.use(
        requestConfig => {
          let data = {
            // 公共请求参数
          };
          requestConfig.data = Object.assign({}, requestConfig.data, data)
          return requestConfig
        },
        error => {
          Promise.reject(error)
        }
    )
    // response interceptor
    service.interceptors.response.use(response => {
      const res = response.data
      if (res.errno === 501) {
          MessageBox.alert('系统未登录,请重新登录', '错误', {
              confirmButtonText: '确定',
              type: 'error'
          }).then(() => {
          })
          return Promise.reject('error')
      } else if (res.errno === 502) {
          toast.showToast('系统内部错误,请联系管理员维护',1200,'error')
          return Promise.reject('error')
      } else if (res.errno === 503) {
          toast.showToast('请求业务目前未支持',1200,'error')
          return Promise.reject('error')
      } else if (res.errno === 504) {
          toast.showToast('更新数据已经失效,请刷新页面重新操作',1200,'error')
          return Promise.reject('error')
      } else if (res.errno === 505) {
          toast.showToast('更新失败,请再尝试一次',1200,'error')
          return Promise.reject('error')
      } else if (res.errno === 506) {
          toast.showToast('没有操作权限,请联系管理员授权',1200,'error')
          return Promise.reject('error')
      }  else {
          return response
        }
      }, error => {
        toast.showToast('登录连接超时',5 * 1000,'error')
        return Promise.reject(error)
      })
    export default service
    
    
    • src 目录下常见 api 文件夹,并创建组件index.js
    import request from '../utils/request'
    
    /**
     * @method getUserInfo 获取用户信息
     * @param query {Object}
     */
    export function getUserInfo(query){
      return request({
        url: 'user/info',
        method: 'post',
        data: query
      })
    }
    
    • index.vue中调用
    <template>
      <div class="index-wrap">
        <comHeader />
        你好,首页
      </div>
    </template>
    
    <script>
    import header from '@/components/index/header'
    import { getUserInfo } from '@/api/index.js'  // 引入
    
    export default {
      data() {
        return {
    
        }
      },
      components: {
        comHeader: header
      },
      methods: {
        getInfo(){
          getUserInfo()  //业务逻辑
          .then(res => {
            // do something
          })
          .catch(response => {})
        }
      },
      created() {
        this.getInfo(); //调用
      }
    }
    
    </script>
    
    <style scoped lang="less">
    
    </style>
    
    

    三.编译发布

    1.编译生成 dist

    npm run build
    
    //在根目录下生成dis文件夹,可以将此文件夹放到oss上以供不同浏览器浏览。
    

    总结

    • 在开发项目的过程中要考虑项目的模块化。
    • 尽可能的做到代码规范,具体的代码规范可在我的其他博文参考下:
    • 实际项目中的具体问题可私信我,共同解决共同学习。为你能看完本博文而感到愉悦
  • 相关阅读:
    【Java】《Java程序设计基础教程》第三章学习
    【Python】编程小白的第一本python(最基本的魔法函数)
    【Python】编程小白的第一本python(基础中的基础)
    bootstrap中的col-xs-*,col-sm-*,col-md-* 关系
    java基础面试题总结
    人生中第一次面试(阿里一面)
    阿里云服务器ip:端口号无法访问
    redis基本指令
    linux基本指令
    centos安装redis
  • 原文地址:https://www.cnblogs.com/huiwenhua/p/10984352.html
Copyright © 2011-2022 走看看