Hi everyone, It's been a while since the last chapter of 'Code your own vue', in the last post we saw how to do our own lifecycle hooks, today we going to see how to code methods and events.
If you followed atleast the first chapter you can use methods and events in this way
<div id="app">
<h1>{{ msg }}</h1>
<button onclick="hi()">Click me</button>
</div>
const vm = new Vue({
el: "#app",
data: {
msg: "Hello",
},
});
// toggle vm.msg between 'Hello' and "World"
const hi = () => vm.msg = vm.msg === "Hello" ? "World" : "Hello";
But today we going to programm this in the vue way:
<div id="app">
<h1>{{ msg }}</h1>
<button v-on:click="hi">Click me</button>
</div>
const vm = new Vue({
el: "#app",
data: {
msg: "Hello",
},
methods: {
hi() {
this.msg = this.msg === "Hello" ? "World" : "Hello";
},
},
});
Implementing methods
First we can define a function that will read the methods and mix all those methods with our vue instance. Like this:
function walkMethods(vue, methods) {
for (const key in methods) {
vue[key] = methods[key];
}
}
Then call the function in the constructor before the created lifecycle hook.
class Vue {
constructor({ methods }) {
// Before Create
walkMethods(this, methods);
// Create
// Mount
And now you should be able to call this.[method]
in the vm
or vm.[method]
outside of vue.
Implementing events
Implementing events is more dificult. Javascript Dom cannot get attributes with specials characters like @click
or v-on:click
. So we need to handle that, for that I decided read the innerHTML
and add vue-event=[event]
and vue-event-method=[method]
as attribute when a @[event]
or v-on:[event]
is found in a element. Other thing to consider is editing the innerHTML
, if we add a event and edit the innerHTML
the element will lose all events, for this reason we need to edit the innerHTML
before adding any event.
const regex = {
// regex to get v-on:[event]="[method]" and @[event]="[method]"
vueOn: /(@|v-on:)\w+="([0-z.?]+)\(?\)?"/,
};
// replace v-on:[event]=[method] to selectionable attributes
function replaceAttributes(el) {
el.innerHTML = el.innerHTML.replace(
new RegExp(regex.vueOn, "g"),
(match) => {
// get event and method as [event]=[method]
// from @[event]=[method] or v-on:[event]=[method]
const attr = /@/.test(match) ? match.slice(1) : match.split(":")[1];
// get event and method without quotes
const [ event, method ] = attr.replace(/"/g, "").split("=");
return `vue-event=${event} vue-event-method=${method}`;
}
);
return el;
}
After that we need a function that read all element with the vue-event
attribute, add the event listener and remove all those attributes.
function addEvents(vue) {
vue.$el.querySelectorAll("[vue-event]").forEach((el) => {
const event = el.getAttribute("vue-event");
const method = el.getAttribute("vue-event-method");
el.addEventListener(event, vue[method].bind(vue.$data));
clearElement(el, ["vue-event", "vue-event-method"])
});
}
function clearElement(el, attributes) {
attributes.forEach(attr => el.removeAttribute(attr));
}
And finally, we need to use those functions on our render function.
const regex = {
mostach: /\{\{((?:.|\r?\n)+?)\}\}/,
};
function renderVue(vue) {
const originalTemplate = replaceAttributes(vue.$el.cloneNode(true));
return () => {
const { $data } = vue;
vue.$el.innerHTML = originalTemplate.innerHTML.replace(
new RegExp(regex.mostach, "g"),
(_, val) => $data[val.trim()]
);
addEvents(vue);
};
}
Example of the rendering:
<!-- Original -->
<button v-on:click="foo">I'm a button<button>
<!-- After replaceAttributes -->
<button vue-event="click" vue-event-method="foo">I'm a button<button>
<!-- After rendering -->
<button>I'm a button<button>
Conclusion
And we are finally done, adding methods to vue is really easy but code the vue events can be a headache.
You can see more about code your own vue here
Top comments (1)
If you have readed the last two post about this series, just let you know that I did a little update to both post, mostly code.