0.基础准备

node、npm

1.环境安装

全局安装vue-cli(已装忽略)

  1. npm install -g @vue/cli

2.创建uni-app基础框架

创建正式版

  1. vue create -p dcloudio/uni-preset-vue my-project(项目名字)

之后,会提示选择项目模板,搭建框架选择默认模板
image.png
创建完成后,会生成对应名字的vue cli3项目,这个就是uni-app框架的基础,需要在此基础上改造,以适应日常开发情景。
image.png

3.启动vue cli3图形界面

vue cli3图形界面

  1. vue ui

image.png
image.png

4.安装依赖

需要安装以下依赖:

  1. 样式预处理器(使用的是sass,也可以使用less等)
  2. node-sass sass-loader

以node-sass为例,演示安装步骤:
1.在vue cli3图形界面中的左侧菜单选中【依赖】,点击右侧【安装依赖】按钮
image.png
2.在弹出的对话框中选择【运行依赖】【开发依赖】,node-sass是开发依赖,所以选择开发依赖,然后在搜索框中搜索node-sass
image.png
3.选择需要的node-sass依赖,点击对话框右下角的【安装node-sass】
image.png
4.在终端中会显示正在安装依赖
image.png
5.安装完成后,在【依赖】菜单中可以看到刚刚安装好的依赖
image.png
6.在项目的package.json中,会增加刚刚安装好的依赖,到此,说明依赖安装成功
image.png

5.安装插件

1.在vue cli3图形界面中的左侧菜单选中【插件】,可以看到已经安装的插件
image.png
2.点击右侧【添加插件】按钮
image.png
3.打开添加插件后可以看到默认选中了【所有插件】
image.png
4.在搜索框中输入eslint,按下回车键搜索,在搜索结果中选中@vue/cli-plugin-eslint插件,然后点击【安装】
image.png
5.在终端中会显示正在安装插件
image.png
6.插件安装完成后,会进入【配置插件】面板
image.png
7.点击右侧【selected】下拉选择框,选中【standard】风格(可以根据自己的项目选择合适的风格)
image.png
8.点击【完成安装】按钮
image.png
9.可以看到正在安装相关依赖
image.png
10.安装完成后会进入【文件改动】面板,点击【继续】按钮即可
image.png
11.可以看到插件已经安装完成
image.png
12.在项目的package.json中,会增加刚刚安装好的插件和依赖,到此,说明插件安装成功
image.png

6.添加配置

