Vidya Ramakrishnan
Front-end developer at HasGeek
vidya-ram vidya_ramki
Text
<!DOCTYPE html>
<html>
<head>
<title>Vue.js</title>
</head>
<body>
<div id="app">
<p>Hello everyone! Welcome to {{message}}</p>
</div>
<script src="https://unpkg.com/vue@2.5.13/dist/vue.js"></script>
<script>
new Vue({
el: '#app',
data: {
message: 'Girls who JavaScript - Meetup 6',
}
});
</script>
</body>
</html>
Vue.js is a progressive framework
It is easy to plug it into the part where you would like to have a more richer user interaction
since it's core library is focused on the view layer
<template>
<div class="main">
<p class="text">Computed Properties</p>
<textarea v-model="message" class="message"></textarea>
<p>Message: "{{ message }}"</p>
<p>String length: {{ messageLen }}</p>
</div>
</template>
<script>
export default {
name: 'ComputedProperties',
data () {
return {
message: ''
}
},
computed: {
// messageLen is a computed property
messageLen () {
if (this.message) {
return this.message.length
}
}
}
}
</script>
Vue CLI
A simple CLI for scaffolding vue.js spa projects
$ npm install -g vue-cli $ vue init webpack my-project $ cd my-project $ npm install $ npm run dev
For a PWA template with webpack, run
$ vue init pwa my-project
import Vue from 'vue';
import App from './App';
import router from './router';
new Vue({
el: '#app',
router,
template: '<App/>',
components: { App },
});
main.js
<template>
<div id="app">
<transition name="fade">
<router-view/></router-view>
</transition>
</div>
</template>
<script>
export default {
name: 'app',
};
</script>
<style>
.fade-enter-active, .fade-leave-active {
transition: opacity .5s
}
.fade-enter, .fade-leave-to {
opacity: 0
}
</style>
App.vue
Text
import Vue from 'vue';
import Router from 'vue-router';
import Home from '@/components/Home'
import Channel from '@/components/Channel'
import EditChannel from '@/components/EditChannel'
Vue.use(Router);
export default new Router({
mode: 'history',
routes: [
{
path: '/',
name: 'Home',
component: Home,
},
{
path: '/:channel',
name: 'Channel',
component: Channel,
},
{
path: '/:channel/edit',
name: 'EditChannel',
component: EditChannel,
}
],
});
router.js
Text
import Vue from 'vue';
import Router from 'vue-router';
const Home = () => import('@/components/Home');
const Channel = () => import('@/components/Channel');
Vue.use(Router);
export default new Router({
mode: 'history',
routes: [
{
path: '/',
name: 'Home',
component: Home,
},
{
path: '/:channel',
name: 'Channel',
component: Channel,
}
],
});
router.js
Code splitting with async component and
webpack dynamic module loading
Text
<template>
<div>
<p class="site-title">{{ message }}</p>
</div>
</div>
</template>
<script>
export default {
name: 'Home',
data() {
return {
message: "Welcome to HasGeek TV. Watch talks and discussions from past events here."
};
},
};
</script>
<style scoped>
.site-title {
font-size: 25px;
text-align: center;
}
</style>
Single file component
vue-loader
Template
Script (ES5/ES6)
Style
Text
vue-template-compiler
babel
pre-processors + post css
Render functions
ES5 JavaScript
CSS files
Text
Vue's parsing & compilation phases of single file component
with webpack plugins and loaders
webpack plugin
webpack loader
webpack loader
webpack loader
Text
"A lightweight JavaScript data structure to represent what the DOM should look like at a given point of time" - Evan You
In simple terms, Virtual Dom is a JavaScript object that represents the Document Object Model(DOM)
This function returns a virtual dom.
In Vue CLI, vue-template-compiler complies Vue templates into render function
Text
The lifecycle hooks provide you a method with which you can trigger some functionality at different moments of a component's lifecycle.
beforeCreate, created, beforeMount, mounted, beforeUpdate, updated, activated, deactivated, beforeDestroy, and destroyed.
Text
Text
Image source: https://vuejs.org/v2/guide/reactivity.html
HasGeek TV app has many admin pages with forms. Our python flask backend has the capability to generate HTML forms and render them. General format that we follow when we require form for an application is as simple as defining the forms fields and backend takes care of providing the form HTML along with the required JavaScript.
First we tried creating a form component with it's template as the form html received from the backend. In case of Vue Cli, the templates are precompiled and cannot be changed later. Hence this was not an option
Then we tried using Vue's async component feature which lets you load the component only when required but the issue is async components are cached after the first load which was an issue for us, since for edit forms the fields are prefilled which requires it to be fe
tched fresh for each page load. Finally Vue’s dynamic component and computed properties helped us reload the form component every time there was a change in it's template . This let us reuse the backend generated form (html and associated JS library) and saved us from writing the HTML all over again.
<template>
<div>
<Form v-if="showForm"></Form>
</div>
</template>
<script>
import axios from 'axios';
import Utils from '../assets/js/utils';
let vm = {};
export default {
name: 'EditChannel',
data() {
return {
showForm: false,
errors: [],
};
},
components: {
Form: (resolve) => {
resolve({
template: vm.formTemplate,
});
},
},
Async form component
created() {
vm = this;
axios.get(this.path)
.then((response) => {
this.formTemplate =
Utils.getVueFormTemplate(
response.data.form);
this.showForm = true;
})
.catch((e) => {
vm.errors.push(e);
});
},
};
</script>
<template>
<div>
<component :is="Form"></component>
</div>
</template>
<script>
import axios from 'axios';
import Utils from '../assets/js/utils';
let vm = {};
export default {
name: 'AddChannel',
data() {
return {
path: this.$route.path,
formTemplate: '',
formId: '',
};
},
computed: {
Form() {
const template = this.formTemplate ?
this.formTemplate :
'<p>Loading..</p>';
return {
template,
methods: {
onFormSubmit() {
Utils.formSubmit(vm.formId);
},
},
};
},
},
Dynamic component &
Computed properties
created() {
vm = this;
axios.get(this.path)
.then((response) => {
this.formTemplate =
Utils.getVueFormTemplate(
response.data.form);
this.formId =
Utils.getElementId(
this.formTemplate);
})
.catch((error) => {
this.error = error;
});
},
};
</script>