分享OpenTiny总结VUE目录结构

OpenTiny总结VUE目录结构,在设计规范和基础组件的基础上, 继续向上构建,提炼出典型模板/业务组件/配套设计资源,进一步提升企业级中后台产品设计研发过程中的『用户』和『设计者』的体验。

Vue 项目目录结构

├── node_modules  (为整个工作空间提供 npm 包)
├── src  (页面代码)
├── env (环境变量配置)
├── .editorconfig
├── .eslintrc.js
├── .gitignore
├── config (为工作区中的所有项目指定 CLI 的默认配置)
├── package.json  (配置工作空间中所有项目可用的 npm 包依赖)
├── README.md
├── tsconfig.json  (工作空间中所有项目的基本 TypeScript 配置)

页面代码结构

src 目录下是页面代码,对于大多数的情况,您只需要开发 src 目录下的文件。 推荐您在开发的过程中,遵守现有的目录结构,以使项目代码的组织结构更加规范。

若一个组件被多个页面所依赖,我们推荐您放到 src/components 中; 若只是被单个页面依赖的组件,我们推荐您放到就近的 view 目录。

|-- src
    |-- index.html  (主要 HTML 页面)
    |-- main.ts  (应用的主要挂载入口)
    |-- api  (包含接口和mock数据的文件)
    |-- assets (包含静态资源,国际化等文件)
    |   |-- style
    |   |-- img
    |-- components  (包含封装的组件文件)
    |   |-- breadcrumb (路由面包屑)
    |   |-- footer (底部)
    |   |-- global-setting (页面陪住)
    |   |-- menu (路由菜单)
    |   |-- navbar (头部导航)
    |   |-- theme (右下角主题切换)
    |-- directive (自定义指令)
    |-- hooks (自定义hook)
    |-- layout (页面布局)
    |-- locale  (国际化配置文件)
    |-- mock  (mock数据)
    |-- router  (router配置)
    |-- store  (pinia定义的状态管理)
    |-- types  (ts定义类型)
    |-- utils  (全局方法)
    |-- views  (项目页面)
    |   |-- board (看板页)
    |   |-- exception (异常页)
    |   |-- form (表单页)
    |   |-- list (列表页)
    |   |-- login (登录页)
    |   |-- not-found (404页)
    |   |-- profile (详情页)
    |   |-- result (结果页)
    |   |-- user (个人中心)
    |-- env (包含特定目标环境的构建配置选项)

在用户使用应用程序时,Vue 的路由器能让用户从一个视图导航到另一个视图。

核心模块和功能

  • 导航

    src/router/routes/modules中根据你的路由进行配置。

  • 路由管理
    • 1.主路由
      src/router/index中进行配置。

    • 2.页面路由
      src/router/routes/modules中进行配置。

  • 面包屑

    可以参考src/compoments/breadcrumb中进行配置。

导航

导航的相关内容可以在src/router/routes/modules中进行修改。 menu数据格式如下所示:

export default {
  path: 'form',
  name: 'Form',
  id: 'Form',
  label: 'Form',
  component: () => import('@/views/form/index.vue'),
  meta: {
    locale: 'menu.form',
    icon: 'icon-settings',
    requiresAuth: true,
    order: 3,
  },
  children: [
    {
      path: 'base',
      name: 'Base',
      id: 'Base',
      label: 'Base',
      component: () => import('@/views/form/base/index.vue'),
      meta: {
        locale: 'menu.form.base',
        requiresAuth: true,
        roles: ['admin'],
      },
    },
    {
      path: 'step',
      name: 'Step',
      id: 'Step',
      label: 'Step',
      component: () => import('@/views/form/step/index.vue'),
      meta: {
        locale: 'menu.form.step',
        requiresAuth: true,
        roles: ['admin'],
      },
    },
  ],
};

注意:在国际化文件中补充对应的修改内容

在导航中使用Vue的图标

menu.ts中为配置项menuIcon传入VueIcon 组件的对应图标名称即可。

路由

项目中的路由分为主路由、页面路由详细配置如下:
主路由的配置文件在src/router/index

