uniapp-vue3-vite 搭建小程序、H5 项目模板

uniapp-vue3-vite 搭建小程序、H5 项目模板

  • 特色
  • 准备
    • 拉取默认UniApp模板
    • 安装依赖
    • 启动项目测试
    • 结果
  • 配置自动化导入
    • 安装依赖
    • 在vite.config.js中配置
  • 引入 prerttier + eslint + stylelint
    • .editorconfig
    • .prettierrc.cjs
    • .eslintrc.cjs
    • .stylelintrc.cjs
  • 引入 husky + lint-staged + commitlint
    • Commitizen & cz-git
      • 更改提示消息模板 .cz-config.js
    • 检测
  • 配置UnoCss
    • 检测
  • 配置pinia 添加持久化
    • 检测
  • Axios接入配置
    • 在vite.config.js中配置自动化导入
    • 检测
  • 图标库
  • UI 方案
  • 模板
  • 敬请期待

1

作者GitHub:https://github.com/gitboyzcf 有兴趣可关注!!!

特色

  • ⚡️uni-app, Vue 3, Vite, pnpm

  • 📦 组件自动化引入

  • 🍍 使用 Pinia 的状态管理

  • 🎨 UnoCSS - 高性能且极具灵活性的即时原子化 CSS 引擎

  • 😃 各种图标集为你所用

  • 🔥 使用 新的 <script setup> 语法

  • 📥 API 自动加载 - 直接使用 Composition API 无需引入

  • 🌍 API 采用模块化自动导入方式 根据demo.js文件设置接口,以API_xxx_method的方式命名,在请求时无需导入 直接使用useRequest()函数返回参数以解构的方式获取,拿到即为写入的接口

准备

Vue3/Vite版要求 node 版本^14.18.0 || >=16.0.0

拉取默认UniApp模板

点击下载 默认模板,或者通过下面命令行拉取

npx degit dcloudio/uni-preset-vue#vite my-vue3-project

得到下面目录结构👇

1

安装依赖

我这里使用pnpm ,可以使用如npm、yarn、…

pnpm install

如有报下面错误👇