1.eslintignore配置
在根路径下添加【.eslintignore】文件,设置忽略eslint检查文件
image.png
在【.eslintignore】文件中写入以下内容即可

  1. dist/*
  2. plugins/*
  3. node_modules/*

image.png
2.eslint配置
image.png
在.eslintrc.js文件中写入以下内容(可以根据需要配置eslint规则)

  1. module.exports = {
  2. root: true,
  3. env: {
  4. browser: true,
  5. node: true
  6. },
  7. extends: [
  8. 'plugin:vue/essential',
  9. '@vue/standard'
  10. ],
  11. globals: {
  12. Vue: true,
  13. uni: true,
  14. wx: true,
  15. getApp: true,
  16. feConfig: true,
  17. Util: true,
  18. Enums: true
  19. },
  20. parserOptions: {
  21. parser: 'babel-eslint'
  22. },
  23. // add your custom rules here
  24. rules: {
  25. // js
  26. 'indent': ['off', 4],
  27. // 开启语句强制分号结尾
  28. 'semi': ["error", "always"],
  29. // 函数前面的空格
  30. "space-before-function-paren": ["error", {
  31. "anonymous": "never",
  32. "named": "never",
  33. "asyncArrow": "never"
  34. }],
  35. // allow paren-less arrow functions
  36. 'arrow-parens': 0,
  37. // allow async-await
  38. 'generator-star-spacing': 0,
  39. // only allow console in development
  40. 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
  41. // allow debugger during development
  42. 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
  43. //
  44. // Vue 可能的错误
  45. //
  46. // 禁止重复的二级键名
  47. 'vue/no-dupe-keys': 'error',
  48. // 禁止出现语法错误
  49. 'vue/no-parsing-error': 'error',
  50. // 禁止覆盖保留字
  51. // 'vue/no-reservered-keys': 'error',
  52. // 组件的 data 属性的值必须是一个函数
  53. // @off 没必要限制
  54. 'vue/no-shared-component-data': 'error',
  55. // 可以让 <template> 使用 key 属性
  56. 'vue/no-template-key': 'off',
  57. // render 函数必须有返回值
  58. 'vue/require-render-return': 'error',
  59. // prop 的默认值必须匹配它的类型
  60. 'vue/require-valid-default-prop': 'error',
  61. // 计算属性必须有返回值
  62. 'vue/return-in-computed-property': 'error',
  63. // template 的根节点必须合法
  64. 'vue/valid-template-root': 'error',
  65. // v-bind 指令必须合法
  66. 'vue/valid-v-bind': 'error',
  67. // v-cloak 指令必须合法
  68. 'vue/valid-v-cloak': 'error',
  69. // v-else-if 指令必须合法
  70. 'vue/valid-v-else-if': 'error',
  71. // v-else 指令必须合法
  72. 'vue/valid-v-else': 'error',
  73. // v-for 指令必须合法
  74. 'vue/valid-v-for': 'error',
  75. // v-html 指令必须合法
  76. 'vue/valid-v-html': 'error',
  77. // v-if 指令必须合法
  78. 'vue/valid-v-if': 'error',
  79. // v-model 指令必须合法
  80. 'vue/valid-v-model': 'error',
  81. // v-on 指令必须合法
  82. 'vue/valid-v-on': 'error',
  83. // v-once 指令必须合法
  84. 'vue/valid-v-once': 'error',
  85. // v-pre 指令必须合法
  86. 'vue/valid-v-pre': 'error',
  87. // v-show 指令必须合法
  88. 'vue/valid-v-show': 'error',
  89. // v-text 指令必须合法
  90. 'vue/valid-v-text': 'error',
  91. //
  92. //
  93. // 最佳实践
  94. //
  95. // @fixable html 的结束标签必须符合规定
  96. // 有的标签不必严格符合规定,如 <br> 或 <br/> 都应该是合法的, 在此列为警告
  97. 'vue/html-end-tags': 'off',
  98. // 计算属性禁止包含异步方法
  99. 'vue/no-async-in-computed-properties': 'error',
  100. // 禁止出现难以理解的 v-if 和 v-for
  101. 'vue/no-confusing-v-for-v-if': 'error',
  102. // 禁止出现重复的属性
  103. 'vue/no-duplicate-attributes': 'error',
  104. // 禁止在计算属性中对属性修改, 是具体情况而定,有时候可能会用到,列为warn;
  105. 'vue/no-side-effects-in-computed-properties': 'warn',
  106. // 禁止在 <textarea> 中出现 {{message}}
  107. 'vue/no-textarea-mustache': 'error',
  108. // 组件的属性必须为一定的顺序
  109. 'vue/order-in-components': [2, {
  110. "order": [
  111. "el",
  112. ["name", "parent"],
  113. "functional",
  114. "delimiters",
  115. ["components", "directives", "filters"],
  116. ["extends", "mixins"],
  117. ["model", "props", "propsData"],
  118. ["data", "computed"],
  119. ["watch", "LIFECYCLE_HOOKS"],
  120. "methods",
  121. ["template", "render", "renderError"]
  122. ]
  123. }],
  124. // <component> 必须有 v-bind:is
  125. 'vue/require-component-is': 'error',
  126. // prop 必须有类型限制
  127. 'vue/require-prop-types': 'error',
  128. // v-for 指令的元素必须有 v-bind:key
  129. 'vue/require-v-for-key': 'error',
  130. //
  131. //
  132. // 风格问题
  133. //
  134. // @fixable 限制自定义组件的属性风格, Vue风格指南强烈建议,但和一般习惯差别略大,列为warn;
  135. 'vue/attribute-hyphenation': 'warn',
  136. // html 属性值必须用双引号括起来
  137. 'vue/html-quotes': 'error',
  138. // @fixable 没有内容时,组件必须自闭和。只要闭合即可,不限制。
  139. 'vue/html-self-closing': 'off',
  140. // 限制每行允许的最多属性数量
  141. // @off 没必要限制。但多行时应该每行一个属性。
  142. 'vue/max-attributes-per-line': 'off',
  143. // @fixable 限制组件的 name 属性的值的风格
  144. 'vue/name-property-casing': 'error',
  145. // @fixable 要求花括号插值两边必须有空格
  146. 'vue/mustache-interpolation-spacing': 'error',
  147. // @fixable 禁止出现连续空格
  148. 'vue/no-multi-spaces': 'error',
  149. // @fixable 限制 v-bind 的风格, 统一简写形式
  150. 'vue/v-bind-style': 'error',
  151. // @fixable 限制 v-on 的风格,统一简写形式
  152. 'vue/v-on-style': 'error',
  153. //
  154. //
  155. // 变量
  156. //
  157. // 定义了的 jsx element 必须使用
  158. 'vue/jsx-uses-vars': 'error',
  159. 'no-tabs': 'off'
  160. }
  161. }

3.开发环境配置
在【src】目录下新建【feConfig】目录
image.png
在【feConfig】目录下新建development.js、production.js、test.js三个文件分别对应开发环境、正式环境、测试环境
image.png
在三个文件内分别写入以下内容

  1. // development.js
  2. module.exports = {
  3. api: {
  4. // #ifndef H5
  5. base: 'https://www.fastmock.site/mock/b0e7c0fd4d0c17abe3d7bda7f9be5104/demo'
  6. // #endif
  7. }
  8. };
  9. // production.js
  10. module.exports = {
  11. api: {
  12. base: 'https://www.fastmock.site/mock/b0e7c0fd4d0c17abe3d7bda7f9be5104/demo'
  13. }
  14. };
  15. // test.js
  16. module.exports = {
  17. api: {
  18. base: 'https://www.fastmock.site/mock/b0e7c0fd4d0c17abe3d7bda7f9be5104/demo'
  19. }
  20. };

小贴士:https://www.fastmock.site是一个免费的mock数据平台

4.vue.config配置(先创建好文件,后面会详细讲解配置)
在根路径下添加【vue.config.js】文件,增加cli配置
image.png
写入以下内容

  1. const path = require('path');
  2. const webpack = require('webpack');
  3. const configEnv = process.env.CONFIG_ENV;
  4. module.exports = {
  5. devServer: {
  6. host: '0.0.0.0',
  7. port: 8080,
  8. open: true,
  9. proxy: {
  10. '/v1': {
  11. target: 'https://www.fastmock.site/mock/b0e7c0fd4d0c17abe3d7bda7f9be5104/demo',
  12. changeOrigin: true
  13. },
  14. '/v2': {
  15. target: 'https://www.fastmock.site/mock/b0e7c0fd4d0c17abe3d7bda7f9be5104/demo',
  16. changeOrigin: true
  17. }
  18. },
  19. disableHostCheck: true
  20. },
  21. configureWebpack: {
  22. plugins: [
  23. new webpack.ProvidePlugin({
  24. feConfig: path.resolve('.', './src/feConfig/' + (configEnv || 'development')),
  25. Util: path.resolve('.', './src/utils/util'),
  26. Enums: path.resolve('.', './src/contants/enum')
  27. })
  28. ]
  29. },
  30. transpileDependencies: ['luch-request']
  31. };

7.配置启动脚本

在项目的package.json中,可以看到【scripts】,启动脚本需要在里面配置。默认的命令有两类,dev和build,对应开发环境和生产环境,一般项目开发还需要测试环境,所以需要对启动命令进行改进
image.png
如何配置测试环境呢?
首先需要知道【环境变量】的概念,在node中通过process.env.NODE_ENV的值区分运行环境也就是【NODE_ENV】参数的值。在vue cli3中,【NODE_ENV】的值默认支持development和production两种,对应开发及生产环境。
想要支持测试环境,我们可以自己定义一个变量来区分当前运行环境,如:【CONFIG_ENV】,值为development、test、production,对应开发、测试、生成环境。
对应修改调整启动脚本如下:

  1. "scripts": {
  2. "serve": "npm run dev:h5",
  3. "test": "npm run test:h5",
  4. "build": "npm run build:h5",
  5. "dev:h5": "cross-env CONFIG_ENV=development NODE_ENV=development UNI_PLATFORM=h5 vue-cli-service uni-serve",
  6. "dev:mp-weixin": "cross-env CONFIG_ENV=development NODE_ENV=development UNI_PLATFORM=mp-weixin vue-cli-service uni-build --watch",
  7. "dev:mp-360": "cross-env CONFIG_ENV=development NODE_ENV=development UNI_PLATFORM=mp-360 vue-cli-service uni-build --watch",
  8. "dev:mp-alipay": "cross-env CONFIG_ENV=development NODE_ENV=development UNI_PLATFORM=mp-alipay vue-cli-service uni-build --watch",
  9. "dev:mp-baidu": "cross-env CONFIG_ENV=development NODE_ENV=development UNI_PLATFORM=mp-baidu vue-cli-service uni-build --watch",
  10. "dev:mp-kuaishou": "cross-env CONFIG_ENV=development NODE_ENV=development UNI_PLATFORM=mp-kuaishou vue-cli-service uni-build --watch",
  11. "dev:mp-qq": "cross-env CONFIG_ENV=development NODE_ENV=development UNI_PLATFORM=mp-qq vue-cli-service uni-build --watch",
  12. "dev:mp-toutiao": "cross-env CONFIG_ENV=development NODE_ENV=development UNI_PLATFORM=mp-toutiao vue-cli-service uni-build --watch",
  13. "dev:quickapp-native": "cross-env CONFIG_ENV=development NODE_ENV=development UNI_PLATFORM=quickapp-native vue-cli-service uni-build --watch",
  14. "dev:quickapp-webview": "cross-env CONFIG_ENV=development NODE_ENV=development UNI_PLATFORM=quickapp-webview vue-cli-service uni-build --watch",
  15. "dev:quickapp-webview-huawei": "cross-env CONFIG_ENV=development NODE_ENV=development UNI_PLATFORM=quickapp-webview-huawei vue-cli-service uni-build --watch",
  16. "dev:quickapp-webview-union": "cross-env CONFIG_ENV=development NODE_ENV=development UNI_PLATFORM=quickapp-webview-union vue-cli-service uni-build --watch",
  17. "dev:app-plus": "cross-env CONFIG_ENV=development NODE_ENV=development UNI_PLATFORM=app-plus vue-cli-service uni-build --watch",
  18. "dev:custom": "cross-env CONFIG_ENV=development NODE_ENV=development uniapp-cli custom",
  19. "test:h5": "cross-env CONFIG_ENV=test NODE_ENV=production UNI_PLATFORM=h5 vue-cli-service uni-build",
  20. "test:mp-weixin": "cross-env CONFIG_ENV=test NODE_ENV=production UNI_PLATFORM=mp-weixin vue-cli-service uni-build",
  21. "test:mp-360": "cross-env CONFIG_ENV=test NODE_ENV=production UNI_PLATFORM=mp-360 vue-cli-service uni-build",
  22. "test:mp-alipay": "cross-env CONFIG_ENV=test NODE_ENV=production UNI_PLATFORM=mp-alipay vue-cli-service uni-build",
  23. "test:mp-baidu": "cross-env CONFIG_ENV=test NODE_ENV=production UNI_PLATFORM=mp-baidu vue-cli-service uni-build",
  24. "test:mp-kuaishou": "cross-env CONFIG_ENV=test NODE_ENV=production UNI_PLATFORM=mp-kuaishou vue-cli-service uni-build",
  25. "test:mp-qq": "cross-env CONFIG_ENV=test NODE_ENV=production UNI_PLATFORM=mp-qq vue-cli-service uni-build",
  26. "test:mp-toutiao": "cross-env CONFIG_ENV=test NODE_ENV=production UNI_PLATFORM=mp-toutiao vue-cli-service uni-build",
  27. "test:quickapp-native": "cross-env CONFIG_ENV=test NODE_ENV=production UNI_PLATFORM=quickapp-native vue-cli-service uni-build",
  28. "test:quickapp-webview": "cross-env CONFIG_ENV=test NODE_ENV=production UNI_PLATFORM=quickapp-webview vue-cli-service uni-build",
  29. "test:quickapp-webview-huawei": "cross-env CONFIG_ENV=test NODE_ENV=production UNI_PLATFORM=quickapp-webview-huawei vue-cli-service uni-build",
  30. "test:quickapp-webview-union": "cross-env CONFIG_ENV=test NODE_ENV=production UNI_PLATFORM=quickapp-webview-union vue-cli-service uni-build",
  31. "test:app-plus": "cross-env CONFIG_ENV=test NODE_ENV=production UNI_PLATFORM=app-plus vue-cli-service uni-build",
  32. "test:custom": "cross-env CONFIG_ENV=test NODE_ENV=production uniapp-cli custom",
  33. "build:h5": "cross-env CONFIG_ENV=production NODE_ENV=production UNI_PLATFORM=h5 vue-cli-service uni-build",
  34. "build:mp-weixin": "cross-env CONFIG_ENV=production NODE_ENV=production UNI_PLATFORM=mp-weixin vue-cli-service uni-build",
  35. "build:mp-360": "cross-env CONFIG_ENV=production NODE_ENV=production UNI_PLATFORM=mp-360 vue-cli-service uni-build",
  36. "build:mp-alipay": "cross-env CONFIG_ENV=production NODE_ENV=production UNI_PLATFORM=mp-alipay vue-cli-service uni-build",
  37. "build:mp-baidu": "cross-env CONFIG_ENV=production NODE_ENV=production UNI_PLATFORM=mp-baidu vue-cli-service uni-build",
  38. "build:mp-kuaishou": "cross-env CONFIG_ENV=production NODE_ENV=production UNI_PLATFORM=mp-kuaishou vue-cli-service uni-build",
  39. "build:mp-qq": "cross-env CONFIG_ENV=production NODE_ENV=production UNI_PLATFORM=mp-qq vue-cli-service uni-build",
  40. "build:mp-toutiao": "cross-env CONFIG_ENV=production NODE_ENV=production UNI_PLATFORM=mp-toutiao vue-cli-service uni-build",
  41. "build:quickapp-native": "cross-env CONFIG_ENV=production NODE_ENV=production UNI_PLATFORM=quickapp-native vue-cli-service uni-build",
  42. "build:quickapp-webview": "cross-env CONFIG_ENV=production NODE_ENV=production UNI_PLATFORM=quickapp-webview vue-cli-service uni-build",
  43. "build:quickapp-webview-huawei": "cross-env CONFIG_ENV=production NODE_ENV=production UNI_PLATFORM=quickapp-webview-huawei vue-cli-service uni-build",
  44. "build:quickapp-webview-union": "cross-env CONFIG_ENV=production NODE_ENV=production UNI_PLATFORM=quickapp-webview-union vue-cli-service uni-build",
  45. "build:app-plus": "cross-env CONFIG_ENV=production NODE_ENV=production UNI_PLATFORM=app-plus vue-cli-service uni-build",
  46. "build:custom": "cross-env CONFIG_ENV=production NODE_ENV=production uniapp-cli custom",
  47. "serve:quickapp-native": "node node_modules/@dcloudio/uni-quickapp-native/bin/serve.js",
  48. "jest:android": "cross-env UNI_PLATFORM=app-plus UNI_OS_NAME=android jest -i",
  49. "jest:h5": "cross-env UNI_PLATFORM=h5 jest -i",
  50. "jest:ios": "cross-env UNI_PLATFORM=app-plus UNI_OS_NAME=ios jest -i",
  51. "jest:mp-baidu": "cross-env UNI_PLATFORM=mp-baidu jest -i",
  52. "jest:mp-weixin": "cross-env UNI_PLATFORM=mp-weixin jest -i",
  53. "lint": "vue-cli-service lint",
  54. "info": "node node_modules/@dcloudio/vue-cli-plugin-uni/commands/info.js"
  55. }

其中【CONFIG_ENV】的值对应运行环境,如何识别CONFIG_ENV的值去区分环境呢?
在【vue.config.js】文件中定义了变量接收CONFIG_ENV的值,区分开发环境,代码如下:

  1. const path = require('path');
  2. const webpack = require('webpack');
  3. const configEnv = process.env.CONFIG_ENV; // 环境变量
  4. ...
  5. ...
  6. // 注入全局依赖,根据环境加载不同的文件,区分不同的运行环境
  7. configureWebpack: {
  8. plugins: [
  9. new webpack.ProvidePlugin({
  10. feConfig: path.resolve('.', './src/feConfig/' + (configEnv || 'development'))
  11. ...
  12. })
  13. ]
  14. }

到此,项目的基础功能就完成了,运行

  1. npm run serve

在浏览器中我们可以看到demo页面
image.png
在项目开发中,通常会配置启动端口和代理,在【vue.config.js】文件中加入以下代码即可配置成功

  1. ...
  2. ...
  3. module.exports = {
  4. devServer: {
  5. host: '0.0.0.0',
  6. port: 8080,
  7. open: true,
  8. proxy: {
  9. '/v1': {
  10. target: 'https://www.fastmock.site/mock/b0e7c0fd4d0c17abe3d7bda7f9be5104/demo',
  11. changeOrigin: true
  12. },
  13. '/v2': {
  14. target: 'https://www.fastmock.site/mock/b0e7c0fd4d0c17abe3d7bda7f9be5104/demo',
  15. changeOrigin: true
  16. }
  17. },
  18. disableHostCheck: true
  19. }
  20. ...
  21. ...
  22. };

8.uView

uni-app生态非常丰富,uView是uni-app生态中优秀的UI框架,组件丰富,可以极大地提高开发效率,你也可以选择其它优秀的UI库,例如:uni-ui
在脚手架中如何安装配置uView呢?
1.使用npm形式安装(也可以选择下载后放入项目)

  1. npm install uview-ui

2.引入uView主JS库
在项目根目录中的main.js中,引入并使用uView的JS库,注意这两行要放在import Vue之后

  1. // main.js
  2. import uView from "uview-ui";
  3. Vue.use(uView);

3.在引入uView的全局SCSS主题文件
在项目根目录的uni.scss中引入此文件

  1. /* uni.scss */
  2. @import 'uview-ui/theme.scss';

