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

news2024/11/8 15:36:01

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


推荐文章👇

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《0基础》学习Python——第十一讲

一、lambda 匿名函数 lambda函数是一种匿名函数。它是一种快速定义单行函数的方法。与常规函数不同&#xff0c;lambda函数没有名称&#xff0c;也没有使用def关键字来定义。lambda函数通常用于一些简单的函数&#xff0c;可以在代码中快速定义和使用&#xff0c;而不需要为其定…

推荐系统:从协同过滤到深度学习

目录 一、协同过滤&#xff08;Collaborative Filtering, CF&#xff09;1. 基于用户的协同过滤2. 基于物品的协同过滤 二、深度学习在推荐系统中的应用1. 深度学习模型的优势2. 深度学习在推荐系统中的应用实例 三、总结与展望 推荐系统是现代信息处理和传播中不可或缺的技术&…

异常检测算法

目录 一、异常检测算法功能&#xff1a;二、正态&#xff08;高斯&#xff09;分布&#xff1a;三、异常检测算法执行过程&#xff1a;四、如何选择特征&#xff1a;五、评估异常检测算法&#xff1a; 一、异常检测算法功能&#xff1a; 异常检测算法用来检测数据集中的一些异…

VsCode 与远程服务器 ssh免密登录

首先配置信息 加入下列信息 Host qb-zn HostName 8.1xxx.2xx.3xx User root ForwardAgent yes Port 22 IdentityFile ~/.ssh/id_rsa 找到自己的公钥&#xff0c;不带pub是私钥&#xff0c;打死都不能给别人。复制公钥 拿到公钥后&#xff0c;来到远程服务器 vim ~/.ss…

LLM 构建Data Multi-Agents 赋能数据分析平台的实践之④:数据分析之三(数据展示)

概述 在先前探讨的文章中&#xff0c;我们构建了一个全面的数据测试体系&#xff0c;该体系遵循“数据获取—数据治理—数据分析”的流程。如何高效地构建数据可视化看板&#xff0c;以直观展现分析结果&#xff0c;正逐渐成为利用新兴技术提升效能的关键领域。伴随业务拓展、数…

前端路由手写Hash和History两种模式

文章目录 1. Hash模式&#xff1a;简洁而广泛适用2. History模式&#xff1a;更自然的用户体验3. 结论 在现代Web开发中&#xff0c;单页面应用&#xff08;Single Page Application&#xff0c;简称SPA&#xff09;因其流畅的用户体验和高效的页面交互能力而备受青睐。前端路由…

C#学习3-微软C#官方文档Microsoft-dotnet-csharp.pdf

文章目录 1.内插表达式的字段宽度和对齐方式 1.内插表达式的字段宽度和对齐方式 static void Main(string[] args) {var titles new Dictionary<string, string>() {["Doyle ,Arthur"] "Hound of the Basker,The",["Lodon ,Jack"] &quo…

数电基础 - 触发器

目录 ​编辑 一. 简介 二. SR锁存器 三. JK 触发器 四. D 触发器 五. 电平触发的触发器 六. 脉冲触发的触发器 七. 边沿触发的触发器 八 . 触发器的逻辑功能和描述方法 一. 简介 触发器是数字电路中的一种基本存储单元&#xff0c;具有记忆功能&#xff0c;能够存储一…

记录些MySQL题集(3)

MySQL 分区技术深入解析 分区的基本概念 MySQL分区 是一种数据库优化的技术&#xff0c;它允许将一个大的表、索引或其子集分割成多个较小的、更易于管理的片段&#xff0c;这些片段称为“分区”。每个分区都可以独立于其他分区进行存储、备份、索引和其他操作。这种技术主要…

【常见开源库的二次开发】基于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解码过…

网络安全 DVWA通关指南 DVWA Brute Force (爆破)

DVWA Brute Force (爆破) 文章目录 DVWA Brute Force (爆破)LowMediumHighImpossible Low 1、分析网页源代码 <?php// 检查是否存在"Login" GET 参数&#xff0c;这通常是提交登录表单后触发的动作 if( isset( $_GET[ Login ] ) ) {// 获取POST方式提交的用户名…

SpringCloud | 单体商城项目拆分(微服务)

为什么要进行微服务拆分&#xff1f; 在平常的商城项目中&#xff0c;我们一般的项目结构模块都是将各种业务放在同一个项目文件夹&#xff0c;比如像&#xff1a; 用户&#xff0c;购物车&#xff0c;商品&#xff0c;订单&#xff0c;支付等业务都是放在一起&#xff0c;这样…

无人机航电系统技术详解

一、系统概述 无人机航电系统&#xff08;Avionics System&#xff09;是无人机飞行与任务执行的核心部分&#xff0c;它集成了飞控系统、传感器、导航设备、通信设备等&#xff0c;为无人机提供了必要的飞行控制和任务执行能力。航电系统的设计和性能直接影响到无人机的安全性…

log4js node日志插件

最近不是特别忙在用express搭建后台项目&#xff0c;在开发过程中遇到了需要输入日志的问 本来想直接用node自带的console来实现&#xff0c;后来发现console输出的日志达不到自己希望的 日志格式&#xff0c;后来各种百度发现了log4js插件&#xff0c;本文来记录log4js插件使用…

关于KafkaTemplate与 @KafkaListener生产者与消费者功能的实现

1.前言&#xff1a; 1.1关于生产者与消费者的详细介绍请查看另一篇文章&#xff1a; 使用JavaApi实现模拟Kafka的消息生产者与发送者http://t.csdnimg.cn/ukNSU 1.2 本文使用 KafkaTemplate与 KafkaListener实现生产者与消费者功能&#xff1a; Kafka 是一个流行的分布式流处…

解决RuntimeError: Couldn‘t load custom C++ ops. This can happen if your PyTorch

问题描述 刚下好yolov8的代码&#xff0c;想测一下能否成果&#xff0c;果然没成功&#xff0c;报错如下 RuntimeError: Couldnt load custom C ops. This can happen if your PyTorch and torchvision versions are incompatible, or if you had errors while compiling tor…

设计模式-创建型模式之工厂方法模式

和简单工厂模式中工厂负责生产所有产品相比&#xff0c;工厂方法模式将生成具体产品的任务分发给具体的产品工厂&#xff0c;定义一个用于创建对象的接口&#xff0c;让子类决定实例化哪个产品类对象。 工厂方法模式的主要角色: 抽象工厂(AbstractFactory):提供了创建产品的接…

C++20中的constinit说明符

constinit说明符断言(assert)变量具有静态初始化&#xff0c;即零初始化和常量初始化(zero initialization and constant initialization)&#xff0c;否则程序格式不正确(program is ill-formed)。 constinit说明符声明具有静态或线程存储持续时间(thread storage duration)的…

代谢组数据分析(十四):代谢物组间网络分析(spearman coefficient)

介绍 在代谢物网络分析领域,研究者采用斯皮尔曼系数来定量评估代谢物之间的相关性。该系数作为一种有效的非参数统计工具,能够揭示代谢物间潜在的关联模式,不受它们分布特性的限制。通过计算所有代谢物配对间的斯皮尔曼系数,研究者能够构建出反映代谢物相互关系的网络。 …

Word创建多级列表的样式

Word创建多级列表的样式 要求结果方法创建样式修改样式设置段落创建快捷键 关联多级列表 要求 创建自定义的三级列表样式&#xff0c;要求标题均为黑体&#xff0c;小四字号&#xff0c;1.5倍行距&#xff0c;有快捷键。 结果 方法 在样式中创建三个样式。 创建样式 录入名…