This modules directory was created using the following registries configuration:{“default”:“https://registry.npmjs.org/”}. The current configuration is {“default”:“https://registry.npm.taobao.org/”}. To recreate the modules directory using the new settings, run “pnpm install -g”.

解决方案 下载源切换

pnpm config set registry https://registry.npmjs.org

启动项目测试

执行该命令 会将此项目编译成微信小程序项目,该命令会持续监听修改并进行热更新

pnpm dev:mp-weixin

执行后会出现 dist\dev\mp-weixin文件夹结构

2

将此目录下的mp-weixin微信开发者工具进行打开

如未安装点击下面链接下载安装即可👇
https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html

结果

结果

配置自动化导入

安装依赖

pnpm i unplugin-auto-import -D

在vite.config.js中配置

配置

import AutoImport from 'unplugin-auto-import/vite'

AutoImport({
 imports: ["vue", "uni-app", "pinia"],
 dts: true,
})

配置完后 重新执行pnpm dev:mp-weixin此时会生成auto-imports.d.ts文件

此时在pages/index/index.vue中不用引入直接可以使用vue的api

<script setup>
const title = ref('Hello World!')
</script>

引入 prerttier + eslint + stylelint

安装相关依赖包👇

pnpm add -D eslint @babel/eslint-parser eslint-config-airbnb-base eslint-config-prettier eslint-plugin-import eslint-plugin-prettier eslint-plugin-vue vue-global-api stylelint stylelint-scss stylelint-config-standard-scss stylelint-config-prettier

.editorconfig

# .editorconfig 文件
root = true

[*] # 表示所有文件适用
charset = utf-8 # 设置文件字符集为 utf-8
indent_style = space # 缩进风格(tab | space)
indent_size = 2 # 缩进大小
end_of_line = lf # 控制换行类型(lf | cr | crlf)
trim_trailing_whitespace = true # 去除行首的任意空白字符
insert_final_newline = true # 始终在文件末尾插入一个新行

[*.md] # 表示仅 md 文件适用以下规则
max_line_length = off # 关闭最大行长度限制
trim_trailing_whitespace = false # 关闭末尾空格修剪

.prettierrc.cjs

module.exports = {
  // 一行的字符数,如果超过会进行换行,默认为80,官方建议设100-120其中一个数
  printWidth: 100,
  // 一个tab代表几个空格数,默认就是2
  tabWidth: 2,
  // 启用tab取代空格符缩进,默认为false
  useTabs: false,
  // 行尾是否使用分号,默认为true(添加理由:更加容易复制添加数据,不用去管理尾行)
  semi: false,
  vueIndentScriptAndStyle: true,
  // 字符串是否使用单引号,默认为false,即使用双引号,建议设true,即单引号
  singleQuote: true,
  // 给对象里的属性名是否要加上引号,默认为as-needed,即根据需要决定,如果不加引号会报错则加,否则不加
  quoteProps: 'as-needed',
  // 是否使用尾逗号,有三个可选值"<none|es5|all>"
  trailingComma: 'none',
  // 在jsx里是否使用单引号,你看着办
  jsxSingleQuote: true,
  // 对象大括号直接是否有空格,默认为true,效果:{ foo: bar }
  bracketSpacing: true,
  proseWrap: 'never',
  htmlWhitespaceSensitivity: 'strict',
  endOfLine: 'auto',
}

.eslintrc.cjs

// .eslintrc.cjs 文件
module.exports = {
  env: {
    browser: true,
    es2021: true,
    node: true,
  },
  extends: [
    'eslint:recommended',
    'plugin:vue/vue3-essential',
    // eslint-plugin-import 插件, @see https://www.npmjs.com/package/eslint-plugin-import
    'plugin:import/recommended',
    // eslint-config-airbnb-base 插件, tips: 本插件也可以替换成 eslint-config-standard
    'airbnb-base',
    // 1. 接入 prettier 的规则
    'prettier',
    'plugin:prettier/recommended',
    'vue-global-api',
  ],
  overrides: [
    {
      env: {
        node: true,
      },
      files: ['.eslintrc.{js}'],
      parserOptions: {
        sourceType: 'script',
      },
    },
  ],
  parserOptions: {
    ecmaVersion: 'latest',
    parser: '@babel/eslint-parser',
    sourceType: 'module',
  },
  plugins: [
    '@babel/eslint-parser',
    'vue',
    // 2. 加入 prettier 的 eslint 插件
    'prettier',
    // eslint-import-resolver-typescript 插件,@see https://www.npmjs.com/package/eslint-import-resolver-typescript
    'import',
  ],
  rules: {
    // 3. 注意要加上这一句,开启 prettier 自动修复的功能
    'prettier/prettier': 'error',
    // turn on errors for missing imports
    'import/no-unresolved': 'off',
    // 对后缀的检测,否则 import 一个ts文件也会报错,需要手动添加'.ts', 增加了下面的配置后就不用了
    'import/extensions': [
      'error',
      'ignorePackages',
      { js: 'never', jsx: 'never', ts: 'never', tsx: 'never' },
    ],
    // 只允许1个默认导出,关闭,否则不能随意export xxx
    'import/prefer-default-export': ['off'],
    'no-console': ['off'],
    // 'no-unused-vars': ['off'],
    // '@typescript-eslint/no-unused-vars': ['off'],
    // 解决vite.config.ts报错问题
    'import/no-extraneous-dependencies': 'off',
    'no-plusplus': 'off',
    'no-shadow': 'off',
    'vue/multi-word-component-names': 'off',
    '@typescript-eslint/no-explicit-any': 'off',
  },
  // eslint-import-resolver-typescript 插件,@see https://www.npmjs.com/package/eslint-import-resolver-typescript
  settings: {
    'import/parsers': {
      '@typescript-eslint/parser': ['.ts', '.tsx'],
    },
    'import/resolver': {
      typescript: {},
    },
  },
  globals: {
    uni: true,
    UniApp: true,
    wx: true,
    WechatMiniprogram: true,
    getCurrentPages: true,
    UniHelper: true,
    Page: true,
    App: true,
  },
}

.stylelintrc.cjs

// .stylelintrc.cjs 文件
module.exports = {
  root: true,
  extends: [
    'stylelint-config-standard',
    'stylelint-config-standard-scss', // tips: 本插件也可以替换成 stylelint-config-recommended-scss
    'stylelint-config-recommended-vue/scss',
    'stylelint-config-html/vue',
    'stylelint-config-recess-order',
  ],
  overrides: [
    // 扫描 .vue/html 文件中的<style>标签内的样式
    {
      files: ['**/*.{vue,html}'],
      customSyntax: 'postcss-html',
    },
    {
      files: ['**/*.{css,scss}'],
      customSyntax: 'postcss-scss',
    },
  ],
  // 自定义规则
  rules: {
    // 允许 global 、export 、v-deep等伪类
    'selector-pseudo-class-no-unknown': [
      true,
      {
        ignorePseudoClasses: ['global', 'export', 'v-deep', 'deep'],
      },
    ],
    'unit-no-unknown': [
      true,
      {
        ignoreUnits: ['rpx'],
      },
    ],
    // 处理小程序page标签不认识的问题
    'selector-type-no-unknown': [
      true,
      {
        ignoreTypes: ['page'],
      },
    ],
    'comment-empty-line-before': 'never',
  },
}

引入 husky + lint-staged + commitlint

说明
husky 用于git提交的钩子
lint-staged 一个在 git 暂存文件上(也就是被git add后的文件)运行已配置的格式工具;比如eslint、stylelintrc、…
commitlint 检查您的提交消息是否符合 常规提交格式 (Conventional commit format)
正确的提交格式:(): ,type 和 subject 默认必填
在这里插入图片描述

安装相关依赖包👇

pnpm i -D husky@6 lint-staged commitlint @commitlint/cli @commitlint/config-conventional

执行 npx husky install
并且在 package.json的scripts里面增加 "prepare": "husky install",(其他人安装后会自动执行) 根目录会生成 .hushy 文件夹。

package.josn 增加如下属性👇:

...
"scripts": {
	...
	"prepare": "husky install",
},
"lint-staged": {
  "**/*.{html,vue,ts,cjs,json,md}": [
    "prettier --write"
  ],
  "**/*.{vue,js,ts,jsx,tsx}": [
    "eslint --fix"
  ],
  "**/*.{vue,css,scss,html}": [
    "stylelint --fix"
  ]
}

根目录新增 .commitlintrc.cjs,内容如下👇

module.exports = {
  extends: ['@commitlint/config-conventional'],
  rules: {
    'type-enum': [
      2,
      'always',
      [
        'feat',
        'fix',
        'perf',
        'style',
        'docs',
        'test',
        'refactor',
        'build',
        'ci',
        'init',
        'chore',
        'revert',
        'wip',
        'workflow',
        'types',
        'release',
      ],
    ],
    'subject-case': [0],
  },
}

通过下面命令在钩子文件中添加内容👇

npx husky add .husky/pre-commit "npx --no-install -- lint-staged"
npx husky add .husky/commit-msg "npx --no-install commitlint --edit $1"

Commitizen & cz-git

说明
commitizen 基于Node.js的 git commit 命令行工具,辅助生成标准化规范化的 commit message
cz-customizable 标准输出格式的 commitizen 适配器

安装依赖包👇

pnpm add -D commitizen cz-customizable

修改 package.json指定使用的适配器

...
"scripts": {
	...
	"cz": "git-cz"
},
 "config": {
    "commitizen": {
      "path": "node_modules/cz-customizable"
    }
  }

更改提示消息模板 .cz-config.js

.cz-config.js

module.exports = {
  types: [
    { value: 'feat', name: '✨ feat:     新功能' },
    { value: 'fix', name: '🐛 fix:      修复' },
    { value: 'init', name: '🎉 Init:     初始化' },
    { value: 'docs', name: '📝 docs:     文档变更' },
    { value: 'style', name: '💄 style:    代码格式(不影响代码运行的变动)' },
    {
      value: 'refactor',
      name: '♻️  refactor: 重构(既不是增加feature,也不是修复bug)',
    },
    { value: 'perf', name: '⚡️ perf:     性能优化' },
    { value: 'test', name: '✅ test:     增加测试' },
    { value: 'revert', name: '⏪️ Revert:   回退' },
    { value: 'build', name: '🚀‍ build:    构建过程或辅助工具的变动' },
    { value: 'ci', name: '👷 ci:       CI 配置' },
  ],
  // 消息步骤
  messages: {
    type: '请选择提交类型:',
    subject: '请简要描述提交(必填):',
    customScope: '请输入修改范围(可选):',
    body: '请输入详细描述(可选):',
    breaking: '列出任何BREAKING CHANGES(可选)',
    footer: '请输入要关闭的issue(可选):',
    confirmCommit: '确认使用以上信息提交吗?',
  },
  allowBreakingChanges: ['feat', 'fix'],
  skipQuestions: ['customScope'],
  subjectLimit: 72,
}

检测

在命令行中输入👇

git add .
pnpm cz

然后会出现本次提交选项
1

选择本次提交的类型,按要求写入然后回车即可

配置UnoCss

安装依赖👇

pnpm add -D unocss @unocss/preset-uno unocss-applet @unocss/preset-legacy-compat
pnpm add @uni-helper/unocss-preset-uni

然后配置 unocss.config.js

// uno.config.js
import {
  Preset,
  defineConfig,
  presetAttributify,
  presetIcons,
  transformerDirectives,
  transformerVariantGroup,
} from 'unocss'

import {
  presetApplet,
  presetRemRpx,
  transformerApplet,
  transformerAttributify,
} from 'unocss-applet'
import { presetUni } from '@uni-helper/unocss-preset-uni'

// @see https://unocss.dev/presets/legacy-compat
import presetLegacyCompat from '@unocss/preset-legacy-compat'

const isH5 = process.env?.UNI_PLATFORM === 'h5'
const isMp = process.env?.UNI_PLATFORM?.startsWith('mp') ?? false

const presets = []
if (!isMp) {
  /**
   * you can add `presetAttributify()` here to enable unocss attributify mode prompt
   * although preset is not working for applet, but will generate useless css
   * 为了不生产无用的css,要过滤掉 applet
   */
  // 支持css class属性化,eg: `<button bg="blue-400 hover:blue-500 dark:blue-500 dark:hover:blue-600" text="sm white">attributify Button</button>`
  presets.push(presetAttributify())
}
if (!isH5) {
  presets.push(presetRemRpx())
}
export default defineConfig({
  presets: [
    presetApplet({ enable: !isH5 }),
    ...presets,
    // 支持图标,需要搭配图标库,eg: @iconify-json/carbon, 使用 `<button class="i-carbon-sun dark:i-carbon-moon" />`
    presetIcons({
      scale: 1.2,
      warn: true,
      extraProperties: {
        display: 'inline-block',
        'vertical-align': 'middle',
      },
    }),
    // 将颜色函数 (rgb()和hsl()) 从空格分隔转换为逗号分隔,更好的兼容性app端,example:
    // `rgb(255 0 0)` -> `rgb(255, 0, 0)`
    // `rgba(255 0 0 / 0.5)` -> `rgba(255, 0, 0, 0.5)`
    presetLegacyCompat({
      commaStyleColorFunction: true,
    }),
  ],
  /**
   * 自定义快捷语句
   * @see https://github.com/unocss/unocss#shortcuts
   */
  shortcuts: [['center', 'flex justify-center items-center']],
  transformers: [
    // 启用 @apply 功能
    transformerDirectives(),
    // 启用 () 分组功能
    // 支持css class组合,eg: `<div class="hover:(bg-gray-400 font-medium) font-(light mono)">测试 unocss</div>`
    transformerVariantGroup(),
    // Don't change the following order
    transformerAttributify({
      // 解决与第三方框架样式冲突问题
      prefixedOnly: true,
      prefix: 'fg',
    }),
    transformerApplet(),
  ],
  rules: [
    [
      'p-safe',
      {
        padding:
          'env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left)',
      },
    ],
    ['pt-safe', { 'padding-top': 'env(safe-area-inset-top)' }],
    ['pb-safe', { 'padding-bottom': 'env(safe-area-inset-bottom)' }],
  ],
})

src/main.js增加 import 'virtual:uno.css'

vite.config.js文件写入:

import UnoCSS from 'unocss/vite'

// 其他配置省略
plugins: [UnoCSS()],

检测

<view class="text-area b-1px b-solid b-color-red">
  <text class="title mt-4">{{ title }}</text>
</view>

结果👇
res

配置pinia 添加持久化

首先安装依赖包:

pnpm add pinia pinia-plugin-persistedstate -S

然后写入文件:

// src/store/count.js
import { piniaStore } from '@/store'
export const useCountStore = defineStore('count', {
  state: () => {
    return {
      count: 0
    }
  },
  actions: {
    increment() {
      this.count++
    }
  },
  persist: true // 配置持久化
})

export function useOutsideCountStore(){
  return useCountStore(piniaStore)
}

注意下面👇这个文件对持久化的处理,否则非h5环境不能正确持久化

// src/store/index.js
import { createPinia } from 'pinia'
import { createPersistedState } from 'pinia-plugin-persistedstate' // 数据持久化

const store = createPinia()
store.use(
  createPersistedState({
    storage: {
      getItem: uni.getStorageSync,
      setItem: uni.setStorageSync,
    },
  }),
)
export default store

// src/main.js
import { createSSRApp } from 'vue'
import App from './App.vue'
import { setupStore } from './store'
import 'virtual:uno.css'
export function createApp() {
  const app = createSSRApp(App)
  setupStore(app)
  return {
    app
  }
}

如有报下面错误👇
vue pinia版本冲突问题

Not able to use pinia: No matching export in “node_modules/pinia/node_modules/vue-demi/lib/index.mjs” for import “hasInjectionContext”

解决方案

将vue3 和pinia更换成下面版本重新下载对应npm包
“pinia”: “2.0.32”,
“vue”: “3.2.47”,

pnpm install vue@3.2.47 pinia@2.0.32 -S

具体请看:https://github.com/vuejs/pinia/issues/2210

检测

<view>
 <button type="primary" @click="useCountStore.count++">点击 {{ count }}</button>
</view>

<script setup>
  import { useOutsideCountStore } from '@/store/count'
  const useCountStore = useOutsideCountStore()
  const count = computed(() => useCountStore.count)
</script>

res

Axios接入配置

安装相关依赖包👇

pnpm add @uni-helper/axios-adapter axios

以下步骤创建对应文件粘贴代码即可

  1. src》api》index.js

    /**
     * 模块化方式处理 默认处理 modules文件夹下的所有js文件 内容以export default导出的文件
     * @param { 模块内容集合 } moduleContext
     * @returns modules集合
     */
    const modulesHandle = (moduleContext = {}) => {
      if (!Object.keys(moduleContext).length) return
      const modules = {}
      Object.keys(moduleContext).forEach((v) => {
        for (let key in moduleContext[v].default) {
          modules[key] = moduleContext[v].default[key]
        }
      })
      return modules
    }
    
    const apis = modulesHandle(import.meta.glob('./modules/**/*.js', { eager: true }))
    export const useRequest = () => apis
    
  2. src》api》utils.js

    // 请求状态错误
    export const httpLogError = (error, msg) => {
      error.message = msg
      uni.showToast({
        title: msg,
        icon: 'error',
        duration: 2000
      })
    }
    
    // api请求错误
    export const requestError = (response) => {
      return new Promise((_, reject) => {
        const { data } = response
        const msg = `api请求出错 ${response.config.url}${data.message}`
        uni.showToast({
          title: msg,
          icon: 'error',
          duration: 2000
        })
        reject(data)
      })
    }
    
    // 登录失效
    export const throttleToLogin = () => {
      // uni.navigateTo({ url: '/pages/login/login' })
    }
    
  3. src》api》service.js

    import axios from 'axios'
    import { createUniAppAxiosAdapter } from '@uni-helper/axios-adapter'
    import { httpLogError, requestError, throttleToLogin } from './utils'
    export function createService() {
      const request = axios.create({ adapter: createUniAppAxiosAdapter() })
      request.interceptors.request.use(
        (request) => {
          return request
        },
        (err) => {
          return Promise.reject(err)
        }
      )
    
      request.interceptors.response.use(
        (response) => {
          const dataAxios = response.data
          // 这个状态码是和后端约定的
          const { code, data } = dataAxios
          console.log(dataAxios);
          // 根据 code 进行判断
          if (code === undefined) {
            return dataAxios
          } else {
            // 目前和公司后端口头约定是字符串,以防万一强制转字符串
            switch (`${code}`) {
              // code === 200 | 2 代表没有错误
              case '200':
                return data
              // code === 400001004 代表token 过期打回登录页
              case '400001004':
                throttleToLogin()
                break
              case '400':
                // 不是正确的 code
                return requestError(response)
              case '401':
                // 错误登录
                return throttleToLogin()
              default:
                // 不是正确的 code
                return requestError(response)
            }
          }
        }, 
        (error) => {
          console.log(error);
          const status = error.response?.status
          switch (status) {
            // TODO 再考虑下怎么判断是跨域问题
            case undefined:
            case null:
              httpLogError(error, '网路错误或跨域')
              break
            case 400:
              httpLogError(error, '请求错误')
              break
            case 401:
              httpLogError(error, '未授权,请登录')
              break
            case 403:
              httpLogError(error, '拒绝访问')
              break
            case 404:
              httpLogError(error, `请求地址出错: ${error.response.config.url}`)
              break
            case 408:
              httpLogError(error, '请求超时')
              break
            case 500:
              httpLogError(error, '服务器内部错误')
              break
            case 501:
              httpLogError(error, '服务未实现')
              break
            case 502:
              httpLogError(error, '网关错误')
              break
            case 503:
              httpLogError(error, '服务不可用')
              break
            case 504:
              httpLogError(error, '网关超时')
              break
            case 505:
              httpLogError(error, 'HTTP版本不受支持')
              break
            default:
              httpLogError(error, '请求错误')
              break
          }
          return Promise.reject(error)
        }
      )
      return request
    }
    
    export const service = createService()
    
  4. src》api》request.js

    import { service } from './service'
    function createRequest(service) {
      function request(config) {
      	// config 自定义配置
        // axios默认配置
        const configDefault = {
          baseURL: import.meta.env.VITE_APP_API_BASEURL, // 所有通过此配置的基础地址 在.env文件配置
          timeout: 15000, // 请求超时时间
          responseType: 'json', // 响应类型
          headers: {
            // 请求头配置...
          }
        }
        const requestConfig = Object.assign(configDefault, config)
        return service(requestConfig)
      }
      return request
    }
    
    export const request = createRequest(service)
    
  5. src》modules》demo.js

    /**
     * 命名=》API_xxx_methodName
     */
    
    import { request } from '@/api/request.js'
    export default {
      API_DEMO_POST(data = {}) {
        return request({
          url: 'demo/mock',
          method: 'post',
          data
        })
      },
    
      API_DEMO_GET(params = {}) {
        return request({
          url: '/demo/get',
          method: 'get',
          params
        })
      }
    }
    
    

在vite.config.js中配置自动化导入

在原有的配置中添加

import { defineConfig } from 'vite'
import AutoImport from 'unplugin-auto-import/vite'
// ...
// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
  	//...
    AutoImport({
      imports: [
       //...
        {
          '@/api': ['useRequest']
        }
      ],
      //...
    }),
    //...
  ],
  //...
})