const router = createRouter({
  history: createWebHistory(),
  routes: [
    {
      path: '/',
      redirect: import.meta.env.VITE_CONTEXT + 'login',
    },
    {
      path: '/' + import.meta.env.VITE_CONTEXT,
      redirect: import.meta.env.VITE_CONTEXT + 'board/work',
    },
    {
      path: import.meta.env.VITE_CONTEXT + 'login',
      name: 'login',
      component: () => import('@/views/login/index.vue'),
      meta: {
        requiresAuth: false,
      },
    },
    {
      name: 'root',
      path: import.meta.env.VITE_CONTEXT,
      component: DefaultLayout,
      children: appRoutes,
    },
    {
      path: import.meta.env.VITE_CONTEXT + ':pathMatch(.*)*',
      name: 'notFound',
      component: () => import('@/views/not-found/index.vue'),
    },
  ],
});

export default router;

页面路由的配置文件src/router/routes/modules格式为:

export default {
  path: 'form',
  name: 'Form',
  id: 'Form',
  label: 'Form',
  component: () => import('@/views/form/index.vue'),
  meta: {
    locale: 'menu.form',
    icon: 'icon-settings',
    requiresAuth: true,
    order: 3,
  },
  children: [
    {
      path: 'base',
      name: 'Base',
      id: 'Base',
      label: 'Base',
      component: () => import('@/views/form/base/index.vue'),
      meta: {
        locale: 'menu.form.base',
        requiresAuth: true,
        roles: ['admin'],
      },
    },
    {
      path: 'step',
      name: 'Step',
      id: 'Step',
      label: 'Step',
      component: () => import('@/views/form/step/index.vue'),
      meta: {
        locale: 'menu.form.step',
        requiresAuth: true,
        roles: ['admin'],
      },
    },
  ],
};

通过 Breadcrumb 面包屑组件breadcrumb实现,面包屑组件除最后一级外,其余几级一般都为可跳转的链接,链接地址可以通过 href 属性设置; 用户也可通过添加事件,实现业务逻辑, 如下所示:

<breadcrumb class="container-breadcrumb">
    <breadcrumb-item v-for="item in items" :key="item">
      {{ $t(item) }}
    </breadcrumb-item>
  </breadcrumb>

对应的 ts 文件:

import { PropType } from 'vue';
  import {
    Breadcrumb,
    BreadcrumbItem,
  } from '@vue';

  defineProps({
    items: {
      type: Array as PropType<string[]>,
      default() {
        return [];
      },
    },
  });

新增页面

如果你想通过导航栏访问一个新页面,可通过此方法进行操作。新建页面的主要流程为在 src/view 目录中创建对应页面, 然后在模块中创建对应的组件,如果组件中需创建公共组件,则在 src/components 中创建。 下面以新建结果页为例,介绍新建页面的流程。

首先在src/view下新建一个页面:

增加路由访问

以上步骤完成后,需要为新增的页面在导航栏中添加对应的路由访问。

在 src/router/moudles中,添加路由信息。

export default {
  path: 'result',
  name: 'Result',
  id: 'Result',
  label: 'Result',
  component: () => import('@/views/result/index.vue'),
  meta: {
    locale: 'menu.result',
    icon: 'icon-check-circle',
    requiresAuth: true,
    order: 5,
  },
  children: [
    {
      path: 'success',
      name: 'Success',
      id: 'Success',
      label: 'Success',
      component: () => import('@/views/result/success/index.vue'),
      meta: {
        locale: 'menu.result.success',
        requiresAuth: true,
        roles: ['admin'],
      },
    },
    {
      path: 'error',
      name: 'Error',
      id: 'Error',
      label: 'Error',
      component: () => import('@/views/result/error/index.vue'),
      meta: {
        locale: 'menu.result.error',
        requiresAuth: true,
        roles: ['admin'],
      },
    },
  ],
};

Mock 数据

支持不依赖后端,本地方便调试数据。

实现原理

实现前后端的我们需要将 data 文件和 service 文件分隔开。 在Vue中,我们在src/api中定义数据的类型,同时在src/api中实现相关的接口文件。

下面以登录为例,介绍 Mock 数据的使用。

首先需要在src/api/user.ts文件中定义数据参数类型:

import axios from 'axios';
import { UserState } from '@/store/modules/user/types';

export interface LoginData {
  username: string;
  password: string;
}

export function login(data: LoginData) {
  return axios.post<LoginRes>('/api/user/login', data);
}

