vue+element-ui使用babel-plugin-component按需加载组件及自定义主题对应的scss样式

简介: 作者本人在工作之余喜欢自己写一些东西玩玩, 虽然不是资深程序员, 不过也还是能够完成前端页面+后端接口+服务端部署的整个流程了。

作者的挖坑之旅

作者本人在工作之余喜欢自己写一些东西玩玩, 虽然不是资深程序员, 不过也还是能够完成前端页面+后端接口+服务端部署的整个流程了。

如果不愿意看分析过程,可以直接拉到最后看结果。

开始入坑

首先前端页面使用了Vue作为前端开发框架,我相信点这个标题进来看文章的都用过这个框架的吧。。。

  1. 首先肯定是要引入element这个ui组件库,但是作者是个很讲究的人,虽然自己瞎倒腾的页面没多少东西,但是有些东西还是要规范处理的↓↓↓
  2. 为了项目整体内容不过于庞大,按需加载是许多第三方的库和插件必不可少的,于是使用了官方提供的按需加载插件babel-plugin-component↓↓↓
  3. 先看看官方的代码按需加载
[
    "component",
    {
    "libraryName": "element-ui",
    "styleLibraryName": "theme-chalk"
    }
]
复制代码

这是.babelrc配置参数,component是babel插件的名字,对象是参数。

import Vue from 'vue';
import {
    Dialog,
    Autocomplete,
    Dropdown,
    ...
} from 'element-ui';
Vue.use(Pagination);
Vue.use(Dialog);
Vue.use(Autocomplete);
...
//这里提个醒
//MessageBox,Message,Notification这三个组件只能挂载Vue原型上调用,
//不能使用Vue.use();否则项目运行会默认执行一次,即使没有使用它们
复制代码

这样就可以愉快的按需加载使用自己想要的组件了,接下来给大家看一下这个按需加载插件的部分源码,看它到底干了什么

  1. 位置在node_modules/babel-plugin-component/lib/core.js
var _options = options,
    _options$libDir = _options.libDir,//这是组件所在根目录下的路径element-ui/lib/
    libDir = _options$libDir === void 0 ? 'lib' : _options$libDir,
    _options$libraryName = _options.libraryName,//这是ui库的名字--elementui
    libraryName = _options$libraryName === void 0 ? defaultLibraryName : _options$libraryName,
    _options$style = _options.style,
    style = _options$style === void 0 ? true : _options$style,
    styleLibrary = _options.styleLibrary,//这是引入组件时,所需要引入对应组件样式的配置对象
    _options$root = _options.root,
    root = _options$root === void 0 ? '' : _options$root,
    _options$camel2Dash = _options.camel2Dash,
    camel2Dash = _options$camel2Dash === void 0 ? true : _options$camel2Dash;
    
    var styleLibraryName = options.styleLibraryName;//这是组件所需样式的路径(相对于上面的lib)
    var _root = root;
    var isBaseStyle = true;
    var modulePathTpl;
    var styleRoot;
    var mixin = false;
    var ext = options.ext || '.css';//这是加载样式的后缀,默认css
复制代码

就这一部分代码,我们已经知道在执行按需加载时已经配置了对应样式的加载,所以如果在.babelrc文件配置过styleLibraryName属性的,不要在全局引入element的css样式了,如果你不在乎打包体积的话,请无视我。

踩坑

  1. 作者当时第一次在看element官网时,就发现了定制主题,很有趣,改个scss变量,整个主题色就变了,来看下官方的代码
/* 改变主题色变量 */
$--color-primary: teal;

/* 改变 icon 字体路径变量,必需 */
$--font-path: '~element-ui/lib/theme-chalk/fonts';

@import "~element-ui/packages/theme-chalk/src/index";//注意此处引入了所有组件的scss样式
复制代码
  1. 看到这里你们发现什么了吗?是的,没错,这里引入了全部的scss,上面我们刚说babel-plugin-component会在按需加载组件时,同时引入对应组件的css样式,有人会说那这里就不引入这个index.scss文件,如果没有组件的scss,那这个$--color-primary变量会有效吗? 答案当然是不可能有效的。

  2. 既然我们node_modules里面有所有组件的scss样式文件,我们是不是就可以让babel-plugin-component在引入组件时,就引入对应的scss文件呢?答案是完全ojbk的,不然还写这文章干嘛。。。

