vue-pre-render-and-mount
by lid0
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/3.0.5/vue.global.js"></script>
<!--
This is a rendered decorated template
we wrap expressions in ref tag, with the original expression
Note: this approach does not work for conditional rendering
-->
<script id ="source" type="text/html" id="my-comp-template">
<div>Welcome : <ref v="{{ hello }}">someone</ref> </div>
<button @click="click"><ref v="{{clickMsg}}"> click for nothing</ref> </button>
<div>is mounted :<ref v='{{isMounted ? "yes" : "no" }}'>no</ref> </div>
<!-- v-if conditional render, will not work as it will always show its content -->
<div class="msg" v-if="false"> will be removed when mounted </div>
<div class="msg" v-else > v-else this will stay </div>
</script>
<pre>Wait 3 seconds for app to mount</pre>
<div id="content">
<!-- will be populated synchronously search engine should pick it up -->
</div>
CSS
#content {
border:1px solid gray;
padding:10px;
width:400px;
}
.msg {
width:400px;
background:#cece44;
padding:2px;
}
JavaScript
var src = document.getElementById("source")
var target = document.getElementById("content")
const annotationTag = 'ref';
trasnferTemplateToContainer(src,target)
function trasnferTemplateToContainer(src,target){
target.innerHTML = src.innerHTML
}
/**
take an annotated rendered template, and convert back to template.
<div><ref v="{{msg}}">hello</ref></div>
output
<div>{{msg}}</div>
**/
function templetaize(sourceElement){
var el = document.createElement("div")
el.innerHTML = sourceElement
// find all ref tags, and replace tags with content in "v" attribute
m = el.querySelectorAll(annotationTag)
m.forEach((el)=>{
el.parentNode.replaceChild(document.createTextNode(el.getAttribute("v")), el)
})
return el.innerHTML
}
setTimeout(loadAppInDelay, 3000)
function loadAppInDelay(){
app.mount("#content")
}
const App = {
template: templetaize(source.innerHTML),
data(){
return {
hello: "you, app is now mounted",
clickMsg: "click for alert",
isMounted : "false"
}
},
methods: {
click(){
alert("you clicked")
},
mounted(){
isMounted = true
}
}
}
let app = Vue.createApp(App)