src/mock/user.ts文件中我们实现接口定义具体要模拟的数据。

{
    url: '/api/user/login',
    method: 'post',
    response: (params: MockParams) => {
      const { username, password } = JSON.parse(JSON.stringify(params.body));
      if (!username) {
        return failResponseWrap(null, '用户名不能为空', 50000);
      }
      if (!password) {
        return failResponseWrap(null, '密码不能为空', 50000);
      }
      if (username === 'admin' && password === 'admin') {
        window.localStorage.setItem('userRole', 'admin');
        return successResponseWrap({
          token: '12345',
        });
      }
      if (username === 'user' && password === 'user') {
        window.localStorage.setItem('userRole', 'user');
        return successResponseWrap({
          token: '54321',
        });
      }
      return failResponseWrap(null, '账号或者密码错误', 50000);
    },
  },

项目中使用

src/view/login中调用你的 service:

   async login(loginForm: LoginData) {
      try {
        const res = await userLogin(loginForm);
        setToken(res.data.token);
      } catch (err) {
        clearToken();
        throw err;
      }
    },

国际化

Vue通过在src/locale的文件夹下添加不同语言的 ts 文件,引入Vue的国际化方案vue-i18n来实现国际化的相关功能。

安装

npm install vue-i18n --save

目录结构

.
├── src/
│   └── locale/
│       │    │── en-US/    (存放所有模块的英文翻译文件)
│       │    │── zh-CN/    (存放所有模块的中文翻译文件)
│       │    │── en-US.ts
│       │    └── zh-CN.ts

添加国际化代码

修改Vue应用入口文件main.ts

export default {
  'settings.title': '页面配置',
  'settings.themeColor': '主题色',
  'settings.content': '内容区域',
  'settings.search': '搜索',
  'settings.language': '语言',
  'settings.navbar': '导航栏',
  'settings.menuWidth': '菜单宽度 (px)',
  'settings.navbar.alerts': '消息通知',
  'settings.navbar.help': '帮助中心',
  'settings.menu': '菜单栏',
  'settings.tabBar': '多页签',
  'settings.footer': '底部',
  'settings.otherSettings': '其他设置',
  'settings.colorWeek': '主题配置',
  'settings.alertContent':
    '配置之后仅是临时生效,要想真正作用于项目,点击下方的 "复制配置" 按钮,将配置替换到 settings.json 中即可。',
  'settings.copySettings': '复制配置',
  'settings.copySettings.message':
    '复制成功,请粘贴到 src/settings.json 文件中',
  'settings.close': '关闭',
  'settings.color.tooltip':
    '根据主题颜色生成的 10 个梯度色(将配置复制到项目中,主题色才能对亮色 / 暗黑模式同时生效)',
  'setting.user.set': '用户设置',
  'setting.loginout': '登出成功',
};

....

zh-CN.ts文件中引入对应的文件:

import localeLogin from '@/views/login/locale/zh-CN';
import localeTheme from '@/components/theme/locale/zh-CN';


export default {
  ...localeTheme,
  ...localeLogin,
};

同理在英文的en-US文件夹下新建模块补充对应的英文翻译,并在en-US.ts的文件中引入。

个性化主题

Vue站点已添加了六套常用的主题(默认主题、糖蜜主题、紫罗兰主题、深邃夜空主题、深色主题、自定义主题)供大家参考,初始化为默认主题风格。

在线主题设置

Vue站点,我们已集成主题切换功能,你可以切换当前站点为我们已内置好的主题风格,并实时预览。

  

src/components/theme组件中,实现主题切换功能

<div class="theme-choose">
      <div>
        <span>Light</span>
        <span>Dark</span>
      </div>
      <div>
        <div v-for="(index, item) in SwitchColor" :key="index">
          <div
            class="theme-block"
            :style="{ 'background-color': item.color }"
            @click="choose(item)"
          >
            <iconYes v-if="item.value === index" class="theme-yes"></iconYes>
          </div>
        </div>
      </div>
const choose = (item: {
    value?: number;
    color?: string;
    dark: any;
    theme: any;
  }) => {
    index.value = item.value;
    theme.changeTheme(item.theme);
    dark.value = item.dark as string;
  };

自定义扩展主题