爬坑

  1. 我们回到按需加载插件的源码,之前看到代码是配置了加载样式的部分代码的,我们现在看一下具体怎么加载的(这段代码是作者连蒙带猜的。。有错请指出)
if (styleLibrary && _typeof(styleLibrary) === 'object') {//这个是样式的一些配置
  styleLibraryName = styleLibrary.name;
  isBaseStyle = styleLibrary.base;
  modulePathTpl = styleLibrary.path;
  mixin = styleLibrary.mixin;
  styleRoot = styleLibrary.root;
}

if (styleLibraryName) {//是否在.babelrc配置了styleLibraryName
  if (!cachePath[libraryName]) {//是否存在配置好的样式获取路径
    var themeName = styleLibraryName.replace(/^~/, '');
    cachePath[libraryName] = styleLibraryName.indexOf('~') === 0 ?//路径是否相对于element-ui/lib
    resolve(process.cwd(), themeName) : 
    "".concat(libraryName, "/").concat(libDir, "/").concat(themeName);
  }//如果是相对于lib   组合路径---element-ui/lib/theme-chalk/   这个目录下是75个css文件
  //这里将这一段路径保存在了cachePath[libraryName]  后续会用到

  if (libraryObjs[methodName]) {//作者也没搞清楚这里是什么  不过没关系,事实证明这里走了false
    /* istanbul ingore next */
    if (cache[libraryName] === 2) {
      throw Error('[babel-plugin-component] If you are using both' + 'on-demand and importing all, make sure to invoke the' + ' importing all first.');
    }

    if (styleRoot) {//这里默认是没有配置的  所有走false
      path = "".concat(cachePath[libraryName]).concat(styleRoot).concat(ext);
    } else {
      path = "".concat(cachePath[libraryName]).concat(_root || '/index').concat(ext);
    }//这里会默认先加载index.css  因为ext没设置就会默认css

    cache[libraryName] = 1;
  } else {//走了else
    if (cache[libraryName] !== 1) {//这里肯定是不等于1,因为上面一行才会赋值1
      /* if set styleLibrary.path(format: [module]/module.css) */
      var parsedMethodName = parseName(methodName, camel2Dash);

      if (modulePathTpl) {
        var modulePath = modulePathTpl.replace(/\[module]/ig, parsedMethodName);
        path = "".concat(cachePath[libraryName], "/").concat(modulePath);
      } else {//这里走了else 也就是样式路径后续为模块名.[ext]
        path = "".concat(cachePath[libraryName], "/").concat(parsedMethodName).concat(ext);
      }//所有这里的路径就是element-ui/lib/

      if (mixin && !isExist(path)) {
        path = style === true ? "".concat(_path, "/style").concat(ext) : "".concat(_path, "/").concat(style);
      }

      if (isBaseStyle) {
        addSideEffect(file.path, "".concat(cachePath[libraryName], "/base").concat(ext));
      }

      cache[libraryName] = 2;
    }
  }

  addDefault(file.path, path, {
    nameHint: methodName
  });
} else {
  if (style === true) {
    addSideEffect(file.path, "".concat(path, "/style").concat(ext));
  } else if (style) {
    addSideEffect(file.path, "".concat(path, "/").concat(style));
  }
}
}
复制代码
  1. 好的,这就过了一遍了,连蒙带猜知道是怎么回事了,我们进入正题,如何变为加载对应组件的scss