4.引入uView基础样式
在App.vue中首行的位置引入,注意给style标签加入lang=”scss”属性

  1. <style lang="scss">
  2. /* 注意要写在第一行,同时给style标签加入lang="scss"属性 */
  3. @import "uview-ui/index.scss";
  4. </style>

5.配置easycom组件模式(easycom可以在页面直接使用组件,无需通过import引入组件)
此配置需要在项目根目录的pages.json中进行

  1. // pages.json
  2. {
  3. "easycom": {
  4. "^u-(.*)": "uview-ui/components/u-$1/u-$1.vue"
  5. },
  6. // 此为本身已有的内容
  7. "pages": [
  8. // ......
  9. ]
  10. }

配置完成后,即可正常使用组件
image.png
image.png

9.luch-request

开发小程序痛点之一就是发起请求,wx.request太过简单,没有类似axios的请求拦截器和响应拦截器,在需要对请求做统一处理、复杂处理时有明显短板,诸如请求loading、cookie、token二次请求、响应状态码统一处理等,需要自己在wx.request基础上大量封装,uni-app中uni.request除了上述问题外,还需要在h5平台携带跨域凭证,使问题变得更加地复杂,无法满足项目级开发要求。
luch-request是基于Promise开发的uni-app跨平台请求库,它解决了使用uni.request的诸多问题,易用、简单、高度自定义,是一个特别用在项目级别的请求库。
在脚手架中如何安装配置luch-request呢?
1.使用npm安装

  1. npm i luch-request -S