检测

<template>
  <view class="content">
    <view><button type="primary" @click="getList">点击请求数据</button></view>
  </view>
  <view class="p-2">
    <view
      class="my-15rpx b-b-solid b-b-1rpx b-b-color-[#cccccc]"
      v-for="item in list"
      :key="item.id"
    >
      <text class="text-18rpx font-bold">{{ item.title }}</text>
      <view class="mt-4 text-12rpx color-[#9999]">{{ item.body }}</view>
    </view>
  </view>
</template>

<script setup>
  const { API_DEMO_GET } = useRequest()
  const list = ref([])
  
  const getList = () => {
    uni.showLoading({
      title: '加载中...'
    })
    API_DEMO_GET()
      .then((res) => {
        console.log(res)
        list.value = res
        uni.hideLoading()
      })
      .catch(() => {
        uni.hideLoading()
      })
  }
</script>

api

图标库

  1. 前往图标库查找相关图标iconify.design

  2. 安装图标所在的图标库

    # 格式:pnpm add @iconify-json/[the-collection-you-want] -D
    
    # 例如
    pnpm add @iconify-json/ep -D
    

    安装完后可以使用当前库下的所有图标
    https://icon-sets.iconify.design/ep/

  3. 项目中使用
    使用unocss的方式https://iconify.design/docs/usage/css/unocss/#icons-with-unocss

    <text class="i-ep-apple w-40rpx h-40rpx color-red"></text>
    

