umi插件开发仿dumi项目实现页面布局详解

目录
  • 实现思路
  • 使用默认项目提供的layout文件
  • 自定义主题
    • 准备工作
    • 主题插件功能
    • modifyAppData
    • 插件代码
    • 生成layout路由对象
  • 使用同步伪代码来描述上面流程
  • 运行检查

实现思路

上一章我们已经完成/docs目录下文件自动生路由功能,本章我们将在此基础上,实现自动生成页面导航的功能。

  • 使用默认模板提供的layout展示路由切换
  • 使用自定义主题插件

使用默认项目提供的layout文件

在我们创建默认umi项目后,会在/src/layouts下生成一个布局文件:

同时在上一章节我们打印modifyRouteshook的入参,可以看到umi会将该文件转成一个layout router对象,如图所示:

因此我们可以直接将这个layout的id属性,赋值到自动生成的路由的parentId属性上,并添加该对象到返回值中:

// /src/features/routes.ts
import path from 'path';
import type { IApi } from 'umi';
import type { IRoute } from '@umijs/core/dist/types';
import { getConventionRoutes } from '@umijs/core';
export default (api: IApi) => {
  api.describe({ key: 'domi:routes' });
  api.modifyRoutes((oRoutes: Record<string, IRoute>) => {
    const routes: Record<string, IRoute> = {}
    const docDir = 'docs'
    // 获取某个目录下所有可以配置成umi约定路由的文件
    const dirRoutes: Record<string, IRoute> = getConventionRoutes({
      base: path.join(api.cwd, docDir),
    });
    // 默认提供的布局layout的Id
    let docLayoutId : undefined | string = '@@/global-layout';
    // 从旧路由对象中获取放入返回值中
    routes[docLayoutId] = oRoutes[docLayoutId]
    Object.entries(dirRoutes).forEach(([key, route]) => {
      // 这里将文件的路径改为绝对路径,否则umi会默认找/src/pages下组件
      route.file = path.resolve(docDir, route.file);
      // 给页面对象赋值布局Id
      route.parentId = docLayoutId
      routes[route.id] = route;
    });
    return routes;
  });
};

同时我们修改布局文件,将导航改成我们的测试页面路由:

// /src/layouts/index.tsx
import { Link, Outlet } from 'umi';
import styles from './index.less';
export default function Layout() {
  return (
    <div className={styles.navs}>
      <ul>
        <li><Link to="/">Home</Link></li>
        <li><Link to="/button">Button</Link></li>
      </ul>
      <Outlet />
    </div>
  );
}

运行项目可以看到布局文件已添加到页面中,并可以切换路由:

自定义主题

上面我们通过最简单的方式使用了默认提供的布局文件,这种方式对页面局限性比较大,由于各个项目对页面的展示要求不一样,dumi提供了主题插件来灵活扩展用户自定义布局。同时提供了默认主题,用户可以选择性覆盖默认样式。

本节我们将实现其中的默认主题加载

准备工作

创建主题插件,并注册到插件配置中

mkdir /src/features/theme.ts
import { defineConfig } from "umi";
export default defineConfig({
    plugins: [
        './src/features/routes.ts',
        './src/features/theme.ts',
    ],
});

创建默认主题目录,将/src/layouts/index.tsx文件复制到这里

mkdir /src/client/theme-default/layouts/DocLayout
cp /src/layouts/index.tsx /src/client/theme-default/layouts/DocLayout/index.tsx
cp /src/layouts/index.less /src/client/theme-default/layouts/DocLayout/index.less

然后/src/layouts就没用了,可以删掉

主题插件功能

dumi主题插件主要提供的功能有:

  • 加载默认主题布局文件
  • 加载国际化语言包
  • 合并默认主题及自定义主题
  • ...等其他与页面相关功能

本章我们将实现默认布局的加载,并配置到路由中。

modifyAppData

umi提供modifyAppData钩子,用于初始收集应用数据,在dumi中使用这个钩子来初始化主题数据。

我们在主题插件中提供的主题数据后续会被用在修改路由中,即在modifyRoutes阶段使用。因为modifyRoutes是在appData插件的modifyAppData阶段中执行,所以通过before: 'appData让主题插件的modifyAppDataappData插件的modifyAppData之前先初始化完成,这样在modifyRoutes中就可以使用到主题数据。