2.在【vue.config.js】文件中,增加以下内容

  1. // vue.config.js
  2. module.exports = {
  3. transpileDependencies: ['luch-request']
  4. }

至此,安装完成,如何体现它的诸多优点呢?
1.在【src】目录下新建【utils】文件夹
image.png
2.在【utils】文件夹下新增promisify.js、token.js
image.png
分别写入以下代码

  1. // promisify.js
  2. // 普通函数转promise
  3. module.exports = fn => {
  4. return function(obj = {}) {
  5. return new Promise((resolve, reject) => {
  6. fn({ ...obj, success(res) { resolve(res); }, fail(res) { reject(res); } });
  7. });
  8. };
  9. };
  10. // token.js
  11. import promisify from './promisify.js';
  12. import { http } from '@/plugins/luch-request/config.js';
  13. /**
  14. * 获取token
  15. */
  16. const getToken = () => {
  17. const login = promisify(uni.login);
  18. // #ifndef H5
  19. return login().then(resCode => {
  20. return http.post(feConfig.token, {
  21. data: {
  22. grant_type: 'wx_login',
  23. username: feConfig.appid,
  24. password: resCode.code
  25. },
  26. header: {
  27. 'Content-Type': 'application/x-www-form-urlencoded',
  28. Authorization: 'Basic ' + feConfig.client_base64
  29. }
  30. });
  31. });
  32. // #endif
  33. };
  34. module.exports = {
  35. getToken
  36. };