UI 方案

自行使用相关ui接入项目
uni-ui
https://www.uvui.cn/
https://uviewui.com/

模板

拉取后 开箱即用
模板地址👉 https://github.com/gitboyzcf/uni-preset-vue3-vite

敬请期待

后续还会有新功能接入当前模板,敬请期待…






到这里就结束了,后续还会更新 前端 系列相关,还请持续关注!
感谢阅读,若有错误可以在下方评论区留言哦!!!

111


推荐文章👇

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/800288.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2024Datawhale AI夏令营---基于术语词典干预的机器翻译挑战赛--学习笔记

#Datawhale #NLP 1.背景介绍&#xff1a; 机器翻译&#xff08;Machine Translation&#xff0c;简称MT&#xff09;是自然语言处理领域的一个重要分支&#xff0c;其目标是将一种语言的文本自动转换为另一种语言的文本。机器翻译的发展可以追溯到20世纪50年代&#xff0c;经历…

springboot 适配ARM 架构

下载对应的maven https://hub.docker.com/_/maven/tags?page&page_size&ordering&name3.5.3-alpinedocker pull maven:3.5.3-alpinesha256:4c4e266aacf8ea6976b52df8467134b9f628cfed347c2f6aaf9e6aff832f7c45 2、下载对应的jdk https://hub.docker.com/_/o…