插件代码

// /src/features/theme.ts
import path from 'path';
import type { IApi } from 'umi';
import { glob, winPath } from 'umi/plugin-utils';
const DEFAULT_THEME_PATH = path.join(__dirname, '../../src/client/theme-default');
export default async(api: IApi) => {
    api.describe({ key: 'domi:theme' });
    api.modifyAppData({
      before: 'appData',
      async fn(memo: any) {
        const defaultThemeData = loadTheme(DEFAULT_THEME_PATH);
        // @ts-ignore
        api.service.themeData = defaultThemeData
        return memo;
      },
    });
}
/**
 * 加载主题信息
 */
function loadTheme(dir: string) {
    return {
      name: path.basename(dir),
      path: dir,
      layouts: getComponentMapFromDir(
        'layouts/{GlobalLayout,DocLayout,DemoLayout}{.,/index.}{js,jsx,ts,tsx}',
        dir,
      ),
    };
};
/**
 * 提取dir目录下符合条件的组件信息
 */
function getComponentMapFromDir(globExp: string, dir: string) {
    return glob
      .sync(globExp, { cwd: dir })
      .reduce<any>((ret, file) => {
        const specifier = path.basename(
          winPath(file).replace(/(\/index)?\.[a-z]+$/, ''),
        );
        // ignore non-component files
        if (/^[A-Z\d]/.test(specifier)) {
          ret[specifier] = {
            specifier,
            source: winPath(path.join(dir, file)),
          };
        }
        return ret;
    }, {});
}

另一个比较不优雅的地方是这里使用了api.service来存储生成的主题数据,同样因为上面提到的阶段问题,modifyRoutes是在modifyAppData中执行,所以这里只能用全局变量来存储,否则在修改路由阶段拿不到这里的数据。

执行完成后,api.service.themeData就得到了主题相关的数据:

{
  name: 'theme-default',
  path: 'D:\\project\\domi\\src\\client\\theme-default',
  layouts: {
    DocLayout: {
      specifier: 'DocLayout',
      source: 'D:/project/domi/src/client/theme-default/layouts/DocLayout/index.tsx'
    }
  }
}

生成layout路由对象

前面我们使用了模板自带的对象@@/global-layout作为布局模板,现在我们可以将它改成动态添加主题布局。

我们直接在路由插件中使用主题插件中生成的布局数据,代码很简单,根据前面的layout来生成一个布局路由,并添加到返回值中即可,这样所有parentIdDocLayout.specifier的页面就能使用该布局了。

// /src/features/routes.ts
...
let docLayoutId : undefined | string = undefined;
// @ts-ignore
const { DocLayout } = api.service.themeData.layouts;
// 从旧路由对象中获取放入返回值中
if (DocLayout) {
  docLayoutId = DocLayout.specifier;
  routes[DocLayout.specifier] = {
    id: DocLayout.specifier,
    path: '/',
    file: DocLayout.source,
    parentId: undefined,
    absPath: '/',
    isLayout: true,
  };
}
...

使用同步伪代码来描述上面流程

// /umi/packages/core/src/service/service.ts 中代码
service.collectAppData() {
    // /src/features/theme.ts中代码
    // 配置before: 'appData' 使其先于appData.modifyAppData执行
    themePlugin.modifyAppData() {
        // 这里加载主题数据
        api.service.themeData = loadTheme(DEFAULT_THEME_PATH);
    }
    // /umi/packages/preset-umi/src/features/appData/appData.ts 中代码
    appDataPlugin.modifyAppData() {
        // /src/features/routes.ts中代码
        routesPlugin.modifyRoutes() {
            // 这里使用主题数据生成布局路由
            const { DocLayout } = api.service.themeData.layouts;
            routes[DocLayout.specifier] = {
                ...
                isLayout: true,
            };
        }
    }
}

运行检查

至此我们已经完成生成默认布局,实现了简易的主题插件,运行代码可以看到和上节运行结果一样:

路由和页面问题基本解决了,接下来就要开始正式解析markdown文件。

以上就是umi插件开发仿dumi项目实现页面布局详解的详细内容,更多关于umi插件仿dumi页面布局的资料请关注我们其它相关文章!

(0)