增加自定义主题类型和自定义主题相关配置,参考src/components/theme/type里面的配置

const Theme = {
  id: 'theme',
  name: 'Theme',
  data: {
    'base-color-brand-1': '#f36b7f;',
    'base-color-brand-2': '#f36b7f;',
    'base-color-brand-3': '#f36b7f;',
    'base-color-brand-4': '#f36b7f;',
    'base-color-brand-5': '#f36b7f;',
    'base-color-brand-6': '#f36b7f;',
    'base-color-brand-7': '#f36b7f;',
    'base-color-brand-8': '#f36b7f;',
  },
};

布局

Vue为页面开发提供了布局组件,并在页面集成常见的布局模式,可快速调整页面的布局方式。

布局组件

<container>
  <template #header>
    <layout>
      <!-- 头部区域 -->
    </layout>
  </template>
  <template #aside>
    <layout class="layout-sider">
      <!-- 侧边栏区域 -->
    </layout>
  </template>
  <layout class="layout-content">
    <!-- 内容区域 -->
  </layout>
  <template #footer>
    <layout>
      <!-- 页脚区域 -->
    </layout>
  </template>
</container>

布局调整

  • 修改src/layout/default-layout.config.ts属性信息文件,可修改页面的布局。
// 是否显示切换框架结构
  const mPattern = ref('legend');

状态管理

Vue通过在src/store的文件,引入Pinia来实现状态管理。

准备工作

安装依赖

npm install pinia -S

main中注册

import { createApp } from 'vue';
import globalComponents from '@/components';
import router from './router';
import store from './store';
import i18n from './locale';
import directive from './directive';
import { setupProdMockServer } from './mockProdServer';
import './mock';
import App from './App.vue';
import '@/api/interceptor';
import '@/assets/style/global.less';

setupProdMockServer();

const app = createApp(App);

app.use(router);
app.use(store);
app.use(i18n({ locale: 'zhCN' }));
app.use(globalComponents);
app.use(directive);

app.mount('#app');

建立store

import { createPinia } from 'pinia';
import useAppStore from './modules/app';
import useUserStore from './modules/user';
import useTabBarStore from './modules/tab-bar';

const pinia = createPinia();

export { useAppStore, useUserStore, useTabBarStore };
export default pinia;

项目中使用

在使用页面中引入你的store

import { useAppStore } from '@/store';
 const appStore = useAppStore();

调用store中的action方法

appStore.updateSettings({ navbar: true, footer: true });

权限管理

Vue通过在src/store/moudles/user文件结合路由,建立switchRoles方法来实现角色权限管理的。

项目使用方式

路由中设置角色显示标签[roles]

export default {
  path: 'exception',
  name: 'Exception',
  id: 'Exception',
  label: 'Exception',
  component: () => import('@/views/exception/index.vue'),
  meta: {
    locale: 'menu.exception',
    requiresAuth: true,
    icon: 'icon-exclamation-circle',
    order: 6,
  },
  children: [
    {
      path: '403',
      name: '403',
      id: '403',
      label: '403',
      component: () => import('@/views/exception/403/index.vue'),
      meta: {
        locale: 'menu.exception.403',
        requiresAuth: true,
        roles: ['admin'],
      },
    },
    {
      path: '404',
      name: '404',
      id: '404',
      label: '404',
      component: () => import('@/views/exception/404/index.vue'),
      meta: {
        locale: 'menu.exception.404',
        requiresAuth: true,
        roles: ['*'],
      },
    },
    {
      path: '500',
      name: '500',
      id: '500',
      label: '500',
      component: () => import('@/views/exception/500/index.vue'),
      meta: {
        locale: 'menu.exception.500',
        requiresAuth: true,
        roles: ['*'],
      },
    },
  ],
};

store中书写`switchRoles`方法

switchRoles() {
      return new Promise((resolve) => {
        this.role = this.role === 'user' ? 'admin' : 'user';
        resolve(this.role);
      });
    },

页面中调用方法,来做到路由权限管理

 const switchRoles = async () => {
    const res = await userStore.switchRoles();
    Modal.message({
      message: res as string,
      status: 'success',
    });
  };

参见:

Vue.js - 渐进式 JavaScript 框架 | Vue.js

Pinia 中文文档

开始 | Vite 官方中文文档

npm Registry and npm CLI