【银河麒麟操作系统】虚机重启lvs丢失现象分析及处理建议

了解银河麒麟操作系统更多全新产品&#xff0c;请点击访问麒麟软件产品专区&#xff1a;https://product.kylinos.cn 环境及现象描述 40台虚机强制重启后&#xff0c;其中8台虚机找不到逻辑卷导致启动异常&#xff0c;后续通过pvcreate 修复重建pv&#xff0c;激活vg和lv并修复…

矿产资源潜力预测不确定性评价

研究目的&#xff1a; 不确定性评估&#xff1a; 到底什么叫不确定性&#xff0c;简单来说就是某区域内的矿产资源量&#xff0c;并不确定到底有多少&#xff0c;你需要给出一个评估或者分布。 研究方法&#xff1a; 1.以模糊集来表示某些量&#xff1a; 关于什么是模糊集&am…

AWS Aurora Postgres 的开源替代品:存储和计算分离 | 开源日报 No.278

neondatabase/neon Stars: 13.0k License: Apache-2.0 Neon 是一个无服务器的开源替代品&#xff0c;用于 AWS Aurora Postgres。它将存储和计算分离&#xff0c;通过在节点集群中重新分配数据来替换 PostgreSQL 存储层。 提供自动扩展、分支和无限存储。Neon 安装包括计算节…

