1.代码拆分-使用SplitChunks
2.js import å requireçåºå«
3.å¦ä½åºäºWebComponentså°è£
UIç»ä»¶åº
4.Vue组件中如何引入外部的源码js文件
代码拆分-使用SplitChunks
前言
探索代码优化的世界,最近开始接触项目优化工作,源码其中涉及三方组件的源码拆分。在未进行拆分前,源码可能存在两个场景:单一js文件过大,源码影响缓存效率;无法有效管理第三方库。源码低买神马指标源码利用`splitChunks`工具,源码可以将模块进行分割,源码并提取重复代码,源码解决上述问题。源码
概念区分 - module、源码bundle、源码chunk
深入理解`splitChunks`之前,源码空投源码骗局案例先梳理几个概念。源码module:模块,源码在webpack中,任何文件都可视为模块,需要配置loader将其转换为支持打包的文件。chunk:编译完成待输出时,webpack将module按特定规则组合成一个个chunk。bundle:webpack处理完chunk文件后,生成供浏览器运行的代码。
chunk与bundle的关系
探析chunk的构成与bundle之间的关联。chunk有两种形式:初始化(initial)chunk,即入口起点的qt源码编译qmax主chunk,包含入口起点及其依赖的所有模块;非初始化(non-initial)chunk,用于延迟加载,可能在使用动态导入或`SplitChunksPlugin`时出现。
通过入口产生的chunk
假设目录结构如下:index.js, another-module.js, webpack.config.js, package.json添加script配置,运行webpack并使用ndb追踪代码执行。通过命令启动浏览器,点击播放按钮执行build命令,追踪chunk到bundle的流转。
chunk处理步骤概览
从`Compilation`类的`seal`方法出发,首先搜集chunks,然后调用`createChunkAssets`方法生成source,为输出文件做准备;通过`compilation.emitAssets`方法记录资源信息到`compilation.assets`对象;一系列回调最终调用`onCompiled`方法,阅读漫画源码下载将assets信息写入输出目录,生成bundle文件。
Demo2 - 动态导入
将`index.js`中的lodash通过`import`方式导入,动态导入返回promise,通过`then`获取导入信息。修改`webpack.config.js`入口为单个`index.js`。源码追踪显示,初始化文件新增一个名为`index`的chunk,但在模块分析中识别到`import`方式,为`index.js`模块增加了`AsyncDependenciesBlock`标记,经过处理生成一个名为`null`的chunk。
总结:`chunk`是网址在线读取源码源代码中的抽象,封装定义如何将模块组写入文件,而`bundle`则是输出目录的文件。
解决隐患 - `splitChunks`配置
在上述示例中,存在三方模块重复引用的问题。通过简单的`optimization.splitChunks`配置,实现了lodash的抽离,降低了单个入口文件的大小。总结使用心得,`splitChunks`主要用于代码优化,针对不同场景配置`chunks`选项,如`all`、`async`、`initial`以及自定义函数,以达到高效拆分效果。
比较`async`、`initial`、`all`的区别
在示例中增加`another.js`,静态导入lodash,对比`async`、`all`、`initial`的不同效果。默认情况下,`initial`影响HTML文件中的脚本标签,而`async`仅针对动态导入,`all`则考虑更多场景,适合存在复用模块的情况,但需权衡动态导入及其内部依赖的抽离。
splitChunks.cacheGroups
在使用`splitChunks`基础上,通过`cacheGroups`实现更细粒度的代码拆分,进一步优化项目结构。
总结
通过`splitChunks`配置,实现三方组件的高效管理与拆分,优化代码结构与加载效率。理解模块、bundle、chunk之间的关系,以及如何利用`splitChunks`与`cacheGroups`进行代码拆分与优化,是提升项目性能的关键步骤。
js import å requireçåºå«
å¨ç 究reactåwebpackçæ¶åï¼ç»å¸¸çå°å¨jsæ件ä¸åºç°requireï¼è¿æimportï¼è¿ä¸¤ä¸ªé½æ¯ä¸ºäºJS模ååç¼ç¨ä½¿ç¨ãCSSçæ¯@import
1.ES6 模åç设计ææ³ï¼æ¯å°½éçéæåï¼ä½¿å¾ç¼è¯æ¶å°±è½ç¡®å®æ¨¡åçä¾èµå ³ç³»ï¼ä»¥åè¾å ¥åè¾åºçåéã
Requireæ¯CommonJSçè¯æ³ï¼CommonJSç模åæ¯å¯¹è±¡ï¼è¾å ¥æ¶å¿ é¡»æ¥æ¾å¯¹è±¡å±æ§ã
å¤å¶ä»£ç
å¤å¶ä»£ç
// CommonJS模å
let { stat, exists, readFile } = require('fs');
// çåäº
let _fs = require('fs');
let stat = _fs.stat;
let exists = _fs.exists;
let readfile = _fs.readfile;
å¤å¶ä»£ç
aboveï¼æ´ä½å è½½fs模åï¼å³å è½½fsæææ¹æ³ï¼ï¼çæä¸ä¸ªå¯¹è±¡"_fs"ï¼ç¶ååä»è¿ä¸ªå¯¹è±¡ä¸è¯»åä¸ä¸ªæ¹æ³ï¼è¿å«âè¿è¡æ¶å è½½âï¼å 为åªæè¿è¡æ¶æè½å¾å°è¿ä¸ªå¯¹è±¡ï¼ä¸è½å¨ç¼è¯æ¶åå°éæåã
ES6模åä¸æ¯å¯¹è±¡ï¼èæ¯éè¿exportå½ä»¤æ¾ç¤ºæå®è¾åºä»£ç ï¼åéè¿importè¾å ¥ã
import { stat, exists, readFile } from 'fs';
aboveï¼ä»fså è½½âstat, exists, readFileâ ä¸ä¸ªæ¹æ³ï¼å ¶ä»æ¹æ³ä¸å è½½ï¼
2.ES6模åé»è®¤ä½¿ç¨ä¸¥æ ¼æ¨¡å¼ï¼æ 论æ¯å¦å£°æâuse strictâ
ES6 模åä¹ä¸ï¼é¡¶å±çthisæåundefinedï¼å³ä¸åºè¯¥å¨é¡¶å±ä»£ç 使ç¨thisã
Module 主è¦ç±ä¸¤ä¸ªå½ä»¤ç»æï¼importåexportï¼exportç¨äºè§å®æ¨¡åç对å¤æ¥å£ï¼importå½ä»¤ç¨äºè¾å ¥å ¶ä»æ¨¡åæä¾çåè½
3.Export
模åæ¯ç¬ç«çæ件ï¼è¯¥æ件å é¨çææçåéå¤é¨é½æ æ³è·åãå¦æå¸æè·åæ个åéï¼å¿ é¡»éè¿exportè¾åºï¼
// profile.js
export var firstName = 'Michael';
export var lastName = 'Jackson';
export var year = ;
æè ç¨æ´å¥½çæ¹å¼ï¼ç¨å¤§æ¬å·æå®è¦è¾åºçä¸ç»åé
å¤å¶ä»£ç
// profile.js
var firstName = 'Michael';
var lastName = 'Jackson';
var year = ;
export { firstName, lastName, year};
å¤å¶ä»£ç
é¤äºè¾åºåéï¼è¿å¯ä»¥è¾åºå½æ°æè ç±»ï¼classï¼ï¼
export function multiply(x, y) {
return x * y;
};
è¿å¯ä»¥æ¹éè¾åºï¼åæ ·æ¯è¦å å«å¨å¤§æ¬å·éï¼ä¹å¯ä»¥ç¨aséå½åï¼
å¤å¶ä»£ç
å¤å¶ä»£ç
function v1() { ... }
function v2() { ... }
export {
v1 as streamV1,
v2 as streamV2,
v2 as streamLatestVersion
};
å¤å¶ä»£ç
Attention:
export å½ä»¤è§å®çæ¯å¯¹å¤æ¥å£ï¼å¿ é¡»ä¸æ¨¡åå é¨åé建ç«ä¸ä¸å¯¹åºçå ³ç³»
å¤å¶ä»£ç
å¤å¶ä»£ç
// åæ³ä¸
export var m = 1;
// åæ³äº
var m = 1;
export { m};
// åæ³ä¸
var n = 1;
export { n as m};
// æ¥é
export 1;
// æ¥é
var m = 1;
export m;
å¤å¶ä»£ç
æ¥éçåæ³åå æ¯ï¼æ²¡ææä¾å¯¹å¤çæ¥å£ï¼ç¬¬ä¸ç§ç´æ¥è¾åº1ï¼ç¬¬äºç§è½ç¶æåémï¼ä½è¿æ¯ç´æ¥è¾åº1ï¼å¯¼è´æ æ³è§£æã
åæ ·çï¼functionåclassçè¾åºï¼ä¹å¿ é¡»éµå®è¿æ ·çåæ³ã
å¤å¶ä»£ç
å¤å¶ä»£ç
// æ¥é
function f() { }
export f;
// æ£ç¡®
export function f() { };
// æ£ç¡®
function f() { }
export { f};
å¤å¶ä»£ç
Andï¼exportè¯å¥è¾åºçæ¥å£ï¼é½æ¯åå ¶å¯¹åºçå¼æ¯å¨æç»å®çå ³ç³»ï¼å³éè¿è¯¥æ¥å£åå°çé½æ¯æ¨¡åå é¨å®æ¶çå¼ã
ä½ç½®ï¼export模åå¯ä»¥ä½äºæ¨¡åä¸çä»»ä½ä½ç½®ï¼ä½æ¯å¿ é¡»æ¯å¨æ¨¡å顶å±ï¼å¦æå¨å ¶ä»ä½ç¨åå ï¼ä¼æ¥éã
function foo() {
export default 'bar' // SyntaxError
}
foo()
4.Importå½ä»¤
exportå®ä¹äºæ¨¡åç对å¤æ¥å£åï¼å ¶ä»JSæ件就å¯ä»¥éè¿importæ¥å è½½è¿ä¸ªæ¨¡åï¼
å¤å¶ä»£ç
// main.js
import { firstName, lastName, year} from './profile';
function setName(element) {
element.textContent = firstName + ' ' + lastName;
}
å¤å¶ä»£ç
importå½ä»¤æ¥åä¸å¯¹å¤§æ¬å·ï¼éé¢æå®è¦ä»å ¶ä»æ¨¡åå¯¼å ¥çåéåï¼å¿ é¡»ä¸è¢«å¯¼å ¥æ¨¡åï¼profile.jsï¼å¯¹å¤æ¥å£çå称ç¸åã
å¦ææ³éæ°ç»å¯¼å ¥çåéä¸ä¸ªååï¼å¯ä»¥ç¨aså ³é®åï¼
import { lastName as surname } from './profile';
importåçfrom å¯ä»¥æå®éè¦å¯¼å ¥æ¨¡åçè·¯å¾åï¼å¯ä»¥æ¯ç»å¯¹è·¯å¾ï¼ä¹å¯ä»¥æ¯ç¸å¯¹è·¯å¾ï¼ .jsè·¯å¾å¯ä»¥çç¥ï¼å¦æåªæ模ååï¼ä¸å¸¦æè·¯å¾ï¼éè¦æé ç½®æ件æå®ã
注æï¼importå½ä»¤å ·ææåææï¼ä¼æåå°æ´ä¸ªæ¨¡åç头é¨ï¼é¦å æ§è¡ãï¼æ¯å¨ç¼è¯é¶æ®µæ§è¡çï¼
å 为importæ¯éææ§è¡çï¼ä¸è½ä½¿ç¨è¡¨è¾¾å¼ååéï¼å³å¨è¿è¡æ¶æè½æ¿å°ç»æçè¯æ³ç»æï¼e.g. if...else...ï¼
å¦ä½åºäºWebComponentså°è£ UIç»ä»¶åº
è¿æ¯ç¬¬ç¯ä¸æºæ°´çååï¼æ³è·åæ´å¤åå好æï¼è¯·æç´¢å ¬ä¼å·å ³æ³¨æ们å§~æ¬æé¦åäºæ¿éäºå端å客ï¼å¦ä½åºäºWebComponentså°è£ UIç»ä»¶åºåè¨ä½ä¸ºä¸åå端æ»åç®ï¼ç¸ä¿¡å¤§å®¶ä¹é½å¨å ³æ³¨çå端çä¸äºæ°ææ¯ï¼è¿äºå¹´æ¥å端ç»ä»¶åå¼å已为常æï¼æ们ç»å¸¸æéç¨æ§æç模åæ½ç¦»æä¸ä¸ªä¸ªçç»ä»¶ï¼æ¥è¾¾å°å¤ç¨çç®çï¼è¿æ ·åå°äºæ们çç»´æ¤ææ¬ï¼æé«äºå¼åçæçãä½æ¯é½æä¸ä¸ªç¼ºç¹ç¦»ä¸å¼æ¡æ¶æ¬èº«ï¼å 为æ们æµè§å¨æ¬èº«è§£æä¸äºé£äºç»ä»¶ãé£ä¹æ没æä¸ç§ææ¯ä¹å¯ä»¥è¾¾å°è¿ç§ææå¢ï¼çæ¡å°±æ¯ä»å¤©ç主è§WebComponentsã
WebComponentsæ¯ä¸å¥ä¸åçææ¯ï¼å 许æ¨å建å¯éç¨çå®å¶å ç´ ï¼å®ä»¬çåè½å°è£ å¨æ¨ç代ç ä¹å¤ï¼å¹¶ä¸å¨æ¨çwebåºç¨ä¸ä½¿ç¨å®ä»¬ã?ç®åW3Cä¹å¨ç§¯ææ¨å¨ï¼å¹¶ä¸æµè§å¨çæ¯ææ åµè¿ä¸éãFireFoxãChromeãOperaå·²å ¨é¨æ¯æï¼Safariä¹å¤§é¨åæ¯æï¼Edgeä¹æ¢æwebkitå æ ¸äºï¼ç¦»å ¨é¢æ¯æåºè¯¥ä¹ä¸è¿äºãå½ç¶ç¤¾åºä¹æå ¼å®¹ç解å³æ¹æ¡webcomponents/polyfillsã
WebComponentsä¸è¦ç´ åçå½å¨æButtonç»ä»¶ç¤ºä¾é¦å æ们就ä»ä¸ä¸ªæç®åçButtonç»ä»¶å¼å§ï¼æ们å¯ä»¥éè¿å¨ç»ä»¶ä¸ä¼ å ¥typeæ¥æ¹åæé®çæ ·å¼ï¼å¹¶ä¸å¨æçå¬äºæ°æ®çååã
//html<cai-buttontype="primary"><spanslot="btnText">æé®</span></cai-button><templateid="caiBtn"><style>.cai-button{ display:inline-block;padding:4pxpx;font-size:px;line-height:1.;font-weight:;border:1pxsolid#ff;border-radius:2px;background-color:#ff;color:#fff;box-shadow:px#;}.cai-button-warning{ border:1pxsolid#faad;background-color:#faad;}.cai-button-danger{ border:1pxsolid#ff4d4f;background-color:#ff4d4f;}</style><divclass="cai-button"><slotname="btnText"></slot></div></template><script>consttemplate=document.getElementById("caiBtn");classCaiButtonextendsHTMLElement{ constructor(){ super()this._type={ primary:'cai-button',warning:'cai-button-warning',danger:'cai-button-danger',}//å¼å¯shadowdomconstshadow=this.attachShadow({ mode:'open'})consttype=thisconstcontent=template.content.cloneNode(true)//å éä¸ä»½é²æ¢éå¤ä½¿ç¨æ±¡æ//æååºå¼æ°æ®æå°thisthis._btn=content.querySelector('.cai-button')this._btn.className+=`${ this._type[type]}`shadow.appendChild(content)}staticgetobservedAttributes(){ return['type']}attributeChangedCallback(name,oldValue,newValue){ this[name]=newValue;this.render();}render(){ this._btn.className=`cai-button${ this._type[this.type]}`}}//æè½½å°windowwindow.customElements.define('cai-button',CaiButton)</script>ä¸è¦ç´ ãçå½å¨æå示ä¾ç解æCustomelementsï¼èªå®ä¹å ç´ ï¼ï¼ä¸ç»JavaScriptAPIï¼å 许æ¨å®ä¹customelements?åå ¶è¡ä¸ºï¼ç¶åå¯ä»¥å¨æ¨çç¨æ·çé¢ä¸æç §éè¦ä½¿ç¨å®ä»¬ãå¨ä¸é¢ä¾åä¸å°±æçæ¯æ们çèªå®ä¹ç»ä»¶ï¼æ们éè¿classCaiButtonextendsHTMLElement{ }å®ä¹æ们çç»ä»¶ï¼éè¿window.customElements.define('cai-button',CaiButton)æè½½æ们çå·²å®ä¹ç»ä»¶ã
ShadowDOMï¼å½±åDOMï¼ï¼ä¸ç»JavaScriptAPIï¼ç¨äºå°å°è£ çâå½±åâDOMæ éå å°å ç´ ï¼ä¸ä¸»ææ¡£DOMåå¼åç°ï¼å¹¶æ§å¶å ¶å ³èçåè½ãéè¿è¿ç§æ¹å¼ï¼æ¨å¯ä»¥ä¿æå ç´ çåè½ç§æï¼è¿æ ·å®ä»¬å°±å¯ä»¥è¢«èæ¬ååæ ·å¼åï¼èä¸ç¨æ å¿ä¸ææ¡£çå ¶ä»é¨ååçå²çªã使ç¨constshadow=this.attachShadow({ mode:'open'})å¨WebComponentsä¸å¼å¯ã
HTMLtemplatesï¼HTML模æ¿ï¼slotï¼templateå¯ä»¥ç®åçædomå ç´ çæä½ï¼æ们ä¸åéè¦createElementæ¯ä¸ä¸ªèç¹ãslotååVueéé¢çslot类似ï¼åªæ¯ä½¿ç¨å称ä¸å¤ªä¸æ ·ã
å é¨çå½å¨æå½æ°
connectedCallback:å½WebComponents第ä¸æ¬¡è¢«æå¨å°domä¸æ¯è§¦åçé©åï¼å¹¶ä¸åªä¼è§¦åä¸æ¬¡ã类似Vueä¸çmountedReactä¸çuseEffect(()=>{ },[])ï¼componentDidMountã
disconnectedCallback:å½èªå®ä¹å ç´ ä¸ææ¡£DOMæå¼è¿æ¥æ¶è¢«è°ç¨ã
adoptedCallback:å½èªå®ä¹å ç´ è¢«ç§»å¨å°æ°ææ¡£æ¶è¢«è°ç¨ã
attributeChangedCallback:å½èªå®ä¹å ç´ ç被çå¬å±æ§ååæ¶è¢«è°ç¨ãä¸è¿°ä¾åä¸æ们çå¬äºtypeçååï¼ä½¿buttonç»ä»¶åç°ä¸åç¶æãè½ç¶WebComponentsæä¸ä¸ªè¦ç´ ï¼ä½å´ä¸æ¯ç¼ºä¸ä¸å¯çï¼WebComponentsåå©shadowdom?æ¥å®ç°æ ·å¼é离ï¼åå©templatesæ¥ç®åæ ç¾çæä½ã
å¨è¿ä¸ªä¾åç¨æ们使ç¨äºslotä¼ å ¥äºä¿©ä¸ªæ ç¾ä¹é´çå 容ï¼å¦ææ们æ³è¦ä¸ä½¿ç¨slotä¼ å ¥æ ç¾ä¹é´çå 容æä¹åï¼
æ们å¯ä»¥éè¿innerHTMLæ¿å°èªå®ä¹ç»ä»¶ä¹é´çå 容ï¼ç¶åæè¿æ®µå 容æå ¥å°å¯¹åºèç¹å³å¯ã
ç»ä»¶éä¿¡äºè§£ä¸é¢è¿äºåºæ¬çæ¦å¿µåï¼æ们就å¯ä»¥å¼åä¸äºç®åçç»ä»¶äºï¼ä½æ¯å¦ææ们æ³ä¼ å ¥ä¸äºå¤æçæ°æ®ç±»åï¼å¯¹è±¡ï¼æ°ç»çï¼æä¹åï¼æ们åªä¼ å ¥å符串è¿å¯ä»¥ä¹ï¼çæ¡æ¯è¯å®çï¼
ä¼ å ¥å¤ææ°æ®ç±»å使ç¨æ们ä¸é¢çbuttonï¼æ们ä¸ä» è¦æ¹åç¶æï¼èä¸è¦æ³è¦ä¼ å ¥ä¸äºé ç½®ï¼æ们å¯ä»¥éè¿ä¼ å ¥ä¸ä¸ªJSONå符串
//html<cai-buttonid="btn"></cai-button><script>btn.setAttribute('config',JSON.stringify({ icon:'',posi:''}))</script>//button.jsclassCaiButtonextendsHTMLElement{ constructor(){ xxx}staticgetobservedAttributes(){ return['type','config']//çå¬config}attributeChangedCallback(name,oldValue,newValue){ if(name==='config'){ newValue=JSON.parse(newValue)}this[name]=newValue;this.render();}render(){ }}window.customElements.define('cai-button',CaiButton)})()è¿ç§æ¹å¼è½ç¶å¯è¡ä½å´ä¸æ¯å¾ä¼é ã
对äºä½¿ç¨è 说ï¼æç¨ä½ 个ç»ä»¶ä½ è¿è¦è®©ææææçå¤æç±»åé½è½¬æ¢æå符串ï¼
对äºå¼åç»ä»¶è æ¥è¯´ï¼æ为ä»ä¹è¦æ¯æ¬¡é½JSON.parse()ä¸ä¸ï¼
HTMLä¸ä¼æå¾é¿çæ°æ®ã
å æ¤æ们éè¦æ¢ä¸ä¸ªæè·¯ï¼æ们ä¸é¢ä½¿ç¨çæ¹å¼é½æ¯attributeä¼ å¼ï¼æ°æ®ç±»ååªè½æ¯å符串ï¼é£æ们å¯ä»¥ä¸ç¨å®ä¼ å¼åï¼çæ¡å½ç¶ä¹æ¯å¯ä»¥çãåattribute形影ä¸ç¦»è¿ææ们jsä¸çpropertyï¼å®æçæ¯domå±æ§ï¼æ¯js对象并ä¸æ¯æä¼ å ¥å¤ææ°æ®ç±»åã
//tableç»ä»¶demo,以ä¸ä¸ºä¼ªä»£ç ä» å±ç¤ºæè·¯<cai-tableid="table"></cai-table>table.dataSource=[{ name:'xxx',age:}]table.columns=[{ title:'',key:''}]è¿ç§æ¹å¼è½ç¶è§£å³ä¸è¿°é®é¢ï¼ä½æ¯åå¼åºäºæ°çé®é¢--èªå®ä¹ç»ä»¶ä¸æ²¡æåæ³çå¬å°è¿ä¸ªå±æ§çååï¼é£ç°å¨æ们åºè¯¥æä¹åï¼æ许ä»ä¸å¼å§æ¯æ们çæ路就æ¯éçï¼æ¾ç¶å¯¹äºæ°æ®çååºå¼ååæ¯æ们åçjsæ¬æ¥å°±ä¸å¤ªå ·å¤çè½åï¼æ们ä¸åºè¯¥æ使ç¨è¿çæ¡æ¶çææ³è¿äºå¸¦å ¥ï¼å æ¤ä»ç»ä»¶ä½¿ç¨çæ¹å¼ä¸æ们éè¦ååºæ¹åï¼æ们ä¸åºè¯¥è¿äºä¾èµå±æ§çé ç½®æ¥è¾¾å°æç§ææï¼å æ¤æ¹é æ¹æ³å¦ä¸ã
<cai-tablethead="Name|Age"><cai-tr><cai-td>zs</cai-td><cai-td></cai-td></cai-tr><cai-tr><cai-td>ls</cai-td><cai-td></cai-td></cai-tr></cai-table>æ们æå±äºHTMLåççè½åå½è¿ï¼èæ¯ä¸æ¯éç¨é ç½®çæ¹å¼ï¼å°±è§£å³äºè¿ä¸ªé®é¢ï¼ä½æ¯è¿æ ·åæ¶ä¹å³å®äºæ们çç»ä»¶å¹¶ä¸æ¯æ太è¿å¤æçè½åã
ç¶æçååç»å®ä¸é¢è®²äºæ°æ®çååç»å®ï¼ç»ä»¶ç¶æ页é¢ä¹ä¼éä¹æ´æ°ï¼é£ä¹æ们æä¹å®ç°ååç»å®å¢ï¼
æ¥ä¸æ¥æ们å°è£ ä¸ä¸ªinputæ¥å®ç°ååç»å®ã
<cai-inputid="ipt":value="data"@change="(e)=>{ data=e.detail}"></cai-input>//js(function(){ consttemplate=document.createElement('template')template.innerHTML=`<style>.cai-input{ }</style><inputtype="text"id="caiInput">`classCaiInputextendsHTMLElement{ constructor(){ super()constshadow=this.attachShadow({ mode:'closed'})constcontent=template.content.cloneNode(true)this._input=content.querySelector('#caiInput')this._input.value=this.getAttribute('value')shadow.appendChild(content)this._input.addEventListener("input",ev=>{ consttarget=ev.target;constvalue=target.value;this.value=value;this.dispatchEvent(newCustomEvent("change",{ detail:value}));});}getvalue(){ returnthis.getAttribute("value");}setvalue(value){ this.setAttribute("value",value);}}window.customElements.define('cai-input',CaiInput)})()è¿æ ·å°±å°è£ äºä¸ä¸ªç®åååç»å®çinputç»ä»¶ï¼ä»£ç ä¸get/setåobservedAttributes/attributeChangedCallbackåè æ¯çå¬å个ï¼åè å¯ä»¥çå¬å¤ä¸ªç¶ææ¹å并ååºå¤çã
è¿éé¢æ ¸å¿çä¸æ¥æ¯æ们çå¬äºè¿ä¸ªè¡¨åçinputäºä»¶ï¼å¹¶ä¸å¨æ¯æ¬¡è§¦åinputäºä»¶çæ¶å触åèªå®ä¹çchangeäºä»¶ï¼å¹¶ä¸æè¾å ¥çåæ°åä¼ ã
é£æ们åºè¯¥æä¹ä½¿ç¨å¢ï¼ä»¥vue为ä¾åï¼vueçååç»å®v-modelå ¶å®æ¯ä¸ä¸ªè¯æ³ç³,æ们çç»ä»¶å没æåæ³ä½¿ç¨è¿ä¸ªè¯æ³ç³ï¼ä¸v-modelä¸ç®ååæ³ç±»ä¼¼<cai-input:value="data"@change="(e)=>{ data=e.detail}">
å°è£ æ们èªå·±çç»ä»¶åºè®¾è®¡ç®å½ç»æ第ä¸æ¥ï¼è¦æä¸ä¸ªä¼é çç»ä»·åºæ们é¦å è¦è®¾è®¡ä¸ä¸ªä¼é çç®å½ç»æ设计ç®å½ç»æå¦ä¸
.âââcai-uiâââcomponents//èªå®ä¹ç»ä»¶|âââButton||âââindex.js|âââ...âââindex.js.//ä¸»å ¥å£ç¬ç«å°è£ç¬ç«å°è£ æ们çç»ä»¶ï¼ç±äºæ们ç»ä»¶åºä¸ç»ä»¶çå¼å ¥ï¼æ们è¯å®æ¯éè¦ææ¯ä¸ªç»ä»¶å°è£ å°åç¬æ件ä¸çã
å¨æ们çButton/index.jsä¸åå ¥å¦ä¸ï¼
(function(){ consttemplate=document.createElement('template')template.innerHTML=`<style>/*cssåä¸é¢ä¸æ ·*/</style><divclass="cai-button"><slotname="text"></slot></div>`classCaiButtonextendsHTMLElement{ constructor(){ super()//å ¶ä½åä¸è¿°ä¸æ ·}staticgetobservedAttributes(){ return['type']}attributeChangedCallback(name,oldValue,newValue){ this[name]=newValue;this.render();}render(){ this._btn.className=`cai-button${ this._type[this.type]}`}}window.customElements.define('cai-button',CaiButton)})()å°è£ å°ç»ä»¶å°åç¬çjsæ件ä¸
å ¨é¨å¯¼å ¥åæéå¯¼å ¥æ¯æå ¨é¨å¯¼å ¥ï¼æ们éè¿ä¸ä¸ªjsæä»¶å ¨é¨å¼å ¥ç»ä»¶
//index.jsimport'./components/Button/index.js'import'./components/xxx/xxx.js'æéå¯¼å ¥æ们åªéè¦å¯¼å ¥ç»ä»¶çjsæ件å³å¯å¦import'cai-ui/components/Button/index.js'
èªå®ä¹é 置主é¢æ¯æ主é¢è²å¯é ç½®æ们åªéæé¢è²åæåéå³å¯ï¼æ¹é å¦ä¸ï¼
(function(){ consttemplate=document.createElement('template')template.innerHTML=`<style>/*å¤ä½çç¥*/.cai-button{ border:1pxsolidvar(--primary-color,#ff);background-color:var(--primary-color,#ff);}.cai-button-warning{ border:1pxsolidvar(--warning-color,#faad);background-color:var(--warning-color,#faad);}.cai-button-danger{ border:1pxsolidvar(--danger-color,#ff4d4f);background-color:var(--danger-color,#ff4d4f);}</style><divclass="cai-button"><slotname="text"></slot></div>`//åé¢çç¥...})()è¿æ ·æ们就è½å¨å ¨å±ä¸ä¿®æ¹ä¸»é¢è²äºãæ¡ä¾å°å
å¨åçãVueåReactä¸ä¼é ç使ç¨å¨åçHTMLä¸åºç¨ï¼<scripttype="module">import'//cai-ui';</script><!--or--><scripttype="module"src="//cai-ui"></script><cai-buttontype="primary">ç¹å»</cai-button><cai-inputid="caiIpt"></cai-button><script>constcaiIpt=document.getElementById('caiIpt')/*è·åè¾å ¥æ¡çå¼æ两ç§æ¹æ³*1.getAttribute*2.changeäºä»¶*/caiIpt.getAttribute('value')caiIpt.addEventListener('change',function(e){ console.log(e);//e.detail为表åçå¼})</script>å¨Vue2xä¸çåºç¨://html<cai-buttonid="btn"></cai-button><script>btn.setAttribute('config',JSON.stringify({ icon:'',posi:''}))</script>//button.jsclassCaiButtonextendsHTMLElement{ constructor(){ xxx}staticgetobservedAttributes(){ return['type','config']//çå¬config}attributeChangedCallback(name,oldValue,newValue){ if(name==='config'){ newValue=JSON.parse(newValue)}this[name]=newValue;this.render();}render(){ }}window.customElements.define('cai-button',CaiButton)})()0å¨Vue3xä¸çå·®å¼:å¨æè¿çVue3ä¸ï¼Vue对WebComponentsæäºæ´å¥½çæ¯æãVue?å¨CustomElementsEverywhereæµè¯ä¸è·å¾äº%çå®ç¾åæ°ãä½æ¯è¿éè¦æ们ååºå¦ä¸é ç½®ï¼
è·³è¿Vueæ¬èº«å¯¹ç»ä»¶ç解æcustomElementsçé£æ ¼åVueç»ä»¶å¾åï¼å¯¼è´Vueä¼æèªå®ä¹ï¼éåççHTMLæ ç¾ï¼æ ç¾è§£æ并注å为ä¸ä¸ªVueç»ä»¶ï¼ç¶å解æ失败æä¼å解æ为ä¸ä¸ªèªå®ä¹ç»ä»¶ï¼è¿æ ·ä¼æ¶èä¸å®çæ§è½å¹¶ä¸ä¼å¨æ§å¶å°è¦åï¼å æ¤æ们éè¦å¨æå»ºå·¥å ·ä¸è·³è¿è¿ä¸ªè§£æï¼
//html<cai-buttonid="btn"></cai-button><script>btn.setAttribute('config',JSON.stringify({ icon:'',posi:''}))</script>//button.jsclassCaiButtonextendsHTMLElement{ constructor(){ xxx}staticgetobservedAttributes(){ return['type','config']//çå¬config}attributeChangedCallback(name,oldValue,newValue){ if(name==='config'){ newValue=JSON.parse(newValue)}this[name]=newValue;this.render();}render(){ }}window.customElements.define('cai-button',CaiButton)})()1ç»ä»¶çå ·ä½ä½¿ç¨æ¹æ³åVue2x类似ã
å¨Reactä¸çåºç¨//html<cai-buttonid="btn"></cai-button><script>btn.setAttribute('config',JSON.stringify({ icon:'',posi:''}))</script>//button.jsclassCaiButtonextendsHTMLElement{ constructor(){ xxx}staticgetobservedAttributes(){ return['type','config']//çå¬config}attributeChangedCallback(name,oldValue,newValue){ if(name==='config'){ newValue=JSON.parse(newValue)}this[name]=newValue;this.render();}render(){ }}window.customElements.define('cai-button',CaiButton)})()2WebComponents触åçäºä»¶å¯è½æ æ³éè¿React渲ææ æ£ç¡®çä¼ éãä½ éè¦å¨Reactç»ä»¶ä¸æå¨æ·»å äºä»¶å¤çå¨æ¥å¤çè¿äºäºä»¶ãå¨React使ç¨æ个ç¹æ们éè¦æ³¨æä¸ï¼WebComponentsç»ä»¶æ们éè¦æ·»å ç±»æ¶éè¦ä½¿ç¨classèä¸æ¯className
æ»ç»ç°é¶æ®µçå£å¿çå®è¿ç¯æç« å¤§å®¶è¯å®ä¼è§å¾ä¸ºä»ä¹WebComponentså®ç°äºä¸ä»½ä»£ç å¤ä¸ªæ¡æ¶ä½¿ç¨ï¼å´è¿æ²¡æé¸å ç»ä»¶åºçå¸åºå¢ï¼ææ»ç»äºä¸ä¸å ç¹ï¼
æ´å ååäºUIå±é¢ï¼ä¸ç°å¨æ°æ®é©±å¨ä¸å¤ªç¬¦ï¼åç°å¨çç»ä»¶åºè½åä¸ç¸æ¯åè½ä¼æ¯è¾å¼±ï¼ä½¿ç¨åºæ¯ç¸å¯¹åä¸ã
å ¼å®¹æ§è¿æå¾ æåï¼è¿éä¸ä» ä» æçæ¯æµè§å¨çå ¼å®¹æ§ï¼è¿ææ¡æ¶çå ¼å®¹æ§ï¼å¨æ¡æ¶ä¸ä½¿ç¨å¶å°ä¼åç°æå¤çâæåâï¼å¹¶ä¸åæ³ä¼æ¯è¾å¤æã
å¦æä¸åå©æ¡æ¶å¼åçè¯ï¼åæ³ä¼è¿çå½çï¼HTMLCSSJSä¼ç³ åå¨ä¸ä¸ªæ件ï¼htmlCSSé½æ¯å符串çå½¢å¼ï¼æ²¡æé«äº®ï¼æ ¼å¼ä¹éè¦èªå·±è°æ´ï¼å¯¹äºå¼å人å
Vue组件中如何引入外部的js文件
在Vue组件中引入外部js文件,无需依赖npm安装,以下是六种不同方法供参考。
方法一:在Vue项目的index.html中使用全局引入,如:
缺点:所有组件均加载该js插件,而非仅在特定组件中使用。
方法二:对于本地静态文件,使用import导入。
缺点:仅适用于本地静态文件,远程js文件不可直接导入。
方法三:在Vue组件加载完毕后,手动操作DOM插入js插件。
优势:仅当前组件加载该插件,避免全局引入带来的问题。
方法四:利用render方法,编写自定义组件。
实现:在页面中调用自定义组件,引入外部js文件。
方法五:高阶技巧,将方法三包装为js插件,使用Promise管理加载状态。
实现:js加载成功时调用resolve,加载失败时调用reject。
方法六:动态替换js文件,通过包装importJs.js插件。
实现:使用动态导入机制,根据需求加载不同的js文件。