Ant Design of React - Ant Design

Ant Design Vue — An enterprise-class UI components based on Ant Design and Vue.js

TinyPro of Vue - 开箱即用的中台前端/设计解决方案 (opentiny.design)

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

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

相关文章

js实现websocket断线重连功能

在项目开发中我们可能经常要使用websocket技术&#xff0c;当连接发生断线后&#xff0c;如果不进行页面刷新将不能正常接收来自服务端的推送消息。为了有效避免这种问题&#xff0c;我们需要在客户端做断线重连处理。当网络或服务出现问题后&#xff0c;客户端会不断检测网络状…

ubuntu-server部署hive-part3-安装mysql

参照 https://blog.csdn.net/qq_41946216/article/details/134345137 操作系统版本&#xff1a;ubuntu-server-22.04.3 虚拟机&#xff1a;virtualbox7.0 部署mysql 下载上传 下载地址 https://downloads.mysql.com/archives/community/ 以root用户上传&#xff0c;/usr/loc…

Transformer模型-softmax的简明介绍

今天介绍transformer模型的softmax softmax的定义和目的&#xff1a; softmax&#xff1a;常用于神经网络的输出层&#xff0c;以将原始的输出值转化为概率分布&#xff0c;从而使得每个类别的概率值在0到1之间&#xff0c;并且所有类别的概率之和为1。这使得Softmax函数特别适…

利用IP地址判断羊毛用户:IP数据云提供IP风险画像

在当今数字化社会&#xff0c;互联网已经成为人们日常生活和商业活动中不可或缺的一部分。然而&#xff0c;随着网络的普及&#xff0c;网络欺诈行为也日益猖獗&#xff0c;其中包括了羊毛党这一群体。羊毛党指的是利用各种手段获取利益、奖励或者优惠而频繁刷取优惠券、注册账…

微信小程序自定义弹窗组件

业务背景&#xff1a;弹窗有时字体较多&#xff0c;超过7个字&#xff0c;不适用wx.showToast. 组件代码 <view class"toast-box {{isShow? show:}}" animation"{{animationData}}"><view class"toast-content" ><view class&q…

【FTP,EMail】

文章目录 FTPFTP&#xff1a;文件传输协议FTP: 控制连接与数据连接分开FTP命令、响应 EMail电子邮件&#xff08;EMail&#xff09;邮件服务器EMail: SMTP [RFC 2821]SMTP&#xff1a;总结 FTP FTP&#xff1a;文件传输协议 向远程主机上传输文件或从远程主机接收文件。客户/服…

抖音视频关键词批量下载工具|视频爬虫采集软件

抖音视频批量提取工具&#xff0c;搜索即下载&#xff0c;轻松获取所需视频&#xff01; 正文&#xff1a; 想要轻松获取抖音上的精彩视频吗&#xff1f;现在&#xff0c;有了我们的抖音视频批量提取工具&#xff0c;一切变得简单易行&#xff01;Q:290615413无论是针对特定关…

美摄科技AI智能图像矫正解决方案

图像已经成为了企业传播信息、展示产品的重要媒介&#xff0c;在日常拍摄过程中&#xff0c;由于摄影技巧的限制和拍摄环境的复杂多变&#xff0c;许多企业面临着图像内容倾斜、构图效果不佳等挑战&#xff0c;这无疑给企业的形象展示和信息传递带来了不小的困扰。 美摄科技深…

55、美国德克萨斯大学奥斯汀分校、钱德拉家族电气与计算机工程系:通过迁移学习解决BCI个体差异性[不得不说,看技术还得是老美]

2024年2月5日跨被试最新文章&#xff1a; 德州州立大学奥斯汀分校研究团队最近的一项研究成果&#xff0c;通过非侵入式的脑机接口&#xff0c;可以让被试不需要任何校准就可以使用脑机接口设备&#xff0c;这意味着脑机接口具备了大规模被使用的潜力。 一般来说&#xff0c;…

杰理芯片AC79——物联网远程点亮/关闭LED灯

杰理芯片的封装简直太香了&#xff08;比STM32香多了&#xff09;&#xff0c;SDK也封装得很好&#xff0c;对于我这种手残党简直不要太友好。赶紧学起来&#xff0c;快速实现你想要的功能吧&#xff01; 芯片选型 杰理AC79 资料文档 环境搭建以及点亮第一盏灯请访问&#x…