【常见开源库的二次开发】基于openssl的加密与解密——Base58比特币钱包地址——算法分析(三)

目录&#xff1a; 目录&#xff1a; 一、base58(58进制) 1.1 什么是base58&#xff1f; 1.2 辗转相除法 1.3 base58输出字节数&#xff1a; 二、源码分析&#xff1a; 2.1源代码&#xff1a; 2.2 算法思路介绍&#xff1a; 2.2.1 Base58编码过程&#xff1a; 2.1.2 Base58解码过…

基于高德地图实现Android定位功能实现(二)

基于高德地图实现Android定位功能实现&#xff08;二&#xff09; 在实现的高德地图的基本显示后&#xff0c;我们需要不断完善地图的功能 地图界面设计&#xff08;悬浮按钮等&#xff09; 首先就是地图页面的布局&#xff0c;这个根据大家的实际需求进行设计即可&#xff…

nacos 适配瀚高数据库、ARM 架构

下载nacos源码: https://github.com/alibaba/nacos/tree/2.3.1 瀚高技术文档 1、修改pom.xml 根目录nacos-all => pom.xml<dependencyManagement><dependency><groupId>com.highgo</groupId><artifactId>HgdbJdbc</artifactId><…

xss复习总结及ctfshow做题总结xss

xss复习总结 知识点 1.XSS 漏洞简介 ​ XSS又叫CSS&#xff08;Cross Site Script&#xff09;跨站脚本攻击是指恶意攻击者往Web页面里插入恶意Script代码&#xff0c;当用户浏览该页之时&#xff0c;嵌入其中Web里面的Script代码会被执行&#xff0c;从而达到恶意攻击用户的…

