美文网首页
2023.4 ElementUI源码-建设组件库文档

2023.4 ElementUI源码-建设组件库文档

作者: wo不是黄蓉 | 来源:发表于2023-02-07 21:49 被阅读0次

    大家好,我是wo不是黄蓉,今年学习目标从源码共读开始,希望能跟着若川大佬学习源码的思路学到更多的东西。

    本文是为了学习组件库搭建思路而衍生的一篇文章,最近在思考搭建项目业务组件库,发现公司封装的命令也是基于vue2的,因此开始了学习ElementUI源码学习之路。

    调试环境准备

    package.jsonscripts中配置

    "dev:sourcemap": "npm run bootstrap && npm run build:file && cross-env NODE_ENV=development webpack-dev-server --config build/webpack.demo.js & node build/bin/template.js --sourcemap",
    

    配置sourcemap就可以开启源码调试了,在项目中打好断点

    1675863128642.png
    入口文件 examples\entry.js

    找到build\webpack.demo.js发现就是一些基础的webpack配置,查看webpack配置文件,发现入口为examples\entry.js

    这正是一个vue项目,因此npm run dev就是启动一个vue项目,而上面build生成的那些文件,是运行时所需的一些配置

    npm run dev首页内容

    1675859002151.png

    examples\components\header.vue页面导航部分代码,最终生成的路径:/zh-CN/component/installation

     <li class="nav-item">
        <router-link
          active-class="active"
          :to="`/${ lang }/component`">{{ langConfig.components }}
        </router-link>
      </li>
    

    router-link的内容应该在路由配置表里面可以找到,从examples\entry.js可以找到路由配置相关信息

    import VueRouter from 'vue-router';
    import routes from './route.config';
    Vue.use(VueRouter);
    const router = new VueRouter({
      mode: 'hash',
      base: __dirname,
      routes
    });
    

    router配置来自examples\route.config.js

    //这边import使用到的内容就是上节我们说的从npm run build中打包过来的内容
    import navConfig from './nav.config';
    const LOAD_MAP = {
      'zh-CN': name => {
        return r => require.ensure([], () =>
          r(require(`./pages/zh-CN/${name}.vue`)),
        'zh-CN');
      },
      'en-US': name => {
        return r => require.ensure([], () =>
          r(require(`./pages/en-US/${name}.vue`)),
        'en-US');
      },
    };
    
    const LOAD_DOCS_MAP = {
      "zh-CN": (path) => {
        return (r) =>
          require.ensure([], () => r(require(`./docs/zh-CN${path}.md`)), "zh-CN")
      },
      "en-US": (path) => {
        return (r) =>
          require.ensure([], () => r(require(`./docs/en-US${path}.md`)), "en-US")
      },
    }
    //组件懒加载-这边加载的是语言包下的导航类的组件
    const load = function(lang, path) {
      return LOAD_MAP[lang](path);
    };
    //加载文档组件-这边加载的才是真正的组件
    const loadDocs = function(lang, path) {
      return LOAD_DOCS_MAP[lang](path)
    }
    //注册路由
    const registerRoute = (navConfig) => {
      let route = [];
      Object.keys(navConfig).forEach((lang, index) => {
        let navs = navConfig[lang];
        route.push({
          path: `/${ lang }/component`,
          redirect: `/${ lang }/component/installation`,
          component: load(lang, 'component'),
          children: []
        });
        navs.forEach(nav => {
          if (nav.href) return;
          if (nav.groups) {
            nav.groups.forEach(group => {
              group.list.forEach(nav => {
                addRoute(nav, lang, index);
              });
            });
          } else if (nav.children) {
            nav.children.forEach(nav => {
              addRoute(nav, lang, index);
            });
          } else {
            addRoute(nav, lang, index);
          }
        });
      });
      function addRoute(page, lang, index) {
          //判断是否是changelog,不是使用loadDocs加载组件
        const component = page.path === '/changelog'
          ? load(lang, 'changelog')
          : loadDocs(lang, page.path);
        let child = {
          path: page.path.slice(1),
          meta: {
            title: page.title || page.name,
            description: page.description,
            lang
          },
          name: 'component-' + lang + (page.title || page.name),
          component: component.default || component
        };
    
        route[index].children.push(child);
      }
    
      return route;
    };
    let route = registerRoute(navConfig);
    export default route;
    

    load函数,这个函数主要是让组件懒加载,LOAD_MAP[lang]返回的是一个函数,即

    (name) => {
        return (r) =>
          require.ensure([], () => r(require(`./pages/zh-CN/${name}.vue`)), "zh-CN")
      }
    

    调用LOAD_MAP[lang]这个函数,返回内容即

    (r) =>require.ensure([], () => r(require(`./pages/zh-CN/${name}.vue`)), "zh-CN")
    

    registerRoute函数会根据examples\nav.config.json这个json里面配置的内容为各种语言的映射,包括导航和菜单组织信息,将导航和菜单信息都提前配置好在这个文件中,后续组件导航就根据这个文件来生成的。

    addRoute函数中,最终组件使用的是loadloadDocs来导入组件的,这两个的区别就是,load加载的组件是导航类的,这个可以在examples\pages\zh-CN中进行验证

    1675862334888.png

    loadDocs加载的组件是examples\docs\zh-CN

    1675862386094.png

    为什么这边加载的组件是md文件呢?

    因为在build\webpack.demo.js中有这么一段配置,这个是用来解析md文件的loader,先将md文件解析成vue文件,再使用vue-loader解析vue文件,再进行展示页面

          {
            test: /\.md$/,
            use: [
              {
                loader: "vue-loader",
                options: {
                  compilerOptions: {
                    preserveWhitespace: false,
                  },
                },
              },
              {
                loader: path.resolve(__dirname, "./md-loader/index.js"),
              },
            ],
          },
    
    总结:

    看一点头绪都没有的代码不妨先看降级的代码,比如我一开始是想学习element-plus源码的,但是新的结构让我觉得陌生,学习摸索大概有一两个星期,也就大概看了个架子,内心其实也是比较受打击的。

    就像我之前说的,我不是一个学习技术特别厉害的人,因此学习跨度更大的代码让我提不起兴趣,想要逃避。但是我当我换成看element源码后完全不会有这样的感觉,即使有不太懂的,也可以在网上找到答案,解决我的疑惑。

    相关文章

      网友评论

          本文标题:2023.4 ElementUI源码-建设组件库文档

          本文链接:https://www.haomeiwen.com/subject/zsmfkdtx.html