相关推荐

  • umi插件开发仿dumi项目加载markdown文件实现详解

    目录 引言 为什么不能直接展示markdown chainWebpack webpack loader 实现过程 新建插件 新建loader 新建测试文档 运行项目 解决文件加载类型错误 webpack ruletype 解决错误 引言 前面章节中我们已经顺利将tsx组件转换为页面展示,但是目前提供的功能和umi的约定式路由功能差不多,接下来我们将实现将markdown文件转换为页面展示. 为什么不能直接展示markdown 我们前面所使用的页面写法都是react组件式写法,umi通过webpa

  • 独立使用umi的核心插件模块示例详解

    目录 引言 实践 结语 引言 今天我们做一个有趣的尝试,将 umi 的核心插件模块独立出来作为另一个框架的基础架构,这里我们将它称为 konos. 介于 umi 自身的源码的独立拆分,要实现这个功能其实非常的简单.只需要单独使用 @umijs/core 就好. 实践 先看具体实践吧.以下步骤都是常规编写 cli 的一些步骤,我就不做过多的说明,如果你看不懂其中的某些代码,可以评论区留言,或者查看我的其他文章. 新建空白文件夹,mkdir konos 你可以根据你使用的电脑执行对应的命令来新建一个

  • Umi4集成阿里低代码框架lowcode-engine实现

    目录 前言 实现 搭建umi4项目 集成lowcode-engine 结束语 前言 最近准备研究下阿里低代码框架lowcode-engine, 官方Demo是提供好的脚手架,由于我们的框架使用的是umi,官方文档提供了一些教程,在此记录下在umi4集成lowcode-engine. 实现 搭建umi4项目 1.通过官方文档的快速开始,我们可以快速创建出项目 先找个地方建个空目录 mkdir myapp && cd myapp 通过官方工具创建项目, 这里我们采用pnpm包管理工具 $ pn

  • 如何在Laravel之外使用illuminate组件详解

    当代框架基本都是有组件构成,这使得框架变得更加灵活.The Laravel Components | github Laravel 中有不少优质组件,那如何在 Laravel 之外使用 illuminate 组件呢? illuminate/validation 以 illuminate/validation 为例,validation 有丰富的数据验证功能. 在项目的 composer.json 文件中添加: ... "require": { ... "illuminate/

  • umi插件开发仿dumi项目实现markdown文件转为页面

    目录 引言 处理导入错误 loader返回渲染函数 添加react处理loader 用ts来写loader 改变原来的loader 创建新的loader 配置webpack 引言 前面我们已经成功将.md文件通过import加载到react组件中,并能拿到文件内容进行展示.但是点击markdown的导航链接还是会报错: 这个报错和前面的报错有点相似,只是前面是无法解析链接,这里是无法解析对象. 处理导入错误 在react渲染页面时,是调用一个个渲染函数来渲染页面,我们来对比一下button页和m

  • umi插件开发仿dumi项目自动生成导航栏实现详解

    目录 引言 获取路由信息 创建获取导航数据hook Layout中使用 引言 前面我们已经完成了页面布局和页面路由,现在我们的导航栏还是自己写死在代码中,现在我们来改造成自动根据页面路由来生成导航栏. 获取路由信息 我们在前面创建的路由对象,会被umi存入appData对象中,umi提供了useAppDataAPI可以用于获取路由信息. 创建获取导航数据hook // /src/client/theme-api/useNavData.ts import { useAppData } from "

  • JavaScript @umijs/plugin-locale插件使用教程

    目录 介绍 启用方式 使用 App.ts配置 在组件中使用 getAllLocales getLocale useIntl setLocale 介绍 plugin-locale是一个国际化的插件,用于解决i18n问题,约定式的多语言支持,可以进行多个国际语言的切换 启用方式 在umirc.ts文件中配置locale:{}开启 使用 在src下创建一个locales文件夹,在文件夹下配置我们的语言文件 中文语言文件:zh-CN.js export default { WELCOME_TO_UMI_

  • umi插件开发仿dumi项目实现页面布局详解

    目录 实现思路 使用默认项目提供的layout文件 自定义主题 准备工作 主题插件功能 modifyAppData 插件代码 生成layout路由对象 使用同步伪代码来描述上面流程 运行检查 实现思路 上一章我们已经完成/docs目录下文件自动生路由功能,本章我们将在此基础上,实现自动生成页面导航的功能. 使用默认模板提供的layout展示路由切换 使用自定义主题插件 使用默认项目提供的layout文件 在我们创建默认umi项目后,会在/src/layouts下生成一个布局文件: 同时在上一章节

  • vue cli实现项目登陆页面流程详解

    目录 1. 搭建项目 1.1 使用vue-cli创建项目 1.2 通过npm安装element-ui 1.3 导入组件 2 创建登录页面 2.1 创建登录组件 2.2 引入css(css.txt) 2.3 配置路由 2.4 在Login组件中将提交按键调整为100%宽度 2.5 运行效果 3. 后台交互 3.1 引入axios 3.2 axios/qs/vue-axios安装与使用 3.2.1 安装axios 3.2.2 发送get请求 3.2.3 发送post请求 3.2.4 简化axios使

  • 创建Go工程化项目布局详解

    目录 正文 /cmd /internal /pkg /docs,/example,/pkg,/third_parth,/tools 基础库项目布局 kit包应该具备的特点 应用程序项目布局 /api /configs /test 不应该包含/src目录 /internal /biz /data /service 布局示意图 数据流向 正文 如果你尝试学习Go,或者你正在为自己建立一个Poc或者一个玩具项目,这个项目布局是没有啥必要的,从一些简单的事情开始(一个main文件绰绰有余).当有更多的人

  • Vue-cli3多页面配置详解

    Vue-cli3发布已经好长时间了,笔者也在一直使用,由于公司业务需要要使用多页面配置,于是花时间研究了一下Vue-cli3如何配置多页面.由于Vue-cli3相比之前的版本做了很大的改动,在研究过程中也遇到一些问题. 对于Vue-cli3创建项目这里就不做太多的赘述了,毕竟不属于本文内容,有关相关博客也有很多,大家可以自行Google一下就好了. 多页面应用(mpa)与单页面应用(spa)优缺点 在项目中我们用到的大多数都是单页面应用(spa),对于多页面可能用到的比较少一些,具体还是要根据具

  • bing Map 在vue项目中的使用详解

    写在最前面 拥有全球数据库国内好像就只有百度地图有,高德.搜狗.腾讯的都不行,但是由于百度地图的数据更新不及时,所以在做相关项目要用到国外数据的时候,最好还是推荐使用bingMap. bing Map 使用教程(基础) 参考文档:bing Map 官方教程 bing Map 初始化 引入bing map资源 <script type='text/javascript' src='http://www.bing.com/api/maps/mapcontrol?callback=GetMap&k

  • 基于mpvue搭建微信小程序项目框架的教程详解

    简介: mpvue框架对于从没有接触过小程序又要尝试小程序开发的人员来说,无疑是目前最好的选择.mpvue从底层支持 Vue.js 语法和构建工具体系,同时再结合相关UI组件库,便可以高效的实现小程序开发 前言: 本文讲述如何搭建完整的小程序项目框架,因为是第一次使用,有不完善的地方请大佬指正. 搭建内容包括: 1.使用scss语法:依赖插件sass-loader .node-sass 2.像vue一样使用路由:依赖插件 mpvue-entry 和 mpvue-router-patch 3.使用

  • python框架django项目部署相关知识详解

    这篇文章主要介绍了python框架django项目部署相关知识详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一:项目部署的框架 nginx和uWSGI在生产服务器上进行的部署 二:什么是nginx? nginx是一个web服务器. 什么是web服务器? web服务器则主要是让客户可以通过浏览器进行访问,处理HTML文件,css文件,js文件,图片等资源.web服务器一般要处理静态文件.对接服务器. 什么是静态文件? css,js,html

  • Visual Studio 2019配置vue项目的图文教程详解

    一,环境安装 1:Vue项目一切基于Node.js,必须先安装NodeJS, 下载地址:https://nodejs.org/zh-cn/ 安装nodejs,一路next就行了 Additonal工具可以不用安装. win+r 输入cmd 输入 node -v 和 npm -v 得到版本信息证明装好了. 2:确认Visual Studio 2019环境:看扩展工具里有没有勾选NodeJs 二,使用VS2019 创建Vue项目 后期会新增多个vue的项目,所以建议加一个vue名称 方案管理文件 你

随机推荐