//第一步不用说了 先把ext后缀改为scss
[
    "component",
    {
        "libraryName": "element-ui",
        "styleLibraryName": "theme-chalk",
        "ext":".scss"
    }
]
//-------------------
//第二步呢  就是配置路径  比较重要的
//有一段代码需要看的  虽然作者也看不懂,不过大概知道这一段是加载模块的
if (libraryObjs[methodName]) {
  path = "".concat(libraryName, "/").concat(libDir).concat(_root);
    //需要注意这里的libDir,之前的代码我们看到  加载样式也会基于libDir
    //所以我们无法通过.babelrc的option去修改libDir,
    //那样的话组件加载就有问题我们不能影响最基本的组件加载
  if (!_root) {
    importAll[path] = true;
  }
} else {
  path = "".concat(libraryName, "/").concat(libDir, "/").concat(parseName(methodName, camel2Dash));
}
//所以我们只能通过修改core.js的源码解决,这是我目前的办法
复制代码
  1. 既然我们要修改按需加载对应的scss样式,那首先先找到文件位置,这里我直接说了element-ui/packages/theme-chalk/src/ 和默认加载css一样75个文件,哇,文件数量都一样,是不是瞬间感觉很放心了呢。
  2. 我们对比一下,
  • 默认的是element-ui/lib/theme-chalk
  • 要修改成element-ui/packages/theme-chalk/src
  1. libDir是不能改的 我们说了 所以看源码
//这是上面提到的三目运算
if (!cachePath[libraryName]) {
    var themeName = styleLibraryName.replace(/^~/, '');
    cachePath[libraryName] = styleLibraryName.indexOf('~') === 0 ?
    resolve(process.cwd(), themeName) : 
    "".concat(libraryName, "/").concat(libDir, "/").concat(themeName);
}//我们把这里------------------------libDir修改为 "packages"

现在路径从element-ui/lib/theme-chalk--->element-ui/packages/theme-chalk
复制代码
  1. 我们再看看,还少了个src
  • element-ui/packages/theme-chalk
  • element-ui/packages/theme-chalk/src
  1. 老规矩,看源码
//咳咳,还是那个三目运算
if (!cachePath[libraryName]) {
    var themeName = styleLibraryName.replace(/^~/, '');
    cachePath[libraryName] = styleLibraryName.indexOf('~') === 0 ?
    resolve(process.cwd(), themeName) : 
    "".concat(libraryName, "/").concat("packages", "/").concat(themeName);
}
//我们看packages后面的路径是个变量themeName
//这个themeName就是styleLibraryName,你懂了吗,你懂怎么修改了吗
复制代码
  1. 如下
[
  "component",
  {
    "libraryName": "element-ui",
    "styleLibraryName": "theme-chalk/src",//这里把theme-chalk-->theme-chalk/src
    "ext":".scss"
  }
]
复制代码
  1. 至此,已经完成。快去跑项目玩玩看吧。

总结

.babelrc

"plugins": [
    [
      "component",
      {
        "libraryName": "element-ui",
        "styleLibraryName": "theme-chalk/src",
        "ext":".scss"
      }
    ]
]
复制代码

node_modules/babel-plugin-component/lib/core.js

//95-98行左右
if (!cachePath[libraryName]) {
    var themeName = styleLibraryName.replace(/^~/, '');
    cachePath[libraryName] = styleLibraryName.indexOf('~') === 0 ? resolve(process.cwd(), themeName) : "".concat(libraryName, "/").concat("packages", "/").concat(themeName);
}
复制代码

over




原文发布时间为:2018年06月29日

作者:chavesgu