3.util.js是常用工具函数库,可以放一些常用函数在全局引用

  1. // vue.config.js
  2. ...
  3. ...
  4. configureWebpack: {
  5. plugins: [
  6. new webpack.ProvidePlugin({
  7. Util: path.resolve('.', './src/utils/util') // 全局注入Util
  8. })
  9. ]
  10. }

4.在【src】目录下新建【plugins】文件夹
image.png
5.在【plugins】下新建【luch-request】目录,并在【luch-request】下新建【config.js】文件
image.png
6.在【config.js】文件写入以下内容

  1. /**
  2. * 文档: https://www.quanzhan.co/luch-request/
  3. * github: https://github.com/lei-mu/luch-request
  4. * DCloud: http://ext.dcloud.net.cn/plugin?id=392
  5. */
  6. import Request from 'luch-request';
  7. import Token from '../../utils/token.js';
  8. const http = new Request();
  9. /**
  10. * 全局默认配置
  11. * @param {Object} config 发送请求的配置数据
  12. */
  13. http.setConfig(config => {
  14. config.baseURL = feConfig.api.base; // 根路径
  15. config.header = { // 请求头
  16. // 'X-Auth-Token': 'xxxx',
  17. // contentType: "application/x-www-form-urlencoded"
  18. 'Content-Type': 'application/json'
  19. };
  20. config.custom = { // 自定义参数,如果局部custom与全局custom有同名属性,则后面的属性会覆盖前面的属性,相当于Object.assign(全局,局部)
  21. loading: true // 默认全局请求开启loading
  22. };
  23. config.withCredentials = true; // 跨域请求时携带凭证(cookies)仅H5支持(HBuilderX 2.6.15+)
  24. return config;
  25. });
  26. /**
  27. * 请求拦截器
  28. * @param {Object} config 发送请求的配置数据
  29. */
  30. http.interceptors.request.use(config => {
  31. config.custom.loading && uni.showLoading({ title: '加载中', mask: true }); // 请求配置中的custom自定义参数中loading为true则显示loading
  32. getToken() && (config.header.token = getToken()); // 有token则在请求头中携带token
  33. getCookie() && (config.header.cookie = getCookie()); // 有cookie则在请求头中携带cookie,h5中浏览器默认携带cookie,此方法不生效,小程序中需手动携带cookie
  34. return config;
  35. }, err => {
  36. showToast(err);
  37. uni.hideLoading();
  38. return Promise.reject(err);
  39. });
  40. /**
  41. * 响应拦截器
  42. * @param {Object} res 请求返回的数据
  43. */
  44. http.interceptors.response.use(async res => {
  45. let data = res.hasOwnProperty('data') ? res.data : res.hasOwnProperty('Data') ? res.Data : null; // eslint-disable-line
  46. let code = data.hasOwnProperty('code') ? data.code : data.hasOwnProperty('Code') ? data.Code : null; // eslint-disable-line
  47. saveCookie(res.header['set-cookie'] || res.header['Set-Cookie']); // 手动种cookie,h5中浏览器自动种cookie,小程序中需手动中cookie
  48. try {
  49. return await handleCode({ data, code, res });
  50. } catch (err) {
  51. uni.hideLoading();
  52. return Promise.reject(err);
  53. }
  54. }, err => {
  55. return Promise.reject(err);
  56. });
  57. /**
  58. * 处理 http状态码
  59. * @param {object} o
  60. * @param {object} o.data 请求返回的数据
  61. * @param {string|number} o.code http状态码
  62. * @param {object} o.res 本次请求的配置和返回数据
  63. * @return {object|Promise<reject>}
  64. */
  65. function handleCode({ data, code, res }) {
  66. const STATUS = {
  67. '0'() { // 请求成功
  68. return data;
  69. },
  70. '1000'() { // token过期,重新获取token
  71. return getApiToken().then(saveToken).then(() => http.request(res.config));
  72. }
  73. };
  74. uni.hideLoading();
  75. return STATUS[code] ? STATUS[code]() : Promise.reject(data, res); // 有状态码但不在这个封装的配置里,就直接进入 `fail`
  76. }
  77. /**
  78. * 获取 `localStorage` 中的 `cookie`
  79. * @return {string} cookie字符串
  80. */
  81. function getCookie() {
  82. return uni.getStorageSync('cookie');
  83. }
  84. /**
  85. * 保存 `cookie` 到 `localStorage`
  86. * @param {string} cookie cookie字符串
  87. * @return {void}
  88. */
  89. function saveCookie(cookie) {
  90. cookie && uni.setStorageSync('cookie', cookie);
  91. }
  92. /**
  93. * 重新请求更新获取 `token`
  94. * @return {Promise}
  95. */
  96. function getApiToken() {
  97. return Token.getToken().then((res) => {
  98. return res.token;
  99. });
  100. }
  101. /**
  102. * 获取 `localStorage` 中的 `token`
  103. * @return {string} token字符串
  104. */
  105. function getToken() {
  106. return uni.getStorageSync('token');
  107. }
  108. /**
  109. * 保存 `token` 到 `localStorage`
  110. * @param {string} token token字符串
  111. * @return {void}
  112. */
  113. function saveToken(token) {
  114. uni.setStorageSync('token', token);
  115. }
  116. /**
  117. * 显示消息提示框
  118. * @param {String} msg
  119. * @return {void}
  120. */
  121. function showToast(msg) {
  122. uni.showToast({
  123. title: msg,
  124. icon: 'none',
  125. duration: 2000
  126. });
  127. }
  128. export { http };

