Vue 3.3 + Vite 4.3 + TypeScript 5+ Element-Plus:从零到一构建企业级后台管理系统(前后端开源)(四)

简介: Vue 3.3 + Vite 4.3 + TypeScript 5+ Element-Plus:从零到一构建企业级后台管理系统(前后端开源)(四)

组件封装

wangEditor 富文本

参考: wangEditor 官方文档


安装 wangEditor


npm install @wangeditor/editor @wangeditor/editor-for-vue@next

1

wangEditor 组件封装

</code></div><div><code>import { onBeforeUnmount, shallowRef, reactive, toRefs } from 'vue';</code></div><div><code>import { Editor, Toolbar } from '@wangeditor/editor-for-vue';</code></div><div><code>// API 引用</code></div><div><code>import { uploadFileApi } from '@/api/file';</code></div><div><code>const props = defineProps({</code></div><div><code>  modelValue: {</code></div><div><code>    type: [String],</code></div><div><code>    default: ''</code></div><div><code>  }</code></div><div><code>});</code></div><div><code>const emit = defineEmits(['update:modelValue']);</code></div><div><code>// 编辑器实例,必须用 shallowRef</code></div><div><code>const editorRef = shallowRef();</code></div><div><code>const state = reactive({</code></div><div><code>  toolbarConfig: {},</code></div><div><code>  editorConfig: {</code></div><div><code>    placeholder: '请输入内容...',</code></div><div><code>    MENU_CONF: {</code></div><div><code>      uploadImage: {</code></div><div><code>        // 自定义图片上传</code></div><div><code>        async customUpload(file: any, insertFn: any) {</code></div><div><code>          uploadFileApi(file).then(response => {</code></div><div><code>            const url = response.data.url;</code></div><div><code>            insertFn(url);</code></div><div><code>          });</code></div><div><code>        }</code></div><div><code>      }</code></div><div><code>    }</code></div><div><code>  },</code></div><div><code>  defaultHtml: props.modelValue,</code></div><div><code>  mode: 'default'</code></div><div><code>});</code></div><div><code>const { toolbarConfig, editorConfig, defaultHtml, mode } = toRefs(state);</code></div><div><code>const handleCreated = (editor: any) => {</code></div><div><code>  editorRef.value = editor; // 记录 editor 实例,重要!</code></div><div><code>};</code></div><div><code>function handleChange(editor: any) {</code></div><div><code>  emit('update:modelValue', editor.getHtml());</code></div><div><code>}</code></div><div><code>// 组件销毁时,也及时销毁编辑器</code></div><div><code>onBeforeUnmount(() => {</code></div><div><code>  const editor = editorRef.value;</code></div><div><code>  if (editor == null) return;</code></div><div><code>  editor.destroy();</code></div><div><code>});</code></div><div><code>


使用案例

</code></div><div><code>import Editor from '@/components/WangEditor/index.vue';</code></div><div><code>const value = ref('初始内容');</code></div><div><code>



效果预览

微信图片_20230706152812.png



Echarts 图表

参考:📊 Echarts 官方示例


安装 Echarts


npm install echarts

1

组件封装

 

