赞
踩
使用vue-cli脚手架创建uni-app框架,vue3 + vite应用框架,uview-plusUI组件库,pinia状态管理器,pnpm依赖包管理。
nodeJs版本要求:^14.18.0 || >=16.0.0
npm:8.5.0 pnpm:6.32.6
vue/cli版本:@5.0.8 vue:^3.2.45 vite:^3.2.4
uview-plus:^3.1.26 pinia:^2.0.30
pnpm install -g @vue/cli vue create -p dcloudio/uni-preset-vue#vite 项目名
- ┌─src
- │ ├─api 请求地址目录
- │ ├─assets 静态资源目录
- │ │ └─css 样式
- │ │ │ ├─common 公共样式、字体图标样式、uview组件库
- │ │ │ └─app.styl 全局样式引入
- │ │ └─icon-font 字体图标库
- │ └─common
- │ │ ├─http 网络请求封装
- │ │ ├─bus.js eventBus封装
- │ │ └─common.js 公共方法封装
- │ ├─component 公共组件
- │ ├─conf 系统配置文件
- │ ├─pages 主包目录
- │ ├─pagesAffairs 办事页面目录
- │ ├─pagesCommon 公用页面目录(办理流程、办事指南)
- │ ├─pagesIndex 首页页面目录
- │ ├─pagesServiced 服务页面目录
- │ ├─pagesUser 我的页面目录
- │ ├─plugins 插件引入
- │ │ └─uview.js uview-plusUI组件库
- │ ├─static 静态图片资源目录
- │ ├─stores pinia状态管理
- │ ├─utils 公用函数、工具目录
- │ ├─App.vue 应用配置,用来配置小程序全局样式以及监听、应用生命周期
- │ ├─main.js Vue初始化入口文件
- │ ├─manifest.json 配置应用名称、appid、logo、版本等打包信息
- │ ├─pages.json 配置页面路由、导航条、选项卡等页面类信息
- │─.editorconfig 统一代码编辑器配置
- │─.eslintignore 统一代码编辑器配置忽略文件
- │─.eslintrc.js eslint代码约束配置
- │─.gitignore git代码提交忽略文件
- │─.prettierrc.json 文件代码格式化配置
- │─index.html 静态资源目录
- │─jsconfig.json javascript根目录
- │─package.json 常见的配置有配置项目启动、打包命令,声明依赖包等
- │─pnpm-lock.yaml
- │─postcss.config.js css适配方案
- └─vite.config.js 项目打包、插件引入、编译相关配置
UI组件库: uview-plus@3.1.26
- // 安装命令
- pnpm install uview-plus@3.1.26
引入方式:
- // plugins/uview.js 初始化配置
- import uviewPlus from "uview-plus"
-
- export const $toast = (message) => {
- uni.$u.toast(message)
- }
-
- export default app => {
- app.provide('$toast', $toast)
- app.use(uviewPlus)
- }
-
- // main.js 主入口文件进行引用
- import uviewPlusFn from '@/plugins/uview'
- // 挂载uviewPlus
- uviewPlusFn(app)
-
- // App.vue 引入样式文件
- <style lang="scss" scope>
- // uview-plus
- @import 'uview-plus/index.scss';
- // 引入uview-plus主题
- @import 'uview-plus/theme.scss';
- </style>
-
- // 注意:uview-plus开发还不完善,小程序中相关组件样式不生效,存在报错,需在node_modules中手动引入主题样式
- // node_modules/-plus/libs/css/components.css中引入
- @import "../../theme.scss";
项目使用:pinia@2.0.30
- // 安装命令
- pnpm install pinia@3.1.26
- // 使用持久化存储-安装命令
- pnpm install pinia-plugin-persist
引入方式:
- // stores/index.js 初始化配置
- import { createPinia } from "pinia"
- import piniaPersist from 'pinia-plugin-persist'
-
- const store = createPinia()
- // 持久化存储 小程序暂不支持sessionStorage、localStorage所以不能使用
- store.use(piniaPersist)
-
- export function setupStore (app) {
- app.use(store)
- }
-
- export { store }
-
- // main.js 主入口文件进行引用
- import { setupStore } from './stores/index'
- // 挂载pinia
- setupStore(app))
使用方式:
- import { defineStore } from 'pinia'
- import { store } from "../index"
-
- export const userCommonStore = defineStore({
- id: 'common',
- state: () => {
- return {
- token: ''
- }
- },
- actions: {
- // token
- setToken (token) {
- this.token = token
- }
- },
- persist: {
- // 开启持久化存储
- enabled: true,
- // 自定义持久化参数
- strategies: [
- {
- // 自定义key,默认就是仓库的key
- key: 'token',
- // 自定义存储方式,默认sessionStorage
- storage: localStorage,
- // 指定要持久化的数据,默认所有 state 都会进行缓存,可以通过 paths 指定要持久化的字段,其他的则不会进行持久化。
- paths: ['token']
- }
- ]
- }
- })
- // 导出状态hook
- export function userCommonStoreHook () {
- return userCommonStore(store)
- }
-
- // vue文件使用
- import { userCommonStoreHook } from '@/stores/modules/common'
- <script>
- // 存储
- userCommonStoreHook().setToken('value')
- // 获取
- const token = userCommonStoreHook().token
- </script>
项目使用:结合new Promise + uni.request(OBJECT)
相关配置方法:uniapp-request
系统配置:
- // conf/index.js 相关系统配置文件
- export const API = {
- // 开发环境
- development: {
- DEFAULT: 'http://192.168.1.246:19601/iframework' || import.meta.env.BASE_URL,
- JR: 'http://192.168.1.246:19601/iframework' || '/api', // 测试环境
- API: 'http://192.168.18.91:8001' // 第三方api
- },
- // 生产环境
- production: {
- DEFAULT: 'http://192.168.1.246:19601/iframework' || import.meta.env.BASE_URL,
- JR: 'http://192.168.1.246:19601/iframework' || '/api',
- API: 'http://192.168.18.91:8001' // 第三方api
- }
- }
- const isProd = import.meta.env.MODE === 'production'
- export const BASE_CONFIG = isProd ? API.production : API.development
使用方法:
- // common/http/http-async.js 目录文件
- 'use strict'
- import { API as configApi } from '@/conf/'
- import qs from 'querystring'
- import { getStorage, removeStorage } from '@/utils/storage'
- import { linkJump } from '@/common/common'
- import { userCommonStoreHook } from '@/stores/modules/common'
-
- // 获取接口根路径
- const isProd = import.meta.env.MODE === 'production'
- const BASE_PATH = isProd ? configApi.production : configApi.development
-
- export const request = (options) => {
- return new Promise((resolve, reject) => {
- let url = options.url
-
- // 简化类型设置
- const headers = {
- 'Content-Type': 'application/json; charset=UTF-8',
- 'Cookie': `JSESSIONID=${getStorage('JSESSIONID') || ''}`
- }
- // 提交表单类型
- if (options.isForm) {
- headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8'
- delete options.isForm
- }
- // 提交上传类型
- if (options.isFile) {
- headers['Content-Type'] = 'multipart/form-data; charset=UTF-8'
- delete options.isFile
- }
- // 校验post数据格式
- const contentTyoe = headers['Content-Type']
- if (
- typeof options.params === 'object' &&
- contentTyoe &&
- String(contentTyoe).indexOf('application/x-www-form-urlencoded') > -1
- ) {
- options.params = qs.stringify(options.params)
- }
- // 添加token
- if (userCommonStoreHook().token) {
- headers['token'] = userCommonStoreHook().token
- }
- // 设置请求路径
- options.url = BASE_PATH[options.apiType || 'JR'] + url
- console.log('url', options, options.params)
- uni.request({
- url: options.url,
- method: options.method,
- data: options.params,
- withCredentials: true,
- header: headers,
- success (response) {
- const status = +response.statusCode
- const data = response.data || {}
- if (status === 200 || status === 304) {
- // 第三方api接口判断
- if (data.statusCode === 200 && options.url.indexOf('api.jsp')) {
- if (data.statusCode === 200) {
- resolve(data)
- } else {
- uni.$u.toast(data.msg || '')
- reject(data)
- }
- return
- }
- if (data.id === 500) {
- uni.$u.toast(data.msg || '')
- // 退出登录
- userCommonStoreHook().clearOut()
- } else if (data.id === '01') {
- resolve(data)
- } else if (data.id === '02' && data.msg === 'token不能为空') {
- uni.$u.toast(data.msg || '')
- // 退出登录
- userCommonStoreHook().clearOut()
- } else {
- uni.$u.toast(data.msg || '')
- reject(data)
- }
- } else if (status === 404) {
- linkJump('/pages/404/index')
- reject(data)
- } else {
- reject(data)
- }
- },
- fail (error) {
- if (err.errMsg === 'request:fail timeout') {
- uni.$u.toast('请求超时,请重试')
- } else if (err.errMsg === 'request:fail ') {
- uni.$u.toast('无网络')
- } else {
- uni.$u.toast('服务器繁忙' || error.errMsg)
- }
- reject(error)
- }
- })
- })
- }
请求调用:
- 'use strict'
- import { request } from '@/common/http/http-async'
-
- export const login = (params = {}) => {
- const param = {
- apiType: 'JR',
- method: 'post',
- json: true,
- url: '/api/internet/login',
- params: params
- }
- return request(param)
- }
-
- // 第三方api调用
- export const getChannelIdList = (params = {}) => {
- const param = {
- apiType: 'API',
- method: 'get',
- json: true,
- url: '/api.jsp',
- params: params
- }
- return request(param)
- }
-
- // vue文件使用
- import { getChannelIdList } from '@/api/index'
- let params = {}
- getChannelIdList(params).then((result) => {}).catch((err) => {})
- // .eslintrc.js
- module.exports = {
- // 默认情况下,ESLint会在所有父级组件中寻找配置文件,一直到根目录。ESLint一旦发现配置文件中有 "root": true,它就会停止在父级目录中寻找。
- root: true,
- env: {
- node: true,
- es6: true,
- 'vue/setup-compiler-macros': true
- },
- extends: [
- 'plugin:vue/vue3-essential',
- 'eslint:recommended',
- 'prettier',
- '@vue/prettier',
- 'plugin:prettier/recommended'
- ],
- plugins: ['prettier'],
- // 对Babel解析器的包装使其与 ESLint 兼容。
- parserOptions: {
- ecmaVersion: 2020,
- parse: 'babel-eslint',
- // 代码是 ECMAScript 模块
- sourceType: 'module'
- },
- // 去掉校验
- globals: {
- Atomics: 'readonly',
- SharedArrayBuffer: 'readonly',
- defineProps: 'readonly',
- defineEmits: 'readonly',
- defineExpose: 'readonly',
- withDefaults: 'readonly'
- },
- rules: {
- 'prettier/prettier': 'error',
- 'arrow-body-style': 'off',
- 'prefer-arrow-callback': 'off',
- // 关闭名称校验
- 'vue/multi-word-component-names': 'off'
- }
- }
-
- // .prettierrc.json 代码格式化配置
- {
- "semi": false,
- "eslintIntegration": true,
- "singleQuote": true,
- "endOfLine": "lf",
- "tabWidth": 2,
- "trailingComma": "none",
- "bracketSpacing": true,
- "arrowParens": "avoid"
- }
原因:微信官方对小程序的体积大小有硬性要求,上限为2048KB
处理方法:
- // manifest.json 相关配置
- "mp-weixin": {
- // 开启分包优化
- "optimization": {
- "subPackages": true
- }
- }
-
- // pages.json 路径配置
- // 分包
- "subPackages": [
- {
- "root": "pagesCommon",
- "name": "pagesCommon",
- "pages": [
- {
- "path": "handle-event/index",
- "style": {
- "navigationBarTitleText": "办事",
- "enablePullDownRefresh": true,
- "navigationStyle": "custom"
- }
- }
- ]
- },
- {
- "root": "pagesIndex",
- "name": "pagesIndex",
- "pages": [
- {
- "path": "notice-list/index",
- "style": {
- "navigationBarTitleText": "通知公告",
- "enablePullDownRefresh": true,
- "navigationStyle": "custom"
- }
- },
- {
- "path": "problem-list/index",
- "style": {
- "navigationBarTitleText": "常见问题",
- "enablePullDownRefresh": true,
- "navigationStyle": "custom"
- }
- },
- {
- "path": "notice-detail/index",
- "style": {
- "navigationBarTitleText": "通知公告详情",
- "enablePullDownRefresh": true,
- "navigationStyle": "custom"
- }
- }
- ]
- }
- }
原因:微信小程序background-image只能用网络url或者base64图片编码
处理方法:
- /**
- * 本地图片转换base64
- * @param {*} folder 文件夹名称
- * @param {*} fileName 文件名称
- * @param {*} format 文件后缀
- */
- export const getLocalImgToBase64 = (folder, fileName, format = 'png') => {
- let imgUrl = `/static/${folder}/${fileName}.${format}`
- let base64 = uni.getFileSystemManager().readFileSync(imgUrl, 'base64')
- return `data:image/png;base64,${base64}`
- }
-
- // 使用
- :style="{ backgroundImage: `url(${getLocalImgToBase64('文件夹名称', '文件名', 'png')})`}"
-
- // 小程序图片模糊失真处理(作用于image图片)
- image-rendering -moz-crisp-edges
- image-rendering -o-crisp-edges
- image-rendering -webkit-optimize-contrast // 设置图像缩放算法
- image-rendering crisp-edges // 缩放后不会变模糊
- -ms-interpolation-mode nearest-neighbor
下载字体包
- // 安装插件
- cnpm install -g iconfont-tools
- // 进入到文件夹里面用cmd执行下列命令
- iconfont-tools
- // main.js
- // 引入阿里彩色矢量字体
- @import '@/assets/icon-font/iconfont.css'
下载字体包
ttf文件转换成base64格式,转换地址:transfonter.org
- @font-face {
- font-family 'iconfont'
- src url('../../icon-font/iconfont.woff') format('woff'), url('../../icon-font/iconfont.woff2') format('woff2'), url('base64编码') format('truetype')
-
- .iconfont {
- font-family 'iconfont' !important
- font-size 45rpx
- font-style normal
- // 抗锯齿
- -webkit-font-smoothing antialiased
- -moz-osx-font-smoothing grayscale
- }
-
- .icon-jiantou-zuo:before {
- content: "\e71b";
- }
3. 打包
pnpm run build:mp-weixin
登录微信公众平台,设置 > 账号信息 > AppID,获取到ID后打开微信开发者工具,扫码登录需要发布小程序的微信,右侧基本信息,绑定AppId
打开微信公众平台,设置项目成员、体验成员
修改打开页面路径
如需发布上线,点击提交审核即可
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。