7.在【src】下【main.js】中增加以下内容

  1. // main.js
  2. import { http } from '@/plugins/luch-request/config.js';
  3. Vue.prototype.$http = http;

8.在项目中使用

  1. this.$http.post('/v1/token').then(res => {
  2. console.log('%c 🍏 res: ', 'font-size:20px;background-color: #F5CE50;color:#fff;', res);
  3. }).catch(err => {
  4. console.log('%c 🥜 err: ', 'font-size:20px;background-color: #33A5FF;color:#fff;', err);
  5. });

10.uCharts

开发小程序的痛点之一就是图表,wx-charts配色差、适用性差,echarts小程序版,体积大、bug多,F2上手难度大、体积大,在uni-app的生态中,UCharts是一个出色的跨端图表库。
在脚手架中如何安装配置UCharts呢?
1.在【src】目录下新建【components】文件夹
image.png
2.下载UCharts代码,放入【components】的UCharts目录中
image.png
3.在项目中使用

  1. import uCharts from '../../components/u-charts/u-charts.js';

11.contants

在项目开发中,会有一些常量,可以放在【contants】目录
如枚举值可以新建一个【enum.js】存放
image.png
在【vue.config.js】文件中注入全局依赖Enums,然后就可以在全局使用

  1. // 注入全局依赖,根据环境加载不同的文件,区分不同的运行环境
  2. configureWebpack: {
  3. plugins: [
  4. new webpack.ProvidePlugin({
  5. Enums: path.resolve('.', './src/contants/enum')
  6. })
  7. ]
  8. }

12.参考文档

uni-app快速上手:https://uniapp.dcloud.io/quickstart?id=_2-%e9%80%9a%e8%bf%87vue-cli%e5%91%bd%e4%bb%a4%e8%a1%8c
uView:https://uviewui.com
luch-request:https://www.quanzhan.co/luch-request
uCharts:http://doc.ucharts.cn/1073940

13.结语

按文档配置只是入门,想要有更深入的了解,需要思考为什么使用uView、luch-request、uCharts,有没有更好的组件插件,这些组件插件为什么这样配置,目录结构为什么是这样的,可不可以换一种方式,等等,凡事多问一个为什么,看其表象,究其本质。
当然,初次学习可以按部就班按照文档一步步学习,虽然不明所以,但是多次尝试后自然就会明白其中奥秘与精髓。

水平有限,仓促书写,难免错漏,欢迎指正。