本文来源: 掘金  如需转载请联系原作者
相关文章
|
6月前
|
JavaScript 前端开发 开发者
Vue 自定义进度条组件封装及使用方法详解
这是一篇关于自定义进度条组件的使用指南和开发文档。文章详细介绍了如何在Vue项目中引入、注册并使用该组件,包括基础与高级示例。组件支持分段配置(如颜色、文本)、动画效果及超出进度提示等功能。同时提供了完整的代码实现,支持全局注册,并提出了优化建议,如主题支持、响应式设计等,帮助开发者更灵活地集成和定制进度条组件。资源链接已提供,适合前端开发者参考学习。
490 17
|
6月前
|
JavaScript 前端开发 UED
Vue 项目中如何自定义实用的进度条组件
本文介绍了如何使用Vue.js创建一个灵活多样的自定义进度条组件。该组件可接受进度段数据数组作为输入,动态渲染进度段,支持动画效果和内容展示。当进度超出总长时,超出部分将以红色填充。文章详细描述了组件的设计目标、实现步骤(包括props定义、宽度计算、模板渲染、动画处理及超出部分的显示),并提供了使用示例。通过此组件,开发者可根据项目需求灵活展示进度情况,优化用户体验。资源地址:[https://pan.quark.cn/s/35324205c62b](https://pan.quark.cn/s/35324205c62b)。
283 0
|
缓存 JavaScript UED
Vue3中v-model在处理自定义组件双向数据绑定时有哪些注意事项?
在使用`v-model`处理自定义组件双向数据绑定时,要仔细考虑各种因素,确保数据的准确传递和更新,同时提供良好的用户体验和代码可维护性。通过合理的设计和注意事项的遵循,能够更好地发挥`v-model`的优势,实现高效的双向数据绑定效果。
587 161
|
JavaScript
在 Vue 3 中,如何使用 v-model 来处理自定义组件的双向数据绑定?
需要注意的是,在实际开发中,根据具体的业务需求和组件设计,可能需要对上述步骤进行适当的调整和优化,以确保双向数据绑定的正确性和稳定性。同时,深入理解 Vue 3 的响应式机制和组件通信原理,将有助于更好地运用 `v-model` 实现自定义组件的双向数据绑定。
855 159
|
10月前
|
JavaScript 数据安全/隐私保护
Vue Amazing UI 组件库(Vue3+TypeScript+Vite 等最新技术栈开发)
Vue Amazing UI 是一个基于 Vue 3、TypeScript、Vite 等最新技术栈开发构建的现代化组件库,包含丰富的 UI 组件和常用工具函数,并且持续不断维护更新中。另外,组件库全量使用 TypeScript,支持自动按需引入和 Tree Shaking 等,能够显著提升开发效率,降低开发成本。
615 5
Vue Amazing UI 组件库(Vue3+TypeScript+Vite 等最新技术栈开发)
|
12月前
「Mac畅玩鸿蒙与硬件46」UI互动应用篇23 - 自定义天气预报组件
本篇将带你实现一个自定义天气预报组件。用户可以通过选择不同城市来获取相应的天气信息,页面会显示当前城市的天气图标、温度及天气描述。这一功能适合用于动态展示天气信息的小型应用。
529 38
「Mac畅玩鸿蒙与硬件46」UI互动应用篇23 - 自定义天气预报组件
|
前端开发 JavaScript 测试技术
Vue3中v-model在处理自定义组件双向数据绑定时,如何避免循环引用?
Web 组件化是一种有效的开发方法,可以提高项目的质量、效率和可维护性。在实际项目中,要结合项目的具体情况,合理应用 Web 组件化的理念和技术,实现项目的成功实施和交付。通过不断地探索和实践,将 Web 组件化的优势充分发挥出来,为前端开发领域的发展做出贡献。
280 64
|
UED
「Mac畅玩鸿蒙与硬件31」UI互动应用篇8 - 自定义评分星级组件
本篇将带你实现一个自定义评分星级组件,用户可以通过点击星星进行评分,并实时显示评分结果。为了让界面更具吸引力,我们还将添加一只小猫图片作为评分的背景装饰。
298 6
「Mac畅玩鸿蒙与硬件31」UI互动应用篇8 - 自定义评分星级组件
|
前端开发 开发者
「Mac畅玩鸿蒙与硬件23」鸿蒙UI组件篇13 - 自定义组件的创建与使用
自定义组件可以帮助开发者实现复用性强、逻辑清晰的界面模块。通过自定义组件,鸿蒙应用能够提高代码的可维护性,并简化复杂布局的构建。本篇将介绍如何创建自定义组件,如何向组件传递数据,以及如何在不同页面间复用这些组件。
306 5
「Mac畅玩鸿蒙与硬件23」鸿蒙UI组件篇13 - 自定义组件的创建与使用
|
JavaScript API
vue3知识点:自定义hook函数
vue3知识点:自定义hook函数
172 2