MySQL篇:事务

1.四大特性 首先&#xff0c;事务的四大特性&#xff1a;ACID&#xff08;原子性&#xff0c;一致性&#xff0c;隔离性&#xff0c;持久性&#xff09; 在InnoDB引擎中&#xff0c;是怎么来保证这四个特性的呢&#xff1f; 持久性是通过 redo log &#xff08;重做日志&…

【ARM】MDK-服务器与客户端不同网段内出现卡顿问题

【更多软件使用问题请点击亿道电子官方网站】 1、 文档目标 记录不同网段之间的请求发送情况以及MDK网络版license文件内设置的影响。 2、 问题场景 客户使用很久的MDK网络版&#xff0c;在获取授权时都会出现4-7秒的卡顿&#xff0c;无法对keil进行任何操作&#xff0c;彻底…

java——Junit单元测试

测试分类 黑盒测试&#xff1a;不输入代码&#xff0c;给输入值&#xff0c;看程序能够给出期望的值。 白盒测试&#xff1a;写代码&#xff0c;关注程序具体执行流程。 JUnit单元测试 一个测试框架&#xff0c;供java开发人员编写单元测试。 是程序员测试&#xff0c;即白…

【边缘计算网关教程】6.松下 Mewtocol TCP 协议

前景回顾&#xff1a;【边缘计算网关教程】5.三菱FX3U编程口通讯-CSDN博客 松下 Mewtocol TCP 协议 适配PLC&#xff1a;松下FP0H 松下XHC60ET 1. 硬件连接 Mewtocol TCP协议采用网口通信的方式&#xff0c;因此&#xff0c;只需要保证网关的LAN口和松下PLC的IP在一个网段即…

