【uniapp-template】基于uniapp的微信小程序、H5开发实用模板

1,388 阅读2分钟

介绍

✌️一个基于uniapp快速开发微信小程序、H5(其他平台没有特地去兼容,也没有进行相关的测试)项目的模板,无过度封装,容易上手。 (gitee.com)

主要依赖

目录结构

  • 🦚api:项目中使用到的接口请求Api。
  • 🐦‍🔥components:开发者封装的全局组件(只在个别页面用到的组件请放到对应模块的目录下)。
  • 🪿config:项目中用到的一些配置如env相关的配置,以及前端用到的字典也在这里配置。
  • 🐦‍⬛pages:存放应用的页面文件,为了便于后期分包配置,请合理组织目录结构(推荐的方式:“index”目录下仅存放“tabBar”相关的页面文件,其他页面根据模块组织目录结构,具体可以查看项目中的示例)。
  • 🦤static:用于存放应用使用到的静态资源,如图片、字体文件等。
  • 🐣store:存放 vuex 的状态管理相关文件。
  • 🐝uni_modules:存放通过HBuilderX安装的项目插件
  • 🐜utils:工具库,用来存放项目中可能用到的工具类函数
  • 🦗unpackage:打包目录,存放打包后的文件。

项目特色

  • 🦂env:环境配置使得开发者能够根据不同的环境进行更精细化的控制。
  • 🦓subPackages:配合pages合理的目录结构很容易可以做到按功能分包。
  • 🪲request:基于 uView 集成的优秀开源请求库 luch-request (quanzhan.co) 封装了项目统一的请求方法 $http,可以根据实际情况开启接口请求是否loading、请求是否携带token、以及需要token时对未登录、以及token失效的情况进行拦截。
  • 🪱有配套后端:搭配用于演示功能的后端项目,能更快的上手本项目,并且后端采用nodejs开发使得前端开发能够 0学习成本 启动项目。
  • 🐴store:项目中已经使用vuex分模块实现应用状态管理,目前已有app和user的示例。
  • 🪰d-list: 内置了基于uView list 封装的高性能且易于使用的业务常用分页列表组件,轻松实现触底加载功能。

安装教程

  1. 克隆项目

    git clone https://gitee.com/d760358962/uniapp-template.git
    
  2. 安装项目依赖 (当前版本并无 node_modules 依赖,可以跳过这一步)

    npm install
    
  3. 下载安装:HBuilderX

  4. 将项目用HBuilderX打开

  5. 启动配套的用于演示功能的后端项目uniapp-template-backend: uniapp-template 配套后端 (gitee.com)

  6. 如果要开发微信小程序

    1. 下载安装:微信开发者工具
    2. 扫码登陆微信开发者工具
    3. 运行 - 微信小程序 - 完成
  7. 如果要开发H5

    1. 运行 - 根据情况选择浏览器 - 完成
  8. 推荐安装 eslint-js、eslint-plugin-vue 规范团队代码风格

部分功能代码示例

  • env多环境配置

    // 生产环境
    const production = {
      baseUrl: `https://localhost:7002/`,
    };
    
    // 开发环境'
    const development = {
      baseUrl: `http://localhost:7001/`,
    };
    
    const config = {
      development,
      production,
    };
    export default config[process.env.NODE_ENV];
    
  • 请求后端数据

    export function userLogin(data) {
      return $http.post('/users/login', data, {
        custom: {
          auth: false
        }
      })
    }
    
    export function getNewsByUser(params) {
      return $http.get('/news/getNewsByUser', {
        params
      })
    }
    
    import env from "@/config/env.js";
    import store from "@/store";
    
    // 显示请求错误信息
    const showRequestError = (e) => {
      let errMsg = e.errMsg || "系统繁忙!";
      // #ifdef MP-WEIXIN
      if (e.errMsg === "request:fail url not in domain list") {
        errMsg = "当前API域名未添加到微信小程序授权名单";
      }
      // #endif
      if (e.errMsg.startsWith("request:fail")) {
        errMsg = "网络请求错误:请检查请求的API地址能否正常访问";
      }
      uni.showToast({
        title: errMsg,
        icon: "none",
        duration: 3000,
      });
    };
    
    // 处理未登录或登录失效的情况
    const handleNotLogin = (msg) => {
      uni.showModal({
        title: "提示",
        content: msg || "请登录后再进行操作",
        success({
          confirm,
          cancel
        }) {
          if (confirm) {
            uni.redirectTo({
              url: "/pages/login/index",
            });
          }
          if (cancel) {
            uni.switchTab({
              url: "/pages/index/home/index",
            });
          }
        },
      });
    };
    
    const $http = uni.$u.http;
    
    $http.setConfig((config) => {
      /* config 为默认全局配置 */
      config.baseURL = env.baseUrl; // 根域名
      /* 可以加一些自定义参数,在拦截器等地方使用 */
      config.custom = {
        // 如果true就传token
        auth: true,
        // 是否显示加载动画
        loading: true,
      };
      return config;
    });
    
    /* 请求拦截器 */
    $http.interceptors.request.use(
      (config) => {
        // 可使用async await 做异步操作
        if (config.custom.auth) {
          if (!store.getters.token) {
            handleNotLogin();
            // 如果token不存在,return Promise.reject(config) 会取消本次请求
            return Promise.reject({
              config,
              errMsg: "请登录后再进行操作",
            });
          }
          config.header.authorization = store.getters.token;
        }
        /* 显示加载动画 */
        if (config.custom.loading) {
          uni.showLoading({
            mask: true
          });
        }
        return config;
      },
      (config) => {
        // 可使用async await 做异步操作
        return Promise.reject(config);
      }
    );
    
    /* 响应拦截器 */
    $http.interceptors.response.use(
      (response) => {
        /* 对响应成功做点什么 可使用async await 做异步操作*/
        if (response.data.code !== 200) {
          if (response.data.code === 401) {
            response.errMsg = "请登录后再进行操作";
            handleNotLogin();
          }
          if (response.data.code === 10001) {
            response.errMsg = "登录已失效,请重新登录后再进行操作";
            handleNotLogin("登录已失效,请重新登录后再进行操作");
          }
    
          if (response.config.custom.loading) {
            uni.hideLoading();
          }
          showRequestError(response);
          // 服务端返回的状态码不等于200,则reject()
          return Promise.reject(response); // return Promise.reject 可使promise状态进入catch
        }
        /* 关闭加载动画 */
        if (response.config.custom.loading) {
          uni.hideLoading();
        }
        console.log(response);
        return response.data;
      },
      (response) => {
        /*  对响应错误做点什么 (statusCode !== 200)*/
        if (response.config.custom.loading) {
          uni.hideLoading();
        }
    
        showRequestError(response);
        console.log(response);
        return Promise.reject(response);
      }
    );
    
    export default $http;