</code></div><div><code>import * as echarts from 'echarts';</code></div><div><code>const props = defineProps({</code></div><div><code>  id: {</code></div><div><code>    type: String,</code></div><div><code>    default: 'barChart'</code></div><div><code>  },</code></div><div><code>  className: {</code></div><div><code>    type: String,</code></div><div><code>    default: ''</code></div><div><code>  },</code></div><div><code>  width: {</code></div><div><code>    type: String,</code></div><div><code>    default: '200px',</code></div><div><code>    required: true</code></div><div><code>  },</code></div><div><code>  height: {</code></div><div><code>    type: String,</code></div><div><code>    default: '200px',</code></div><div><code>    required: true</code></div><div><code>  }</code></div><div><code>});</code></div><div><code>const options = {</code></div><div><code>  grid: {</code></div><div><code>    left: '2%',</code></div><div><code>    right: '2%',</code></div><div><code>    bottom: '10%',</code></div><div><code>    containLabel: true</code></div><div><code>  },</code></div><div><code>  tooltip: {</code></div><div><code>    trigger: 'axis',</code></div><div><code>    axisPointer: {</code></div><div><code>      type: 'cross',</code></div><div><code>      crossStyle: {</code></div><div><code>        color: '#999'</code></div><div><code>      }</code></div><div><code>    }</code></div><div><code>  },</code></div><div><code>  legend: {</code></div><div><code>    x: 'center',</code></div><div><code>    y: 'bottom',</code></div><div><code>    data: ['收入', '毛利润', '收入增长率', '利润增长率'],</code></div><div><code>    textStyle: {</code></div><div><code>      color: '#999'</code></div><div><code>    }</code></div><div><code>  },</code></div><div><code>  xAxis: [</code></div><div><code>    {</code></div><div><code>      type: 'category',</code></div><div><code>      data: ['浙江', '北京', '上海', '广东', '深圳'],</code></div><div><code>      axisPointer: {</code></div><div><code>        type: 'shadow'</code></div><div><code>      }</code></div><div><code>    }</code></div><div><code>  ],</code></div><div><code>  yAxis: [</code></div><div><code>    {</code></div><div><code>      type: 'value',</code></div><div><code>      min: 0,</code></div><div><code>      max: 10000,</code></div><div><code>      interval: 2000,</code></div><div><code>      axisLabel: {</code></div><div><code>        formatter: '{value} '</code></div><div><code>      }</code></div><div><code>    },</code></div><div><code>    {</code></div><div><code>      type: 'value',</code></div><div><code>      min: 0,</code></div><div><code>      max: 100,</code></div><div><code>      interval: 20,</code></div><div><code>      axisLabel: {</code></div><div><code>        formatter: '{value}%'</code></div><div><code>      }</code></div><div><code>    }</code></div><div><code>  ],</code></div><div><code>  series: [</code></div><div><code>    {</code></div><div><code>      name: '收入',</code></div><div><code>      type: 'bar',</code></div><div><code>      data: [7000, 7100, 7200, 7300, 7400],</code></div><div><code>      barWidth: 20,</code></div><div><code>      itemStyle: {</code></div><div><code>        color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [</code></div><div><code>          { offset: 0, color: '#83bff6' },</code></div><div><code>          { offset: 0.5, color: '#188df0' },</code></div><div><code>          { offset: 1, color: '#188df0' }</code></div><div><code>        ])</code></div><div><code>      }</code></div><div><code>    },</code></div><div><code>    {</code></div><div><code>      name: '毛利润',</code></div><div><code>      type: 'bar',</code></div><div><code>      data: [8000, 8200, 8400, 8600, 8800],</code></div><div><code>      barWidth: 20,</code></div><div><code>      itemStyle: {</code></div><div><code>        color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [</code></div><div><code>          { offset: 0, color: '#25d73c' },</code></div><div><code>          { offset: 0.5, color: '#1bc23d' },</code></div><div><code>          { offset: 1, color: '#179e61' }</code></div><div><code>        ])</code></div><div><code>      }</code></div><div><code>    },</code></div><div><code>    {</code></div><div><code>      name: '收入增长率',</code></div><div><code>      type: 'line',</code></div><div><code>      yAxisIndex: 1,</code></div><div><code>      data: [60, 65, 70, 75, 80],</code></div><div><code>      itemStyle: {</code></div><div><code>        color: '#67C23A'</code></div><div><code>      }</code></div><div><code>    },</code></div><div><code>    {</code></div><div><code>      name: '利润增长率',</code></div><div><code>      type: 'line',</code></div><div><code>      yAxisIndex: 1,</code></div><div><code>      data: [70, 75, 80, 85, 90],</code></div><div><code>      itemStyle: {</code></div><div><code>        color: '#409EFF'</code></div><div><code>      }</code></div><div><code>    }</code></div><div><code>  ]</code></div><div><code>};</code></div><div><code>onMounted(() => {</code></div><div><code>  // 图表初始化</code></div><div><code>  const chart = echarts.init(</code></div><div><code>    document.getElementById(props.id) as HTMLDivElement</code></div><div><code>  );</code></div><div><code>  chart.setOption(options);</code></div><div><code>  // 大小自适应</code></div><div><code>  window.addEventListener('resize', () => {</code></div><div><code>    chart.resize();</code></div><div><code>  });</code></div><div><code>});</code></div><div><code>

组件使用

</code></div><div><code>import BarChart from './components/BarChart.vue';</code></div><div><code>


效果预览


微信图片_20230706152858.png


图标选择器

组件封装


</code></div><div><code>const props = defineProps({</code></div><div><code>  modelValue: {</code></div><div><code>    type: String,</code></div><div><code>    require: false</code></div><div><code>  }</code></div><div><code>});</code></div><div><code>const emit = defineEmits(['update:modelValue']);</code></div><div><code>const inputValue = toRef(props, 'modelValue');</code></div><div><code>const visible = ref(false); // 弹窗显示状态</code></div><div><code>const iconNames: string[] = []; // 所有的图标名称集合</code></div><div><code>const filterValue = ref(''); // 筛选的值</code></div><div><code>const filterIconNames = ref<string[]>([]); // 过滤后的图标名称集合</code></div><div><code>const iconSelectorRef = ref(null);</code></div><div><code>/**</code></div><div><code> * 加载 ICON</code></div><div><code> */</code></div><div><code>function loadIcons() {</code></div><div><code>  const icons = import.meta.glob('../../assets/icons/*.svg');</code></div><div><code>  for (const icon in icons) {</code></div><div><code>    const iconName = icon.split('assets/icons/')[1].split('.svg')[0];</code></div><div><code>    iconNames.push(iconName);</code></div><div><code>  }</code></div><div><code>  filterIconNames.value = iconNames;</code></div><div><code>}</code></div><div><code>/**</code></div><div><code> * 筛选图标</code></div><div><code> */</code></div><div><code>function handleFilter() {</code></div><div><code>  if (filterValue.value) {</code></div><div><code>    filterIconNames.value = iconNames.filter(iconName =></code></div><div><code>      iconName.includes(filterValue.value)</code></div><div><code>    );</code></div><div><code>  } else {</code></div><div><code>    filterIconNames.value = iconNames;</code></div><div><code>  }</code></div><div><code>}</code></div><div><code>/**</code></div><div><code> * 选择图标</code></div><div><code> */</code></div><div><code>function handleSelect(iconName: string) {</code></div><div><code>  emit('update:modelValue', iconName);</code></div><div><code>  visible.value = false;</code></div><div><code>}</code></div><div><code>/**</code></div><div><code> * 点击容器外的区域关闭弹窗 VueUse onClickOutside</code></div><div><code> */</code></div><div><code>onClickOutside(iconSelectorRef, () => (visible.value = false));</code></div><div><code>onMounted(() => {</code></div><div><code>  loadIcons();</code></div><div><code>});</code></div><div><code>





组件使用

</code></div><div><code>const iconName = ref('edit');</code></div><div><code>



效果预览

微信图片_20230706152918.gif



规范配置

代码统一规范

【vue3-element-admin】ESLint+Prettier+Stylelint+EditorConfig 约束和统一前端代码规范


Git 提交规范

【vue3-element-admin】Husky + Lint-staged + Commitlint + Commitizen + cz-git 配置 Git 提交规范


启动部署

项目启动

# 安装 pnpm

npm install pnpm -g

/

# 安装依赖

pnpm install


# 项目运行

pnpm run dev


项目部署

# 项目打包

pnpm run build:prod

1

2

生成的静态文件在工程根目录 dist 文件夹


FAQ

1: defineProps is not defined

问题描述


‘defineProps’ is not defined.eslint no-undef


微信图片_20230706152934.png


解决方案


根据 Eslint 官方解决方案描述,解析器使用 vue-eslint-parser v9.0.0 + 版本


微信图片_20230706152937.png


安装 vue-eslint-parser 解析器


npm install -D vue-eslint-parser

1

微信图片_20230706152942.png


.eslintrc.js 关键配置( v9.0.0 及以上版本无需配置编译宏 vue/setup-compiler-macros)如下 :


 parser: 'vue-eslint-parser',

 extends: [

   'eslint:recommended',

// ...  

 ],


重启 VSCode 已无报错提示


微信图片_20230706153023.png


2: Vite 首屏加载慢(白屏久)

问题描述


Vite 项目启动很快,但首次打开界面加载慢?


参考文章:为什么有人说 vite 快,有人却说 vite 慢


vite 启动时,并不像 webpack 那样做一个全量的打包构建,所以启动速度非常快。启动以后,浏览器发起请求时, Dev Server 要把请求需要的资源发送给浏览器,中间需要经历预构建、对请求文件做路径解析、加载源文件、对源文件做转换,然后才能把内容返回给浏览器,这个时间耗时蛮久的,导致白屏时间较长。


解决方案升级 vite 4.3 版本

https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md

微信图片_20230706153034.png


结语

本篇从项目介绍、环境准备、VSCode 的代码规范配置 、整合各种框架 、再到最后的启动部署,完整讲述如何基于 Vue3 + Vite4 + TypeScript + Element Plus 等主流技术栈从 0 到 1构建一个企业应用级管理前端框架。


项目有问题建议 issue 或者可以通过项目 关于我们 加入交流群反馈。

目录
打赏
0
0
0
0
42
分享
相关文章
Gzm Design:开源神器!用 Vue3、Vite4、TypeScript 革新海报设计,免费开源的海报设计器,主流技术打造,轻松高效
海报设计在各个领域都有着广泛的应用,无论是商业广告、活动宣传还是个人创意表达。今天要给大家介绍一款免费开源的海报设计器——Gzm Design,它基于最新的主流技术开发,为用户提供了丰富的功能,让海报设计变得轻松又高效。
127 64
Vue Amazing UI 组件库(Vue3+TypeScript+Vite 等最新技术栈开发)
Vue Amazing UI 是一个基于 Vue 3、TypeScript、Vite 等最新技术栈开发构建的现代化组件库,包含丰富的 UI 组件和常用工具函数,并且持续不断维护更新中。另外,组件库全量使用 TypeScript,支持自动按需引入和 Tree Shaking 等,能够显著提升开发效率,降低开发成本。
32 5
Vue Amazing UI 组件库(Vue3+TypeScript+Vite 等最新技术栈开发)
Eliza:TypeScript 版开源 AI Agent 开发框架,快速搭建智能、个性的 Agents 系统
Eliza 是一个开源的多代理模拟框架,支持多平台连接、多模型集成,能够快速构建智能、高效的AI系统。
229 8
Eliza:TypeScript 版开源 AI Agent 开发框架,快速搭建智能、个性的 Agents 系统
在vue3中(vite)引入unocss,安装配置unocss
在vue3中(vite)引入unocss,安装配置unocss
vue3第一章基础:创建Vue3.0工程,包括使用vue-cli 创建、使用 vite 创建
vue3第一章基础:创建Vue3.0工程,包括使用vue-cli 创建、使用 vite 创建
65 5
在 vite+vue 中使用@originjs/vite-plugin-federation 模块联邦
【10月更文挑战第25天】模块联邦是一种强大的技术,它允许将不同的微前端模块组合在一起,形成一个统一的应用。在 vite+vue 项目中,使用@originjs/vite-plugin-federation 模块联邦可以实现高效的模块共享和组合。通过本文的介绍,相信你已经了解了如何在 vite+vue 项目中使用@originjs/vite-plugin-federation 模块联邦,包括安装、配置和使用等方面。在实际开发中,你可以根据自己的需求和项目的特点,灵活地使用模块联邦,提高项目的可维护性和扩展性。
vue3之vite配置vite-plugin-mock使用mock轻松创建模拟数据提高开发效率
vue3之vite配置vite-plugin-mock使用mock轻松创建模拟数据提高开发效率
852 0
vite如何打包vue3插件为JSSDK
【9月更文挑战第10天】以下是使用 Vite 打包 Vue 3 插件为 JS SDK 的步骤:首先通过 `npm init vite-plugin-sdk --template vue` 创建 Vue 3 项目并进入项目目录 `cd vite-plugin-sdk`。接着,在 `src` 目录下创建插件文件(如 `myPlugin.js`),并在 `main.js` 中引入和使用该插件。然后,修改 `vite.config.js` 文件以配置打包选项。最后,运行 `npm run build` 进行打包,生成的 `my-plugin-sdk.js` 即为 JS SDK,可在其他项目中引入使用。
260 6
Vite是什么?怎样使用Vite创建Vue3项目?
Vite是什么?怎样使用Vite创建Vue3项目?
228 0
【Vue 3】一个小巧玲珑的 Vue 组件切换动画库,开源且免费!!
【Vue 3】一个小巧玲珑的 Vue 组件切换动画库,开源且免费!!

热门文章

最新文章