大话设计模式之抽象工厂模式

抽象工厂模式&#xff08;Abstract Factory Pattern&#xff09;是一种创建型设计模式&#xff0c;它提供了一种方式来创建一系列相关或依赖对象的家族&#xff0c;而无需指定其具体类。该模式通过提供一个抽象工厂接口&#xff0c;定义了一组可以创建不同类型对象的方法&#…

【JavaEE】_Spring MVC项目上传文件

目录 1. 文件上传具体实现 2. 保存文件 1. 文件上传具体实现 .java文件内容如下&#xff1a; package com.example.demo.controller;import com.example.demo.Person; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.Multip…

2013年认证杯SPSSPRO杯数学建模A题(第二阶段)护岸框架全过程文档及程序

2013年认证杯SPSSPRO杯数学建模 A题 护岸框架 原题再现&#xff1a; 在江河中&#xff0c;堤岸、江心洲的迎水区域被水流长期冲刷侵蚀。在河道整治工程中&#xff0c;需要在受侵蚀严重的部位设置一些人工设施&#xff0c;以减弱水流的冲刷&#xff0c;促进该处泥沙的淤积&…

SpringData ElasticSearch - 简化开发,完美适配 Spring 生态

目录 一、SpringData ElasticSearch 1.1、环境配置 1.2、创建实体类 1.3、ElasticsearchRestTemplate 的使用 1.3.1、创建索引 设置映射 1.3.2、简单的增删改查 1.3.3、搜索 1.4、ElasticsearchRepository 1.4.1、使用方式 1.4.2、简单的增删改查 1.4.3、分页排序查…

【路径规划论文整理(1)】Path Deformation Roadmaps(附带对PRM改进算法、同伦映射的整理)

本系列主要是对精读的一些关于路径搜索论文的整理&#xff0c;包括了论文所拓展的其他一些算法的改进思路。 这是本系列的第一篇文章&#xff1a; Jaillet, Lonard & Simon, Thierry. (2008). Path Deformation Roadmaps: Compact Graphs with Useful Cycles for Motion Pl…

Windows下编译TinyXML(XML文件解析)

作者&#xff1a;翟天保Steven 版权声明&#xff1a;著作权归作者所有&#xff0c;商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处 TinyXML是什么&#xff1f; TinyXML是一个轻量级的C XML解析器&#xff0c;它提供了一种简单的方法来解析和操作XML文档。TinyXM…

【XR806开发板试用】简单点灯-- 基于SPI控制W2812矩阵幻彩动图和字幕显示系统

1.效果展示 1.gif 动图展示 2.字幕展示 2.软件开发流程 2.1 全志XR806 基本开发流程 使用指南 自己踩过的坑 必须app开头 鸿蒙hb 依赖python 环境。建议使用conda虚拟环境 下载开启硬件校验和烧录重启 2.2 W2812 简单介绍 不是科普文&#xff0c;自行百度 /*WS2812B T…

Mac下Docker Desktop starting的解决方法

记录下自己在新增了一个新的容器后&#xff0c;Disk Size过大导致启动Docker Desktop会一直卡在Docker Desktop starting&#xff0c;并且重启无效的解决方法。该方法无需重新卸载&#xff0c;并且能保留原有的镜像和容器。 一、确认问题 首先确认Docker.raw大小以确认是否和笔…

vivado 高级编程功能1

适用于 7 系列、 UltraScale 和 UltraScale FPGA 和 MPSoC 的回读和验证 为 7 系列器件生成已加密文件和已经过身份验证的文件 注释 &#xff1a; 如需获取其它信息 &#xff0c; 请参阅《使用加密确保 7 系列 FPGA 比特流的安全》 ( XAPP1239 ) 。 要生成加密比特流…

【蓝桥杯嵌入式】13届程序题刷题记录及反思

一、题目分析 考察内容&#xff1a; led按键&#xff08;短按&#xff09;PWM输出&#xff08;PA1&#xff09;串口接收lcd显示 根据PWM输出占空比调节&#xff0c;高频与低频切换 串口接收&#xff08;指令解析&#xff09;【中断接收】 2个显示界面 led灯闪烁定时器 二…