It is similar to a react router.
After converting the dom-link element to a tag, the URL is changed without loading when clicked. If the URL is changed, if the URL path name matches the path attribute of the dom-router element, the content of the el attribute must be inserted into the outerHTML of the dom-router element. (this.outerHTML = this.getAttribute('el') means) If they do not match, the outerHTML of the corresponding dom-router element must be empty.
const App = `
<dom-link to="/">Home</dom-link>
<dom-link to="/test">Test</dom-link>
<dom-router path="/" el="<h1>home</h1>"></dom-router>
<dom-router path="/test" el="<h1>SPA Test</h1>"></dom-router>
`
render(App,document.getElementById('root'));
function render(element, queryinsertion) {
queryinsertion.innerHTML = element;
};
function createElement(element, props,innerHTML=""){
if(props == null || undefined){
return `<${element}>${innerHTML}</${element}>`
}else{
let Attribute = "";
Object.keys(props).forEach((element) => {
Attribute += `${element}="${props[element]}"`
});
return `<${element} ${Attribute}>${innerHTML}</${element}>`
};
};
customElements.define('dom-link', class extends HTMLElement {
connectedCallback() {
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz'
let className = "";
let props = {};
if(this.getAttribute('to')){
for (let i = 0; i < 8; i++) {
const rnum = Math.floor(Math.random() * chars.length)
className += chars.substring(rnum, rnum + 1)
};
Object.assign(props,{class:className});
};
if(this.getAttributeNames()) {
const AttrNames = this.getAttributeNames();
AttrNames.forEach(attr => {
if(attr == "to"){
Object.assign(props,{href:this.getAttribute(attr)});
}else{
if(props[attr]){
props[attr] += ` ${this.getAttribute(attr)}`;
}else{
props[attr] = `${this.getAttribute(attr)}`;
};
}
});
};
this.outerHTML = createElement('a',props,this.innerHTML);
document.querySelectorAll(`.${className}[href^="/"]`).forEach(el =>
el.addEventListener("click", evt => {
evt.preventDefault();
const {pathname: path} = new URL(evt.target.href);
window.history.pushState({path}, path, path);
})
);
};
});
customElements.define('dom-router', class extends HTMLElement {
connectedCallback() {
if(window.location.pathname == this.getAttribute('path')){
this.outerHTML = this.getAttribute('el');
}else{
this.outerHTML = "";
};
};
});
<div id="root"></div>
As an example, let's take an example in App const in the code above. When the above code is returned as HTML, the code below
<dom-link to="/">Home</dom-link>
<dom-link to="/test">Test</dom-link>
Is
<a class="{rendom}" href="/">Home</a>
<a class="{rendom}" href="/test">Test</a>
will be changed to
If you click the Home part, the URL at the top of the browser will be "example.com", and if you click the Test part, the URL will be changed to "example.com/test" without loading.
At this time
#1 <dom-router path="/" el="<h1>home</h1>"></dom-router>
#2 <dom-router path="/test" el="<h1>SPA Test</h1>"></dom-router>
When the URL is "example.com", part #1 should be inserted into outerHTML and part #2 should be deleted.
<h1>home</h1>
Conversely, when the URL is "example.com/test", part #2 should be inserted into outerHTML and part #1 should be deleted.
<h1>SPA Test</h1>