【车载开发系列】GIT教程---如何下载代码库

【车载开发系列】GIT教程—如何下载代码库 【车载开发系列】GIT教程---如何下载代码库 【车载开发系列】GIT教程---如何下载代码库一. 设置用户名和邮箱二. 生成SSH三. 登录远程github仓库配置四. Git中的ssh协议介绍五. 什么是GitLab六. GitLab与GitHub区别1&#xff09;用途和…

【区块链 + 智慧政务】区块链 +ETC 下一代公路联网收费关键技术优化项目 | FISCO BCOS应用案例

2020 年&#xff0c;我国取消省界收费站项目完成后&#xff0c;随着收费模式与收费方式的变化&#xff0c;形成了以门架为计费单元的新收 费体系&#xff1a;按照车辆通行门架数&#xff0c;RSU 天线读取 ETC 卡、电子标签 OBU 或 CPC 卡内标识的车型信息&#xff0c;车型门架计…

Qt实现MDI应用程序

本文记录Qt实现MDI应用程序的相关操作实现 目录 1.MDM模式下窗口的显示两种模式 1.1TabbedView 页签化显示 1.2 SubWindowView 子窗体显示 堆叠cascadeSubWindows 平铺tileSubWindows 2.MDM模式实现记录 2.1. 窗体继承自QMainWindow 2.2.增加组件MdiArea 2.3.定义统一…

塑胶件缺胶影响工业生产,云盘科技提供解决方案!

塑料件的成型检测&#xff0c;主要检测其中的各种高低、形状的柱子、块块、条条之类的。因为有一些产品在成型时&#xff0c;可能柱子没有足够的料&#xff0c;又或者是某个挡块只有一半这样的。所以需要进行一定的检测。 塑胶在注塑加工成型后&#xff0c;出现缺胶缺陷。思普泰…

RT-DETR+Flask实现目标检测推理案例

今天&#xff0c;带大家利用RT-DETR&#xff08;我们可以换成任意一个模型&#xff09;Flask来实现一个目标检测平台小案例&#xff0c;其实现效果如下&#xff1a; 目标检测案例 这个案例很简单&#xff0c;就是让我们上传一张图像&#xff0c;随后选择一下置信度&#xff0c;…

部署k8s 1.28.9版本

继上篇通过vagrant与virtualBox实现虚拟机的安装。笔者已经将原有的vmware版本的虚拟机卸载掉了。这个场景下&#xff0c;需要重新安装k8s 相关组件。由于之前写的一篇文章本身也没有截图。只有命令。所以趁着现在。写一篇&#xff0c;完整版带截图的步骤。现在行业这么卷。离…

TikTok账号矩阵运营怎么做?

这几年&#xff0c;聊到出海避不过海外抖音&#xff0c;也就是TikTok&#xff0c;聊到TikTok电商直播就离不开账号矩阵&#xff1b; 在TikTok上&#xff0c;矩阵养号已经成为了出海电商人的流行策略&#xff0c;归根结底还是因为矩阵养号可以用最小的力&#xff0c;获得更大的…