cli 创建 uni-app

1,252 阅读2分钟

环境安装

全局安装 vue 脚手架

npm install -g @vue/cli

创建 uniapp

使用正式版

vue create -p dcloudio/uni-preset-vue my-project

使用 alpha 版

vue create -p dcloudio/uni-preset-vue#alpha my-alpha-project

等待下载一万年......之后出现如下图,可以选择子集想要的模板,我一般选默认模板,什么都没有,自己继续配置

默认模板确认之后,文件结构如下

下面我们要进行改造项目了

自定义项目内容,搭建基础

项目配置文件 .vscode

为了项目开发方便,当然也为了跟我们共同开发的小伙伴,达成代码共识,也就是代码有规范,我们利用插件和简单配置,格式化我们项目代码,并且附带代码规范,在 .vscode文件夹中,也可以放一些项目文档等

其中 setttings.json是项目配置文件,单独在此项目中起作用

我的配置如下,具体就不介绍了,感兴趣小伙伴自行整理,符合自己团队就好

{
  "editor.formatOnSave": true, // #每次保存的时候自动格式化*
  "editor.formatOnPaste": true, // #每次粘贴的时候自动格式化*
  "editor.codeActionsOnSave": { // #每次保存的时候将代码按eslint格式进行修复*
    "source.fixAll.eslint": true
  },
  "prettier.jsxSingleQuote": true,
  "prettier.semi": false, //  #去掉代码结尾的分号*
  "prettier.singleQuote": true, //  #使用带引号替代双引号*
  "prettier.requireConfig": true,
  "javascript.preferences.quoteStyle": "single",
  "javascript.format.insertSpaceBeforeFunctionParenthesis": true, //  #让函数(名)和后面的括号之间加个空格*
  "javascript.updateImportsOnFileMove.enabled": "always",
  "html.format.endWithNewline": true,
  "vetur.format.defaultFormatter.js": "vscode-typescript", // #让vue中的js按编辑器自带的ts格式进行格式化*
  "vetur.format.defaultFormatter.html": "js-beautify-html",
  "vetur.format.defaultFormatterOptions": {
    "js-beautify-html": {
      "wrap_line_length": 120,
      "wrap_attributes": "force-aligned", // 第一个属性不折行,后续所有属性和第一个对齐折行*
      "end_with_newline": false
    }
  },
  "[vue]": {
    "editor.defaultFormatter": "octref.vetur"
  },
  "cSpell.words": [
    "scrollbar",
    "wrapper"
  ],
  "git.ignoreLimitWarning": true,
}

请求工具 api

这里根据uni-app 的请求,来封装了一下,适合自己公司的请求,仅供参考

封装之后,接口请求全部统一管理,页面上只需要调用 this.$api.接口名

文件结构

├── src
│   ├── api
│   │   ├── modules         // 模块文件夹,各个文件需要的不同接口做区分
│   │   │   ├── app.js      // app 全局需要的请求,放这里
│   │   ├── index.js        // 此文件作为 api 唯一出口,引入模块,在 vue 全局挂载
│   │   ├── request.js      // 根据 uniapp 请求封装的请求,带拦截
│   │   └── urls.js         // 后端的接口,统一管理文件

贴出例子,仅供参考

  • app.js
import { urls } from '../urls'
import { getFullUrl } from '@/utils/tools.js'


// type: 2: 图片,3: 视频,4: 音频
export function uploadFile (params, url = urls.uploadFile) { // 上传图片
  const temConfig = {
    header: {
      'Content-Type': 'multipart/form-data'
    }
  }
  return new Promise((resolve, reject) => {
    uni.uploadFile({
      url: url, //仅为示例,非真实的接口地址
      name: 'files',
      filePath: params.file,
      fileType: params.fileType,
      ...temConfig,
      formData: {
        'loginName': uni.getStorageSync('thirdUserId'),
        'orgId': uni.getStorageSync('orgId'),
        'grant_type': 'password',
        'appid': 'mobileWCOA',
        'type': params.type
      },
      success: (response) => {
        const res = JSON.parse(response.data)
        if (res.code === 10000) {
          resolve(res.content)
        } else {
          resolve({
            isError: true,
            message: res.message,
            subCode: res.subCode
          })
        }
      }
    })
  })
}

// 上传头像
export function uploadAvatar (file, url = urls.uploadAvatar) { // 上传头像
  return new Promise((resolve, reject) => {
    const headers = {
      'ContentType': 'multipart/form-data',
    }
    uni.uploadFile({
      url: getFullUrl(urls.uploadAvatar),
      name: 'files',
      filePath: file,
      header:headers,
      fileType: 'image',
      success: (response) => {
        const res = JSON.parse(response.data)
        if (res.code === 10000) {
          resolve(res.content)
        } else {
          resolve({
            isError: true,
            message: res.message,
            subCode: res.subCode
          })
        }
      }
    })
  })
}


  • index.js
import Vue from 'vue'

import { urls, fileHost, imgHost } from './urls'
import * as app from './modules/app'

export const api = {
  ...app
}

Vue.prototype.$api = api
Vue.prototype.$urls = urls

  • request.js
const loginErrorSubCode = ['TOKEN_EXPIRED', 'TOKEN_NULL', 'SESSION_KEY_FAIL']
const loginErrorCode = [40001, 40002]
// 报错锁
let LOGIN_LOCK = false

export default function (obj) {
  return new Promise((resolve, reject) => {
    // 无效请求
    if (!obj.url) return reject('无效请求,没有 url')
    // 没有 token,并且不在白名单,不允许请求
    if (!uni.getStorageSync('token') && !obj.needlessToken) {
      if (LOGIN_LOCK) return
      LOGIN_LOCK = true
      uni.navigateTo({ url: '/pages/public/login' })
      return
    }

    LOGIN_LOCK = false

    let headers = {
      'authToken': uni.getStorageSync('token') || '',
      'masterOrgId': uni.getStorageSync('masterOrgId') || ''
    }
    if (obj.formData) {
      headers['Content-type'] = "application/x-www-form-urlencoded"
    }
    // 发起请求
    uni.request({
      url: obj.url,
      data: obj.data,
      method: obj.method || 'POST',
      header: headers,
      success: (response) => {
        if (obj.method === 'GET') {
          resolve(response.data)
          return
        }

        const res = response.data
        if (loginErrorCode.includes(res.code) || loginErrorSubCode.includes(res.subCode)) {
          if (LOGIN_LOCK) return
          LOGIN_LOCK = true
          uni.navigateTo({ url: '/pages/public/Login' })
          return
        }

        LOGIN_LOCK = false

        if (res.code === 10000) {
          resolve(res)
        } else {
          resolve({
            isError: true,
            message: res.message,
            subCode: res.subCode
          })
        }
      },
      fail: (e) => {
        if (loginErrorCode.includes(e.data.code) && loginErrorSubCode.includes(e.data.subCode)) {
          if (LOGIN_LOCK) return
          LOGIN_LOCK = true
          uni.navigateTo({ url: '/pages/public/Login' })
          return
        }
        console.log(" fail:" + JSON.stringify(e.data));
      },
      complete: () => { }
    })
  })
}


  • urls.js
export const urls = {
  getCommunityNoteInfoById: '/community/communityNote/getCommunityNoteInfoById', // 根据笔记id查询笔记详细信息
}

此时请求封装完成,还是挺好用的

其它内容没什么特别的,就是自己封装的一些工具

整体文件结构如下