
ภาพถ่ายโซเชียลมีเดียโดย Federico Bottos บน Unsplash
รวมห้องสมุด Toolless ที่มีเครื่องมือไว้ด้วย การสาธิตสด
โปรดถามคำถามในที่เก็บอภิปรายโดยเฉพาะเพื่อช่วยชุมชนรอบ ๆ โครงการนี้เติบโต♥
ได้รับแรงบันดาลใจจาก Vue 3 " One Piece " Uce-Template ให้องค์ประกอบในตัว <template> ที่กำหนดเองเพื่อกำหนดส่วนประกอบในรูปแบบ Vue
< template is =" uce-template " >
< style scoped >
span { color: green }
</ style >
< the-green >
The < span > {{thing}} </ span > is green
</ the-green >
< script type =" module " >
export default {
setup ( ) {
return { thing : 'world' }
}
}
</ script >
</ template >เพิ่มไลบรารีนี้ลงในสมการและดูการบูตส่วนประกอบที่กำหนดทั้งหมด
<template lazy> เพื่อแก้ไขคำจำกัดความของพวกเขาเฉพาะเมื่อมีชีวิตอยู่<custom-element shadow> และรูปแบบ <style shadow> ที่มีเงา@uce เสมือนจริงเพื่อสร้าง UIs ปฏิกิริยาและอื่น ๆresolve(name, module) ในขณะที่มีการแนะนำให้ติดตั้ง CLI ทั่วโลกเนื่องจากการพึ่งพาแสงที่ไม่รุนแรง แต่ก็ยังคงเป็นคำสั่ง npx :
# check all options and usage
npx uce-template --help
# works with files
npx uce-template my-component.html
# works with stdin
cat my-component.html | uce-templateแต่แน่นอนว่าเราควรแน่ใจว่าการจัดวางที่ผลิตยังคงใช้งานได้ตามที่คาดไว้หรือไม่?
เทมเพลตใด ๆ ที่ขยาย uce-template จะต้อง มีองค์ประกอบที่กำหนดเองอย่างน้อยในนั้นไม่ว่าจะเป็นแบบปกติหรือในตัว:
<!-- register regular-element -->
< template is =" uce-template " >
< regular-element >
regular
</ regular-element >
</ template >
<!-- register builtin-element as div -->
< template is =" uce-template " >
< div is =" builtin-element " >
builtin
</ div >
</ template > เทมเพลตใด ๆ อาจ มีแท็ก <script> เดียวและ/หรือคำจำกัดความ <style> หนึ่งอันหรือมากกว่า
หากส่วนประกอบมีคำจำกัดความ {{slot.name}} โหนดจาก HTML ที่มีชีวิตก่อนที่ส่วนประกอบจะได้รับการอัพเกรดจะถูกวางไว้ในนั้นครั้งเดียว
ดูตัวอย่างสดนี้เพื่อทำความเข้าใจเพิ่มเติม
" องค์ประกอบ " แต่ละอันอาจกำหนดตัวเองด้วยหรือไม่มีเนื้อหาคงที่หรือไดนามิกของตัวเอง
เนื้อหา ดังกล่าวจะถูกใช้เพื่อแสดงผลแต่ละองค์ประกอบที่กำหนดเองหนึ่งครั้งเมื่อ " ติดตั้ง " (สด) และต่อการเปลี่ยนแปลงสถานะปฏิกิริยาแต่ละครั้ง แต่ เฉพาะ ในกรณีที่เทมเพลตไม่ว่างเปล่า
ชิ้นส่วนไดนามิก ทั้งหมดจะต้องถูกห่อหุ้มภายใน {{dynamic}} วงเล็บหยิกดังที่แสดงที่นี่:
< my-counter >
< button onclick = {{dec}} > - </ button >
< span > {{state.count}} </ span >
< button onclick = {{inc}} > + </ button >
</ my-counter > การอ้างอิง state dec และ inc จะถูกส่งผ่านผ่านโหนดสคริปต์ถ้ามี
เมื่อใดก็ตามที่มีการแสดงผลส่วนประกอบการอัพเดทการโทรกลับจะถูกเรียกใช้ให้องค์ประกอบเป็น บริบท
< button is =" my-button " >
I am a {{this.tagName}}
</ button >เกี่ยวกับ Shadowdom Polyfill ของมันไม่รวมอยู่ในโครงการนี้ แต่เป็นไปได้ที่จะกำหนดส่วนประกอบผ่าน รูทเงา ของมันโดยการเพิ่มแอตทริบิวต์ เงา :
< my-counter shadow >
<!-- this content will be in the shadowRoot -->
< button onclick = {{dec}} > - </ button >
< span > {{state.count}} </ span >
< button onclick = {{inc}} > + </ button >
</ my-counter > แอตทริบิวต์ shadow open โดยค่าเริ่มต้น แต่สามารถระบุได้ว่าเป็น shadow=closed
เกี่ยวกับ {{JS}} หากแอตทริบิวต์และคุณต้องการใช้ช่องว่าง {{ JS }} รอบ ๆ แอตทริบิวต์ จะต้อง อยู่ในเครื่องหมายคำพูดมิฉะนั้นเทมเพลต HTML จะทำลายเลย์เอาต์ในรูปแบบที่ไม่คาดคิด
<!-- OK -->
< my-counter >
< button onClick = {{dec}} > - </ button >
</ my-counter >
<!-- OK -->
< my-counter >
< button onClick =" {{ dec }} " > - </ button >
</ my-counter >
<!-- IT BREAKS!!! -->
< my-counter >
< button onClick = {{ dec }} > - </ button >
</ my-counter ><!--{{interpolation}}--> กรณีเนื่องจากทุกอย่างในที่นี่ส่วนใหญ่ขึ้นอยู่กับพฤติกรรม HTML มาตรฐานมีหลายกรณีที่ควรมีการแก้ไขเป็นความคิดเห็น
กฎของหัวแม่มือคือถ้าคุณไม่เห็นเค้าโครงหรือคุณอ่านข้อผิดพลาด เทมเพลตที่ไม่ดี บางอย่างเป็นไปได้ว่าการแก้ไขของคุณอาจถูกกลืนโดยองค์ประกอบ เทมเพลต
สิ่งนี้เกิดขึ้นส่วนใหญ่กับองค์ประกอบเช่น ตาราง เลือก และองค์ประกอบอื่น ๆ ที่ยอมรับเฉพาะโหนดเด็กประเภทเฉพาะ แต่ไม่ใช่ข้อความ
<!-- ? this won't work as expected -->
< table is =" my-table " >
< tbody > {{rows}} </ tbody >
</ table >
<!-- ? this works ? -->
< table is =" my-table " >
< tbody > <!--{{rows}}--> </ tbody >
</ table > ในกรณีแรก <tbody> จะไม่สนใจโหนดใด ๆ ที่ไม่ใช่ <tr> ยกเว้นความคิดเห็น เพราะความคิดเห็นไม่ได้ถูกกลืนหรือหายไปในกระบวนการ
คุณสามารถดูนิยามไฟล์ dbmonster.html สำหรับทั้งสอง custom <table> และองค์ประกอบ <tr> ที่กำหนดเอง
ส่วนประกอบสามารถมี หนึ่งสไตล์ขึ้นไป ภายใน ขอบเขต เฉพาะ:
<style> ทั่วไปจะใช้เนื้อหาทั่วโลกมีประโยชน์ในการจัดการกับ my-counter + my-counter {...} ตัวอย่างเช่นตัวอย่าง<style scoped> จะใช้คำนำหน้าเนื้อหาด้วยชื่อองค์ประกอบที่กำหนดเอง (เช่น my-counter span, my-counter button {...} )<style shadow> จะใช้เนื้อหาที่ด้านบนของ Shadowroot โดยสมมติว่าส่วนประกอบถูกกำหนดด้วยแอตทริบิวต์ shadow ไม่มีอะไรเป็นพิเศษที่ต้องพิจารณาที่นี่ยกเว้นว่ารูปแบบ ทั่วโลก อาจรบกวน IE11 หาก obtuised เกินไปเช่นเดียว กับ IE11 อีกครั้งไม่เข้าใจวัตถุประสงค์และพฤติกรรมขององค์ประกอบ <template>
คำจำกัดความสามารถมี แท็กสคริปต์เดียว เท่านั้นและ สคริปต์ ดังกล่าวจะได้รับการจัดการเหมือน โมดูล
เนื่องจาก IE11 ไม่ สามารถใช้งานได้กับองค์ประกอบ <template> หากไม่ได้ระบุ type IE11 จะพยายามประเมินสคริปต์ทั้งหมดในหน้าขวา
ดังนั้นแอตทริบิวต์ type สามารถมีค่าใด ๆ ได้จริง ๆ เนื่องจากมันไม่เกี่ยวข้องกับไลบรารีนี้อย่างสมบูรณ์ แต่ค่าดังกล่าวจะต้องไม่สามารถใช้งานได้กับ IE11 และ module เป็นเพียงค่าเดียวที่ IE11 จะเพิกเฉย
สคริปต์ อาจ มี default export หรือแม้กระทั่ง module.exports = ... ซึ่งการส่งออกดังกล่าว อาจ มี setup(element) { ... } วิธีที่ส่งคืนสิ่งที่ชิ้นส่วน ไดนามิก ของส่วนประกอบคาดหวัง:
< script type =" module " >
import { reactive } from '@uce' ;
export default {
setup ( element ) {
const state = reactive ( { count : 0 } ) ;
const inc = ( ) => { state . count ++ } ;
const dec = ( ) => { state . count -- } ;
return { state , inc , dec } ;
}
} ;
</ script > @uce reactive helper ทำให้สามารถอัปเดตมุมมองโดยอัตโนมัติเมื่อใดก็ตามที่หนึ่งในคุณสมบัติของมันเปลี่ยนไป
หากต้องการทราบข้อมูลเพิ่มเติมเกี่ยวกับการเปลี่ยนแปลงปฏิกิริยาโปรดอ่านโพสต์สื่อนี้
setup หากพบ <script type="module" setup> เนื้อหาของสคริปต์จะถูกเรียกใช้ด้วยองค์ประกอบเองเป็นบริบท
การสาธิตสด
< x-clock > </ x-clock >
< template is =" uce-template " >
< x-clock > {{time}} </ x-clock >
< script type =" module " setup >
let id = 0 ;
export default {
get time ( ) {
return ( new Date ) . toISOString ( ) ;
}
} ;
this . connected = e => id = setInterval ( this . render , 1000 / 30 ) ;
this . disconnected = e => clearInterval ( id ) ;
</ script >
</ template > ทางลัดนี้มีประโยชน์เป็นพิเศษสำหรับส่วนประกอบที่ไม่จำเป็นต้องตั้งค่า การสังเกตการณ์ แต่อาจต้องติดตั้ง อุปกรณ์ประกอบฉาก และสำหรับกรณีหลังแอตทริบิวต์ setup ควรมี props
< script type =" module " setup =" props " >
// props are defined as key => defaultValue pairs
export const props = {
name : this . name || 'anonymous' ,
age : + this . age || 0
} ;
</ script > เป้าหมายส่วนนี้คือการแสดงตัวอย่างพื้นฐานไปยังตัวอย่างที่ซับซ้อนผ่าน UCE-Template ซึ่งตัวอย่างบางอย่างอาจใช้ส่วนขยาย .uce เพื่อ จำกัด ส่วนประกอบภายในไฟล์ของตนเอง
.uce FILES เป็น HTML หากคุณใช้รหัส VS คุณสามารถ Ctrl+Shift+P , พิมพ์ การตั้งค่า JSON , เลือก Open Settings (JSON) และเพิ่มสิ่งต่อไปนี้ในไฟล์ ดัง .uce
{
"other-settings" : "..." ,
"files.associations" : {
"*.uce" : "html"
}
} หากเรากำหนดส่วนประกอบเป็น view/my-component.uce เราอาจตัดสินใจที่จะรวมความเกียจคร้านเหล่านี้หรือดีกว่าเฉพาะเมื่อพบสิ่งเหล่านี้ในหน้าปัจจุบัน
วิธีการนี้ช่วยลดความซับซ้อนของการรวมกลุ่มการพึ่งพาจำนวนมากที่ไม่จำเป็นและสามารถทำได้โดยรวมถึง uce-template และ Uce-Loader ขนาดเล็ก (364 ไบต์) เป็น bootstrap
import { parse , resolve } from 'uce-template' ;
import loader from 'uce-loader' ;
// optional components dependencies
import something from 'cool' ;
resolve ( 'cool' , something ) ;
// bootstrap the loader
loader ( {
on ( component ) {
// ignore uce-template itself
if ( component !== 'uce-template' )
fetch ( `view/ ${ component } .uce` )
. then ( body => body . text ( ) )
. then ( definition => {
document . body . appendChild (
parse ( definition )
) ;
} ) ;
}
} ) ;เทคนิคเดียวกันนี้สามารถใช้โดยตรงในหน้า HTML ใด ๆ เขียนโค้ดที่อาจเข้ากันได้กับ IE11 ด้วย
<!doctype html >
< html >
< head >
< script defer src =" //unpkg.com/uce-template " > </ script >
< script defer src =" //unpkg.com/uce-loader " > </ script >
< script defer >
addEventListener (
'DOMContentLoaded' ,
function ( ) {
uceLoader ( {
Template : customElements . get ( 'uce-template' ) ,
on : function ( name ) {
if ( name !== 'uce-template' ) {
var xhr = new XMLHttpRequest ;
var Template = this . Template ;
xhr . open ( 'get' , name + '.uce' , true ) ;
xhr . send ( null ) ;
xhr . onload = function ( ) {
document . body . appendChild (
Template . from ( xhr . responseText )
) ;
} ;
}
}
} ) ;
} ,
{ once : true }
) ;
</ script >
</ head >
< body >
< my-component >
< p slot =" content " >
Some content to show in < code > my-component </ code >
</ p >
</ my-component >
</ body >
</ html >uce-template ขี้เกียจหากหน้าส่วนใหญ่ของเราไม่ได้ใช้ส่วนประกอบเลยการเพิ่ม 7K+ ของ JS ที่ด้านบนของแต่ละหน้าอาจไม่พึงประสงค์
อย่างไรก็ตามเราสามารถทำตามวิธีการ ที่ขี้เกียจที่โหลดได้ เหมือนกันยกเว้นตัวโหลดของเราจะรับผิดชอบในการนำไลบรารี UCE-Template ไม่ว่าจะเมื่อพบ Uce-template หรือส่วนประกอบอื่น ๆ
import loader from 'uce-loader' ;
loader ( {
on ( component ) {
// first component found, load uce-template
if ( ! this . q ) {
this . q = [ component ] ;
const script = document . createElement ( 'script' ) ;
script . src = '//unpkg.com/uce-template' ;
document . body . appendChild ( script ) . onload = ( ) => {
// get the uce-template class to use its .from(...)
this . Template = customElements . get ( 'uce-template' ) ;
// load all queued components
for ( var q = this . q . splice ( 0 ) , i = 0 ; i < q . length ; i ++ )
this . on ( q [ i ] ) ;
} ;
}
// when uce-template is loaded
else if ( this . Template ) {
// ignore loading uce-template itself
if ( component !== 'uce-template' ) {
// load the component on demand
fetch ( `view/ ${ component } .uce` )
. then ( body => body . text ( ) )
. then ( definition => {
document . body . appendChild (
this . Template . from ( definition )
) ;
} ) ;
}
}
// if uce-template is not loaded yet
// add the component to the queue
else
this . q . push ( component ) ;
}
} ) ;การใช้เทคนิคนี้ Payload JS ของเราต่อหน้าจะลดลงเหลือน้อยกว่า 0.5K เมื่อรหัสเหนือได้รับการรวมและลดลงในขณะที่ทุกอย่างจะเกิดขึ้นโดยอัตโนมัติเฉพาะในกรณีที่มีส่วนประกอบอยู่ที่ไหนสักแห่งในหน้า
เนื่องจากหน้าอาจมีองค์ประกอบที่กำหนดเองอื่น ๆ จากบุคคลที่สามและห้องสมุดจึงอาจเป็นความคิดที่ดีที่จะกำหนด ชุด ส่วนประกอบที่คาดหวังที่รู้จักกันดีตรงข้ามกับการพยายามโหลดองค์ประกอบที่กำหนดเองที่เป็นไปได้ใด ๆ ผ่าน view/${...}.uce
เทคนิคการโหลดขี้เกียจก่อนหน้านี้จะใช้งานได้ดีอยู่แล้ว แต่แทนที่จะตรวจสอบว่าชื่อส่วนประกอบไม่ใช่ uce-template เราสามารถใช้ ชุด :
loader ( {
known : new Set ( [ 'some-comp' , 'some-other' ] ) ,
on ( component ) {
if ( this . known . has ( component ) )
fetch ( `view/ ${ component } .uce` )
. then ( body => body . text ( ) )
. then ( definition => {
document . body . appendChild (
parse ( definition )
) ;
} ) ;
}
} ) ; ข้อได้เปรียบของเทคนิคนี้คือ ชุด known สามารถสร้างขึ้นแบบไดนามิกผ่านรายการ view/*.uce เพื่อไม่ให้ไม่มีอะไรจะแตกหักหากองค์ประกอบที่พบไม่ได้เป็นส่วนหนึ่งของตระกูล UCE-Template
uce-template ย่อมต้องใช้ Function เพื่อประเมินส่วนเทมเพลตหรือ ต้องการในสคริปต์ (... )
ขอแนะนำให้เพิ่มความปลอดภัยโดยใช้ทั้ง IJELM8 ijeLM8+5uwZ7ZXFmK+H2dwIWdiKJ1A4zhZIsq2Ffqqo= หรือแอตทริบิวต์ ความสมบูรณ์ที่ ไว้วางใจผ่าน CSP เท่านั้นสคริปต์ที่มาจากโดเมนของเราเอง
< meta http-equiv =" Content-Security-Policy " content =" script-src 'self' 'unsafe-eval' " >
< script defer src =" /js/uce-template.js "
integrity =" sha256-ijeLM8+5uwZ7ZXFmK+H2dwIWdiKJ1A4zhZIsq2Ffqqo= "
crossorigin =" anonymous " >
</ script >โปรดทราบว่าค่าเหล่านี้ เปลี่ยนไปทุกรุ่น ดังนั้นโปรดตรวจสอบให้แน่ใจว่าคุณมีเวอร์ชันล่าสุด (readme นี้สะท้อนถึงล่าสุด)
หากเป็น Uce หากคำจำกัดความมีวิธีการ onEvent(){...} วิธีการเหล่านี้จะถูกใช้เพื่อกำหนดส่วนประกอบ
อย่างไรก็ตามเนื่องจากรัฐมักจะถูกแยกออกจากส่วนประกอบเองจึงเป็นความคิดที่ดีที่จะใช้ beakmap เพื่อเชื่อมโยงองค์ประกอบใด ๆ กับสถานะของมันและ ... ไม่ต้องกังวล, beakmap ได้รับการสนับสนุนใน IE11 ด้วย!
การสาธิตสด
< button is =" my-btn " >
Clicked {{times}} times!
</ button >
< script type =" module " >
const states = new WeakMap ;
export default {
setup ( element ) {
const state = { times : 0 } ;
states . set ( element , state ) ;
return state ;
} ,
onClick ( ) {
states . get ( this ) . times ++ ;
// update the current view if the
// state is not reactive
this . render ( ) ;
}
} ;
</ script >โปรดทราบว่าตัวอย่างนี้ครอบคลุมกรณีการใช้งาน สถานะ เทียบกับ ส่วนประกอบ ใด ๆ เนื่องจากการใช้ WeakMap เป็นคำแนะนำ
หากวัตถุ props ถูกกำหนดและเนื่องจาก อุปกรณ์ประกอบฉาก * อัปเดตมุมมองโดยอัตโนมัติเมื่อมีการเปลี่ยนแปลงเราอาจไม่จำเป็นต้องใช้ beakmap เพื่อเชื่อมโยงสถานะของส่วนประกอบ
การสาธิตสด
< button is =" my-btn " > </ button >
< template is =" uce-template " >
< button is =" my-btn " >
Clicked {{this.times}} times!
</ button >
< script type =" module " >
export default {
props : { times : 0 } ,
onClick ( ) {
this . times ++ ;
}
} ;
</ script >
</ template > ข้อได้เปรียบของการใช้อุปกรณ์ประกอบฉากคือเป็นไปได้ที่จะกำหนดสถานะเริ่มต้นผ่านแอตทริบิวต์หรือผ่านการตั้งค่าโดยตรงเมื่อแสดงผลผ่านยูทิลิตี้ html เพื่อให้มีปุ่มที่มี times="3" เป็น ตัวอย่าง ทันที
< button is =" my-btn " times =" 3 " > </ button > import {ref} from '@uce' ช่วยลดความซับซ้อนของการดึงโหนดโดย ref="name" แอตทริบิวต์
< element-details >
< span ref =" name " > </ span >
< span ref =" description " > </ span >
</ element-details >
< template is =" uce-template " >
< element-details > </ element-details >
< script type =" module " setup >
import { ref } from '@uce' ;
const { name , description } = ref ( this ) ;
name . textContent = 'element name' ;
description . textContent = 'element description' ;
</ script >
</ template > import {slot} from '@uce' ช่วยลดความซับซ้อนของการดึงสล็อตตามชื่อโดยส่งคืน อาร์เรย์ ขององค์ประกอบที่จัดกลุ่มผ่านชื่อเดียวกัน
สิ่งนี้สามารถใช้เพื่อวางสล็อตเดี่ยวในการแก้ไขดังแสดงในตัวอย่างนี้หรือวางสล็อตหลายช่องภายในโหนดเดียวกัน
การสาธิตสด
< filter-list >
Loading filter ...
< ul >
< li slot =" list " > some </ li >
< li slot =" list " > searchable </ li >
< li slot =" list " > text </ li >
</ ul >
</ filter-list >
< template is =" uce-template " >
< filter-list >
< div >
< input placeholder = filter oninput = {{filter}} >
</ div >
< ul >
{{list}}
</ ul >
</ filter-list >
< script type =" module " >
import { slot } from '@uce' ;
export default {
setup ( element ) {
const list = slot ( element ) . list || [ ] ;
return {
list ,
filter ( { currentTarget : { value } } ) {
for ( const li of list )
li . style . display =
li . textContent . includes ( value ) ? null : 'none' ;
}
} ;
}
} ;
</ script >
</ template >อย่างไรก็ตาม ในกรณีที่คำสั่งสล็อตชื่อเดียวกันไม่จำเป็นต้องมองเห็นตามลำดับมันเป็นไปได้เสมอที่จะผ่านอาร์เรย์ของโหนดแทน
นั่นคือค่าการแก้ไขใด ๆ สามารถเป็นโหนด DOM ค่าบางส่วนหรืออาร์เรย์ของโหนดเช่นเดียวกับ µhtml ทำงาน
การสาธิตสด
< howto-tabs >
< p > Loading tabs ... </ p >
< howto-tab role =" heading " slot =" tab " > Tab 1 </ howto-tab >
< howto-panel role =" region " slot =" panel " > Content 1 </ howto-panel >
< howto-tab role =" heading " slot =" tab " > Tab 2 </ howto-tab >
< howto-panel role =" region " slot =" panel " > Content 2 </ howto-panel >
</ howto-tabs >
< template is =" uce-template " >
< howto-tabs >
{{tabs}}
</ howto-tabs >
< script type =" module " >
import { slot } from '@uce' ;
export default {
setup ( element ) {
const { tab , panel } = slot ( element ) ;
const tabs = tab . reduce (
( tabs , tab , i ) => tabs . concat ( tab , panel [ i ] ) ,
[ ]
) ;
return { tabs } ;
}
} ;
</ script >
</ template > ระบบโมดูล ที่จัดทำโดย UCE-Template นั้นง่ายมากและขยายได้อย่างเต็มที่เพื่อให้แต่ละองค์ประกอบสามารถ import any from 'thing'; ตราบใด thing มีการจัดเตรียม/แก้ไขผ่านห้องสมุด
หากเราจะกำหนดจุดเข้าร่วมชุดเดียวและเรารู้ว่าแต่ละองค์ประกอบจะต้องมีการพึ่งพาอย่างน้อยหนึ่งรายการเราสามารถทำสิ่งต่อไปนี้:
import { resolve } from 'uce-template' ;
import moduleA from '3rd-party' ;
const moduleB = { any : 'value' } ;
resolve ( 'module-a' , moduleA ) ;
resolve ( 'module-b' , moduleB ) ;เมื่อการสร้างนี้เป็นจุดเริ่มต้นของหน้าเว็บเดียวส่วนประกอบทั้งหมดจะสามารถ นำเข้า โมดูลฐาน/เริ่มต้นทั้งหมดได้ทันทีรวมถึงการแก้ไขล่วงหน้าทั้งหมด
การสาธิตสด (ดูทั้ง HTML และ JS Panel + Console)
< my-comp > </ my-comp >
< script type =" module " >
import moduleA from 'module-a' ;
import moduleB from 'module-a' ;
export default {
setup ( ) {
console . log ( moduleA , moduleB ) ;
}
}
</ script > ในกรณีที่ส่วนประกอบที่กำหนด นำเข้า บางอย่างจากไฟล์ภายนอกเช่น import module from './js/module.js' จะทำการนำเข้าดังกล่าวจะได้รับ ./js/module.js แก้ไขอย่างเกียจคร้านพร้อมกับโมดูลอื่น ๆ ที่ยังไม่ทราบ
// a file used to bootstrap uce-template component
// dependencies can always use the uce-template class
const { resolve } = customElements . get ( 'uce-template' ) ;
// resolve one to many modules
resolve ( 'quite-big-module' , { ... } ) ;สคริปต์ส่วนประกอบสามารถนำเข้าไฟล์นี้และเข้าถึงโมดูลที่ส่งออกได้ทันที
การสาธิตสด
< script type =" module " >
import './js/module.js' ;
import quiteBigModule from 'quite-big-module' ;
export default {
setup ( ) {
console . log ( quiteBigModule ) ;
}
}
</ script > เมื่อรวมกับ ส่วนประกอบที่โหลดขี้เกียจ วิธีนี้ทำให้สามารถจัดส่งส่วนประกอบที่ขึ้นอยู่กับคำจำกัดความของไฟล์ vue/comp.uce ภายนอกได้อย่างสมบูรณ์ซึ่งส่วนประกอบใด ๆ เหล่านี้สามารถแบ่งปันไฟล์ .js หนึ่งไฟล์หรือมากกว่าสามารถ แก้ไข โมดูลใด ๆ ที่จำเป็นหรือที่นั่น
ในฐานะที่เป็นไฟล์แบบสแตนด์อโลนขนาดองค์ประกอบที่กำหนดเองของฉันอยู่ที่ประมาณ 2.1k แต่เนื่องจากมีการแบ่งปันเกือบทุกห้องสมุด ที่ ใช้เช่นกันการรวมเข้าด้วยกันดูเหมือนวิธีที่ดีที่สุดที่จะไปส่งผลให้เพียง 1k พิเศษสำหรับโมดูลที่เหมาะกับงบประมาณประมาณ 7k ถึง 10k
ในทางกลับกันเนื่องจาก polyfill ไม่ได้เกิดขึ้นและขึ้นอยู่กับการตรวจจับคุณสมบัติรันไทม์ซึ่งหมายความว่าไม่มีใครควรสนใจเกี่ยวกับการนำโพลีฟิลอื่น ๆ มาก่อน แต่ยังมี โครเมี่ยม , Firefox และ Edge จะไม่ถูกแตะต้อง
ในกรณี Safari หรือ WebKit ที่ใช้องค์ประกอบที่กำหนดเองจะถูกจัดเตรียมไว้ในขณะที่อยู่ใน IE11 และ MS Edge เก่าทั้งใน Builtin ขยายและองค์ประกอบปกติจะได้รับการแก้ไข
นั่นคือ: ไม่ต้องกังวลกับโพลีฟิลใด ๆ เพราะทุกอย่างรวมอยู่ในที่นี่แล้ว!
หากคุณกำลังกำหนดเป้าหมายเบราว์เซอร์ที่คุณรู้ว่ามีองค์ประกอบที่กำหนดเองแบบดั้งเดิม V1 คุณสามารถใช้เวอร์ชัน ESM นี้ซึ่งไม่รวมโพลีฟิลด์ทั้งหมดและรวมถึงตรรกะเท่านั้น
ชุด es.js ปัจจุบันนั้นเป็น ~ 7K gzipped และ ~ 6.5K Brotli เพื่อให้สามารถประหยัดแบนด์วิดท์พิเศษในโครงการของคุณได้
ในกรณีเช่นนี้หากเป็นเบราว์เซอร์เป้าหมายเดียวจะต้องรวมโมดูล @webreflection/custom-elements-builtin ไว้ ก่อนที่ โมดูล UCE-template จะลงจอดบนหน้า
< script defer src =" //unpkg.com/@webreflection/custom-elements-builtin " > </ script >
< script defer src =" //unpkg.com/uce-template " > </ script >สิ่งนี้จะช่วยให้มั่นใจได้ว่าทั้งแบบปกติและในตัวจะทำงานได้ตามที่คาดไว้
น่าเสียดายที่ Shadowdom เป็นหนึ่งในข้อกำหนดเหล่านั้นที่เป็นไปไม่ได้ที่จะทำ polyfill แต่ข่าวดีก็คือคุณไม่ค่อยต้องการ Shadowdom ใน Uce-template แต่ถ้าเบราว์เซอร์ของคุณเข้ากันได้คุณสามารถใช้ Shadowdom ได้มากเท่าที่คุณต้องการ
อย่างไรก็ตาม มีโพลีฟิลด์บางส่วนที่เป็นไปได้อย่างน้อยสองส่วนที่จะต้องพิจารณา: แนบ Shadow ซึ่งมีความเรียบง่ายและมีน้ำหนักเบาและร่มรื่นซึ่งอยู่ใกล้กับมาตรฐาน แต่หนักกว่าอย่างแน่นอน แม้ว่า โพ ลี ฟิลด์ทั้งสองจะสามารถฉีดได้
<!-- this must be done before uce-template -->
< script >
if ( ! document . documentElement . attachShadow )
document . write ( '<script src="//unpkg.com/attachshadow"><x2fscript>' ) ;
</ script >
< script defer src =" //unpkg.com/uce-template " > </ script > เนื่องจากเบราว์เซอร์ที่ทันสมัยทุกคนจะมี document.documentElement.attachShadow , document.write จะเกิดขึ้น เฉพาะ ใน IE11 โดยไม่ต้องประนีประนอมหรือลงโทษเบราว์เซอร์เดสก์ท็อปมือถือและทันสมัย
ป <x2fscript>
{{...}} แทน ${...} ? เท่าที่ฉันอยากจะมี ${...} ขอบเขตการแก้ไข IE11 จะแตกหักถ้าองค์ประกอบใน DOM มี ${...} เป็นแอตทริบิวต์
เนื่องจาก {{...}} เป็นทางเลือกที่จัดตั้งขึ้นอย่างดีฉันจึงตัดสินใจหลีกเลี่ยงปัญหา Monkey-Patching IE11 และติดกับทางเลือกมาตรฐาน de-facto
นอกจากนี้ยังคุ้มค่าที่จะพิจารณาว่า Vue ใช้ {{...}} เช่นกันและเอ็นจิ้นที่ใช้เทมเพลตอื่น ๆ อีกมากมาย
Function ? ตามที่อธิบายไว้ในส่วน " CSP & Integrity/Nonce " ของวิธีการ/ตัวอย่างจำเป็นต้องใช้ Function ด้วยเหตุผลอย่างน้อยสองเหตุผล:
"use strict"; คำสั่งและผ่านคำสั่ง with(object) จำเป็นต้องเข้าใจการแก้ไขโดยไม่ต้องสร้างเครื่องยนต์ JS ทั้งหมดตั้งแต่รอยขีดข่วนrequire ฟังก์ชั่นภายใน <script type="module"> เนื้อหา แต่ถึงแม้ว่าจะไม่มี Function ในสมการการแยกวิเคราะห์และการดำเนินการแท็ก <script> เพื่อกำหนดองค์ประกอบที่กำหนดเองจะเป็นสิ่งที่เทียบเท่ากับการใช้ Function เพราะ CSP จะต้องใช้กฎพิเศษเนื่องจากการดำเนินการโดย ทั่วไป
โดยสรุปแทนที่จะหลอกเบราว์เซอร์ด้วยวิธีปฏิบัติที่ปลอดภัยหรือไม่ปลอดภัยเป็น Function การเรียกฉันก็ใช้ Function แทนการรักษาขนาดของรหัสให้เหมาะสม
โครงการนี้ เป็น องค์ประกอบที่กำหนดเองแบบดั้งเดิมได้ยกเว้นค่าใช้จ่ายคำจำกัดความซึ่งเป็นการดำเนินการ ครั้งเดียว ต่อ คลาส องค์ประกอบที่กำหนดเองที่ไม่ซ้ำกันแต่ละคลาสดังนั้นจึงไม่เกี่ยวข้องในระยะยาวและมีค่าใช้จ่ายที่ไม่สำคัญภายในเทมเพลตเริ่มต้นล อ จิก
คุณสามารถตรวจสอบการสาธิต DBMonster คลาสสิกได้ที่นี่และดูว่ามันทำงานได้ดี
ไม่มีสิ่งใดในไลบรารีนี้ที่ปิดกั้นและโมดูลได้รับการแก้ไขเพียง ครั้งเดียว แม้กระทั่งการนำเข้าเส้นทางที่สัมพันธ์กัน
ตรรกะนั้นค่อนข้างง่าย: หากชื่อโมดูลยังไม่ได้รับการแก้ไขและเป็นการนำเข้าสัมพัทธ์คำขอแบบอะซิงโครนัสจะถูกสร้างและประเมินในภายหลังในขณะที่หากโมดูลไม่ได้รับการแก้ไขและเป็นชื่อที่ผ่านการรับรองจะได้รับการแก้ไขเพียงครั้งเดียว
ทั้งหมดนี้รวมถึง การนำเข้า เพื่อ ต้องการ ความละเอียดได้รับการจัดการโดยผู้ช่วย UCE-Require โดยมีจุดประสงค์ไม่ได้ประกอบกับโมดูลนี้เองเพราะมันหวังว่าจะเป็นแรงบันดาลใจและถูกใช้โดยโครงการอื่น ๆ ด้วย
หากคุณต้องการเข้าใจเพิ่มเติมเกี่ยวกับ uce-template และทำงานอย่างไรโปรดตรวจสอบหน้านี้