feat: 添加varletUI框架和升级依赖

This commit is contained in:
fonghehe 2022-07-14 18:47:43 +08:00
parent 160b46dc7f
commit d12e073fce
30 changed files with 1456 additions and 500 deletions

View File

@ -15,7 +15,7 @@ module.exports = {
jsx: true,
},
},
extends: ['plugin:vue/vue3-recommended', 'plugin:@typescript-eslint/recommended', 'plugin:prettier/recommended'],
extends: ['plugin:vue/vue3-recommended', 'plugin:@typescript-eslint/recommended', 'prettier', 'plugin:prettier/recommended'],
rules: {
'vue/script-setup-uses-vars': 'error',
'@typescript-eslint/ban-ts-ignore': 'off',

View File

@ -34,10 +34,10 @@ yarn dev
- [√ vite](#vite)
- [√ 配置多环境变量](#env)
- [√ viewport 适配方案](#viewport)
- [nutUI 组件按需加载](#nutUI)
- [多 UI 组件库供选择](#ui)
- [√ Pinia 状态管理](#Pinia)
- [Vue-router4](#router)
- [Axios 封装及接口管理](#axios)
- [vue-router 4](#router)
- [axios 封装及接口管理](#axios)
- [√ vite.config.ts 基础配置](#base)
- [√ alias](#alias)
- [√ proxy 跨域](#proxy)
@ -154,31 +154,33 @@ module.exports = {
[▲ 回顶部](#top)
### <span id="nutUI">✅ nutUI 组件按需加载 </span>
### <span id="ui">✅ 多 UI 组件库供选择 </span>
Vite 构建工具,使用 vite-plugin-style-import 实现按需引入。
Vite 构建工具,使用 vite-plugin-style-import 和 unplugin-vue-components/vite 实现按需引入。
#### 安装插件
```bash
yarn add vite-plugin-style-import -D
yarn add unplugin-vue-components/vite -D
```
`vite.config.ts` 设置
#### 使用组件库
nutUI 没有按需加载的 resolversstyle 需要自己配置按需加载
`config/vite/plugins/styleImport.ts` 设置
```javascript
plugins: [
...
createStyleImportPlugin({
resolves: [NutuiResolve()],
}),
...
],
// 按需加载样式文件
...
createStyleImportPlugin({
resolves: [NutuiResolve()],
}),
...
```
#### 使用组件
项目在 `plugins/nutUI.ts` 下统一管理组件,用哪个引入哪个,无需在页面里重复引用
项目在 `src/plugins/nutUI.ts` 下统一管理组件,用哪个引入哪个,无需在页面里重复引用
```javascript
// 按需全局引入nutUI组件
@ -192,6 +194,25 @@ nutUiComponents.forEach((item) => {
});
```
vant 和 varlet 可以使用组件按需加载
`config/vite/plugins/component.ts`
```javascript
import { VueUseComponentsResolver, VantResolver, VarletUIResolver } from 'unplugin-vue-components/resolvers';
...
resolvers: [VantResolver(), VarletUIResolver()],
...
```
#### 不需要某个组件库
nutUI 需删除`src/plugins/nutUI.ts``main.ts`文件下的引入
vant 和 varlet 只需删除对应的 resolvers 即可
删除后需全局搜索删除不需要的组件
[▲ 回顶部](#top)
### <span id="Pinia">✅ Pinia 状态管理</span>

View File

@ -2,6 +2,7 @@
* @name AutoImportDeps
* @description
*/
import AutoImport from 'unplugin-auto-import/vite';
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers';

View File

@ -2,8 +2,9 @@
* @name AutoRegistryComponents
* @description
*/
import Components from 'unplugin-vue-components/vite';
import { VueUseComponentsResolver, VantResolver } from 'unplugin-vue-components/resolvers';
import { VueUseComponentsResolver, VantResolver, VarletUIResolver } from 'unplugin-vue-components/resolvers';
export const AutoRegistryComponents = () => {
return Components({
// dirs: ['src/components'],
@ -15,6 +16,6 @@ export const AutoRegistryComponents = () => {
directives: true,
include: [/\.vue$/, /\.vue\?vue/, /\.md$/],
exclude: [/[\\/]node_modules[\\/]/, /[\\/]\.git[\\/]/, /[\\/]\.nuxt[\\/]/],
resolvers: [VueUseComponentsResolver(), VantResolver()],
resolvers: [VueUseComponentsResolver(), VantResolver(), VarletUIResolver()],
});
};

View File

@ -2,6 +2,7 @@
* @name ConfigCompressPlugin
* @description .gz压缩
*/
import viteCompression from 'vite-plugin-compression';
export const ConfigCompressPlugin = () => {

View File

@ -2,6 +2,7 @@
* @name ConfigEruda
* @description 便
*/
import eruda from 'vite-plugin-eruda';
export const ConfigEruda = () => {

View File

@ -2,6 +2,7 @@
* @name ConfigImageminPlugin
* @description
*/
import viteImagemin from 'vite-plugin-imagemin';
export function ConfigImageminPlugin() {

View File

@ -2,6 +2,7 @@
* @name createVitePlugins
* @description plugins数组统一调用
*/
import type { Plugin } from 'vite';
import vue from '@vitejs/plugin-vue';
import vueJsx from '@vitejs/plugin-vue-jsx';

View File

@ -2,6 +2,7 @@
* @name ConfigMockPlugin
* @description mockjs
*/
import { viteMockServe } from 'vite-plugin-mock';
export const ConfigMockPlugin = (isBuild: boolean) => {
return viteMockServe({

View File

@ -2,6 +2,7 @@
* @name ConfigPagesPlugin
* @description
*/
import Pages from 'vite-plugin-pages';
export const ConfigPagesPlugin = () => {
return Pages({

View File

@ -2,6 +2,7 @@
* @name ConfigRestartPlugin
* @description Vite
*/
import ViteRestart from 'vite-plugin-restart';
export const ConfigRestartPlugin = () => {
return ViteRestart({

View File

@ -2,10 +2,11 @@
* @name ConfigRestartPlugin
* @description
*/
import { createStyleImportPlugin, NutuiResolve, VantResolve } from 'vite-plugin-style-import';
import { createStyleImportPlugin, NutuiResolve } from 'vite-plugin-style-import';
export const ConfigStyleImport = () => {
return createStyleImportPlugin({
resolves: [NutuiResolve(), VantResolve()],
resolves: [NutuiResolve()],
});
};

View File

@ -2,6 +2,7 @@
* @name SvgIconsPlugin
* @description SVG文件
*/
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons';
import path from 'path';

View File

@ -1,3 +1,8 @@
/**
* @name ConfigVisualizerConfig
* @description
*/
import visualizer from 'rollup-plugin-visualizer';
import { IsReport } from '../../constant';

View File

@ -7,6 +7,7 @@
name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0,viewport-fit=cover"
/>
<meta name="format-detection" content="telephone=no, email=no, date=no, address=no" />
<title>Vite App</title>
</head>
<body>
@ -31,7 +32,7 @@
lastTouchEnd = now;
},
false
false,
);
document.addEventListener('gesturestart', function (event) {

View File

@ -17,23 +17,27 @@
},
"dependencies": {
"@nutui/nutui": "^3.1.22",
"@vueuse/core": "8.9.1",
"@vueuse/integrations": "8.9.1",
"@varlet/ui": "^1.27.17",
"@vueuse/core": "8.9.2",
"@vueuse/integrations": "8.9.2",
"axios": "0.27.2",
"pinia": "^2.0.14",
"pinia": "^2.0.16",
"universal-cookie": "^4.0.4",
"vant": "^3.5.2",
"vue": "^3.2.36",
"vue-i18n": "^9.1.10",
"vue-router": "^4.1.1"
"vue-router": "^4.1.2"
},
"devDependencies": {
"@types/node": "^17.0.42",
"@typescript-eslint/eslint-plugin": "^5.30.5",
"@typescript-eslint/parser": "^5.30.5",
"@vitejs/plugin-legacy": "^1.8.2",
"@vitejs/plugin-vue": "^2.3.3",
"@vitejs/plugin-vue-jsx": "^1.3.10",
"@typescript-eslint/eslint-plugin": "^5.30.6",
"@typescript-eslint/parser": "^5.30.6",
"@vitejs/plugin-legacy": "^2.0.0",
"@vitejs/plugin-vue": "^3.0.0",
"@vitejs/plugin-vue-jsx": "^2.0.0",
"amfe-flexible": "^2.2.1",
"autoprefixer": "^10.4.7",
"cnjm-postcss-px-to-viewport": "^1.0.0",
"consola": "^2.15.3",
"cross-env": "^7.0.3",
"eruda": "^2.5.0",
@ -47,7 +51,6 @@
"postcss": "^8.4.14",
"postcss-html": "1.5.0",
"postcss-less": "^6.0.0",
"postcss-px-to-viewport-8-plugin": "^1.1.3",
"prettier": "^2.7.1",
"rollup-plugin-visualizer": "^5.6.0",
"stylelint": "^14.9.1",
@ -57,21 +60,21 @@
"stylelint-config-standard": "^26.0.0",
"stylelint-order": "^5.0.0",
"typescript": "^4.6.3",
"unplugin-auto-import": "^0.9.2",
"unplugin-auto-import": "^0.9.3",
"unplugin-vue-components": "^0.21.1",
"vite": "^2.9.14",
"vite": "^3.0.0",
"vite-plugin-compression": "^0.5.1",
"vite-plugin-eruda": "^1.0.1",
"vite-plugin-imagemin": "^0.6.1",
"vite-plugin-mock": "^2.9.6",
"vite-plugin-pages": "^0.25.0",
"vite-plugin-progress": "^0.0.3",
"vite-plugin-restart": "^0.1.1",
"vite-plugin-restart": "^0.2.0",
"vite-plugin-style-import": "^2.0.0",
"vite-plugin-svg-icons": "^2.0.1",
"vite-plugin-vue-setup-extend": "^0.4.0",
"vue-eslint-parser": "^9.0.3",
"vue-tsc": "^0.38.2"
"vue-tsc": "^0.38.5"
},
"husky": {
"hooks": {

View File

@ -1,8 +1,16 @@
const path = require('path');
const judgeComponent = (file) => {
const ignore = ['vant', '@nutui', '@varlet'];
return ignore.some((item) => path.join(file).includes(path.join('node_modules', item)));
};
module.exports = {
plugins: {
'postcss-px-to-viewport-8-plugin': {
autoprefixer: { overrideBrowserslist: ['Android 4.1', 'iOS 7.1', 'Chrome > 31', 'ff > 31', 'ie >= 8'] },
'cnjm-postcss-px-to-viewport': {
unitToConvert: 'px', // 要转化的单位
viewportWidth: 375, // UI设计稿的宽度
viewportWidth: 750, // UI设计稿的宽度
unitPrecision: 6, // 转换后的精度,即小数点位数
propList: ['*'], // 指定转换的css属性的单位*代表全部css属性的单位都进行转换
viewportUnit: 'vw', // 指定需要转换成的视窗单位默认vw
@ -10,7 +18,13 @@ module.exports = {
minPixelValue: 1, // 默认值1小于或等于1px则不进行转换
mediaQuery: true, // 是否在媒体查询的css代码中也进行转换默认false
replace: true, // 是否转换后直接更换属性值
exclude: [/node_modules/], // 设置忽略文件,用正则做目录名匹配
include: [],
exclude: [], // 设置忽略文件,用正则做目录名匹配
customFun: ({ file }) => {
// 这个自定义的方法是针对处理vant组件下的设计稿为375问题
const designWidth = judgeComponent(file) ? 375 : 750;
return designWidth;
},
},
},
};

View File

@ -1,12 +1,17 @@
export const lang = {
title: 'VUE H5 development template',
tabbar: {
home: 'Home',
list: 'List',
member: 'Member',
demo: 'demo',
},
language: {
en: 'English',
zh: 'Chinese',
},
introduction: 'A rapid development vue3 of mobile terminal template',
home: {
support: 'support',
},
};

View File

@ -1,8 +1,10 @@
export const lang = {
title: 'VUE H5开发模板',
tabbar: {
home: '首页',
list: '列表',
member: '我的',
demo: '示例',
},
language: {
en: '英文',

View File

@ -1,15 +1,22 @@
<template>
<nut-navbar :left-show="false" :title="$t($route.meta.title)" />
<div class="main-page">
<router-view v-slot="{ Component }">
<keep-alive>
<router-view v-if="$route.meta.keepAlive" :key="$route.path" />
</keep-alive>
<router-view v-if="!$route.meta.keepAlive" :key="$route.path" />
<!-- <RouterView v-slot="{ Component }" v-if="$route.meta.keepAlive">
<keep-alive>
<component :is="Component" />
<component :is="Component" :key="$route.path" />
</keep-alive>
</router-view>
</RouterView>
<RouterView v-if="!$route.meta.keepAlive" :key="$route.path" /> -->
</div>
<nut-tabbar unactive-color="#364636" active-color="#1989fa" @tab-switch="tabSwitch" bottom>
<nut-tabbar-item :tab-title="$t('tabbar.home')" font-class-name="iconfont" class-prefix="icon" icon="home" />
<nut-tabbar-item :tab-title="$t('tabbar.list')" font-class-name="iconfont" class-prefix="icon" icon="list" />
<nut-tabbar-item :tab-title="$t('tabbar.member')" font-class-name="iconfont" class-prefix="icon" icon="member" />
<nut-tabbar-item :tab-title="$t('tabbar.home')" icon="home" />
<nut-tabbar-item :tab-title="$t('tabbar.list')" icon="horizontal" />
<nut-tabbar-item :tab-title="$t('tabbar.member')" icon="my" />
<nut-tabbar-item :tab-title="$t('tabbar.demo')" icon="location" />
</nut-tabbar>
</template>
@ -29,13 +36,21 @@
case 2:
router.push('/member');
break;
case 3:
router.push('/demo');
}
};
</script>
<style scoped lang="scss">
.nut-navbar {
margin-bottom: 0;
}
.main-page {
height: calc(100vh - 50px);
box-sizing: border-box;
padding: 40px;
height: calc(100vh - 88px);
overflow-y: scroll;
overflow-x: hidden;
}

View File

@ -2,19 +2,26 @@ import { createApp } from 'vue';
import App from './App.vue';
import { nutUiComponents } from './plugins/nutUI';
import { i18n } from '/@/i18n';
import router from './router';
import { setupStore } from '/@/store';
import router from '/@/router';
import store from '/@/store';
import './assets/font/iconfont.css';
import './assets/app.css';
import 'amfe-flexible';
const app = createApp(App);
// 路由
app.use(router);
setupStore(app);
// 国际化
app.use(i18n);
app.mount('#app');
// 状态管理
app.use(store);
// nutUi按需加载
nutUiComponents.forEach((item) => {
app.use(item);
});
app.mount('#app');

View File

@ -1,8 +1,8 @@
import { createRouter, createWebHashHistory, Router } from 'vue-router';
import { createRouter, createWebHistory, Router } from 'vue-router';
import routes from './routes';
const router: Router = createRouter({
history: createWebHashHistory('/'),
history: createWebHistory('/'),
routes: routes,
});

View File

@ -8,7 +8,7 @@ const routes = [
path: 'home',
component: () => import('/@/views/home/index.vue'),
meta: {
title: '',
title: 'tabbar.home',
keepAlive: true,
},
},
@ -16,7 +16,7 @@ const routes = [
path: 'list',
component: () => import('/@/views/list/index.vue'),
meta: {
title: '',
title: 'tabbar.list',
keepAlive: true,
},
},
@ -24,7 +24,15 @@ const routes = [
path: 'member',
component: () => import('/@/views/member/index.vue'),
meta: {
title: '',
title: 'tabbar.member',
keepAlive: true,
},
},
{
path: 'demo',
component: () => import('/@/views/demo/index.vue'),
meta: {
title: 'tabbar.demo',
keepAlive: true,
},
},

View File

@ -1,10 +1,5 @@
import type { App } from 'vue';
import { createPinia } from 'pinia';
const store = createPinia();
export function setupStore(app: App<Element>) {
app.use(store);
}
export { store };
export default store;

55
src/views/demo/index.vue Normal file
View File

@ -0,0 +1,55 @@
<template>
<section>
<span class="title">varlet</span>
<var-space :size="[10, 10]">
<var-button>demo</var-button><var-button type="primary">主要按钮</var-button>
<var-button type="info">信息按钮</var-button>
<var-button type="success">成功按钮</var-button>
<var-button type="warning">警告按钮</var-button>
<var-button type="danger">危险按钮</var-button>
</var-space>
</section>
<section>
<span class="title">vant</span>
<div class="demo">
<van-button type="primary">主要按钮</van-button>
<van-button type="success">成功按钮</van-button>
<van-button type="default">默认按钮</van-button>
<van-button type="warning">警告按钮</van-button>
<van-button type="danger">危险按钮</van-button>
</div>
</section>
<section>
<span class="title">vnutUI</span>
<div class="demo">
<nut-button type="primary">主要按钮</nut-button>
<nut-button type="info">信息按钮</nut-button>
<nut-button type="default">默认按钮</nut-button>
<nut-button type="danger">危险按钮</nut-button>
<nut-button type="warning">警告按钮</nut-button>
<nut-button type="success">成功按钮</nut-button>
</div>
</section>
</template>
<script setup></script>
<style lang="scss" scoped>
section {
.title {
margin-bottom: 40px;
display: inline-block;
}
&:nth-child(2) {
.title {
margin-top: 20px;
}
}
}
.demo {
> :nth-child(n) {
margin-right: 20px;
margin-bottom: 20px;
}
}
</style>

View File

@ -1,20 +1,15 @@
<template>
<nut-navbar :left-show="false" :title="$t('tabbar.home')" />
<header class="header"> <img src="https://www.sunniejs.cn/static/weapp/logo.png" /><span> VUE H5开发模板</span> </header>
<p class="intro-header">
{{ $t('introduction') }}
<header class="header">
<img src="https://www.sunniejs.cn/static/weapp/logo.png" /><span> {{ $t('title') }}</span>
</header>
<div class="intro-header">
<div>{{ $t('introduction') }}</div>
<a href="https://github.com/sunniejs/vue-h5-template.git">
<nut-icon class="github-icon" name="github" />
<nut-icon name="github" />
</a>
</p>
</div>
<nut-cell-group :title="$t('home.support')" class="supportList">
<nut-cell title="Vue3" icon="Check" />
<nut-cell title="Vue-router" icon="Check" />
<nut-cell title="Axios" icon="Check" />
<nut-cell title="Pinia" icon="Check" />
<nut-cell title="NutUI" icon="Check" />
<nut-cell title="Vue-i18n" icon="Check" />
<nut-cell title="Jsx" icon="Check" />
<nut-cell v-for="(item, index) in cellList" :key="index" :title="item" icon="Check" />
</nut-cell-group>
<div class="btn-wrap">
<nut-button shape="square" size="small" type="default" @click="changeLang('zh-cn')">
@ -32,11 +27,13 @@
import { useUserStore } from '/@/store/modules/user';
import { setLang } from '/@/i18n';
let cellList = ['vue3', 'vite', 'vue-router', 'axios', 'Pinia', 'vue-i18n', 'vue-jsx', 'vatlet/vant/nutUI'];
const userStore = useUserStore();
const getUserInfo = computed(() => {
const { name = '' } = userStore.getUserInfo || {};
return name;
});
const changeLang = (type) => {
setLang(type);
};
@ -45,36 +42,34 @@
.header {
display: flex;
justify-content: center;
margin: 26px 0 10px;
align-items: center;
padding: 0 20px;
height: 50px;
height: 30px;
font-size: 20px;
}
.intro-title {
text-align: center;
font-size: 40px;
img {
width: 90px;
height: 90px;
}
}
.intro-header {
height: 30px;
margin-top: 20px;
display: flex;
align-items: center;
justify-content: center;
font-size: 16px;
text-align: center;
}
.supportList {
margin: 0 16px;
.nut-cell-group__title {
margin-top: 30px;
}
.nut-icon {
color: green;
}
}
.github-icon {
margin-top: 4px;
font-size: 24px;
}
.btn-wrap {
margin: 20px;
}

View File

@ -1,5 +1,4 @@
<template>
<nut-navbar :left-show="false" :title="$t('tabbar.list')" />
<nut-card :img-url="state.imgUrl" :title="state.title" :price="state.price" :vip-price="state.vipPrice" :shop-name="state.shopName" />
</template>

View File

@ -1,5 +1,4 @@
<template>
<nut-navbar :left-show="false" :title="$t('tabbar.member')" />
<div class="avatar-wrap">
<nut-avatar
class="avatar"
@ -41,16 +40,20 @@
<style lang="scss">
.avatar-wrap {
display: flex;
margin: 30px;
height: 50px;
margin: 0 10px 40px;
align-items: center;
.member-detail {
margin-left: 20px;
.nickname {
font-size: 16px;
font-weight: bold;
.nut-button {
margin-left: 10px;
}
}
.info {
margin-top: 10px;
font-size: 16px;
}
}
}

View File

@ -10,5 +10,8 @@ declare module '@vue/runtime-core' {
RouterLink: typeof import('vue-router')['RouterLink'];
RouterView: typeof import('vue-router')['RouterView'];
TitleBar: typeof import('./../src/components/TitleBar/index.vue')['default'];
VanButton: typeof import('vant/es')['Button'];
VarButton: typeof import('@varlet/ui')['_ButtonComponent'];
VarSpace: typeof import('@varlet/ui')['_SpaceComponent'];
}
}

1628
yarn.lock

File diff suppressed because it is too large Load Diff