Vue.js is an easy to use web app framework that we can use to develop interactive front end apps.
In this article, we’ll look at using CSS frameworks to save us time from styling everything manually and watching nested data.
Use an Off the Shelf CSS Framework
Off the shelf CSS framework saves us time from styling things that we’ve to style manually otherwise. There’re many frameworks to choose from, including Tailwind CSS, Foundation, Bulma, and Bootstrap.
They come with classes and JavaScript code to style static components like inputs and tables and also create dynamic components like modals and popups.
Some of them have their own Vue components built for it. For instance, Buefy is a library that’s based on Bulma. BootstrapVue is a component library that’s based on Bootstrap.
If there’s a Vue component library made for it then, then we should use it since they integrate much better with other Vue components in our app. They take props and emits events like any other Vue components.
For instance, we can use Buefy to take advantage of the Bulma framework without making our own styled-components based on Bulma as follows:
index.js
:
new Vue({
el: "#app",
data: {
name: ""
}
});
index.html
:
<!DOCTYPE html>
<html lang="en">
<head>
<title>App</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://unpkg.com/buefy/dist/buefy.min.js"></script>
<link rel="stylesheet" href="https://unpkg.com/buefy/dist/buefy.min.css" />
</head>
<body>
<div id="app">
<b-field label="Name" type="is-danger" message="Name">
<b-input type="name" v-model="name" maxlength="30"> </b-input>
</b-field>
<p>{{name}}</p>
</div>
<script src="index.js"></script>
</body>
</html>
In the code above, we have the b-field
component from Buefy, which is an input form field component. Then we have our b-input
component, which is the actual input component.
The label is rendered by the b-field
component so that we can see the label. In addition, there’s styling with the type
prop and the message
prop provides a message that’s displayed.
The input has input validation and binds to a variable of our choice with v-model
.
We did all that by just using the library and referencing the provided component, so it’s the best choice for quickly using styled-components.
Watching Nested Data in Vue
We can watch data with by adding a function to the watch
object in our component options.
It’s useful for watching for updates in nested objects and arrays. In these cases, Vue has no idea what’s changed unless we explicitly add watcher and set it to watch for the structural changes of the object. This is because Vue sees that the reference to the object hasn’t changed.
For instance, we can use watchers to watch for changes to an array as follows:
index.js
:
new Vue({
el: "#app",
data: {
nums: [1, 2, 3]
},
methods: {
append() {
this.nums.push(Math.max(...this.nums) + 1);
}
},
watch: {
nums: {
deep: true,
handler() {
console.log("nums changed");
}
}
}
});
index.html
:
<!DOCTYPE html>
<html lang="en">
<head>
<title>App</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<button @click="append">Append</button>
<p v-for="n in nums">{{n}}</p>
</div>
<script src="index.js"></script>
</body>
</html>
In the code above, we have an append
method to push numbers into the nums
array as it’s called. Then we have the watch
object with the nums
object inside to watch for changes in nums
. We set deep
to true
so that it watches for all structural changes. The handler
is then run when it’s changed.
Then when we click the Append button, the handler
function will run.
There’s also an immediate
option so that the watcher is run when the field is initialized. For instance, we can use it as follows:
new Vue({
el: "#app",
data: {
nums: [1, 2, 3]
},
methods: {
append() {
this.nums.push(Math.max(...this.nums) + 1);
}
},
watch: {
nums: {
deep: true,
immediate: true,
handler() {
console.log("nums changed");
}
}
}
});
Then we’ll see nums changed
logged when we first load the app.
If we want to use the same handler function to watch more than one item, we can set it to the function in the methods
object.
For instance, we can write:
index.js
:
new Vue({
el: "#app",
data: {
nums: [1, 2, 3],
nums2: [4, 5, 6]
},
methods: {
append() {
this.nums.push(Math.max(...this.nums) + 1);
},
appendTo2() {
this.nums2.push(Math.max(...this.nums2) + 1);
},
watch() {
console.log("nums changed");
}
},
watch: {
nums: {
deep: true,
immediate: true,
handler: "watch"
},
nums2: {
deep: true,
immediate: true,
handler: "watch"
}
}
});
index.html
:
<!DOCTYPE html>
<html lang="en">
<head>
<title>App</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<button @click="append">Append</button>
<button @click="appendTo2">Append 2</button>
<p v-for="n in nums">{{n}}</p>
<p v-for="n in nums2">{{n}}</p>
</div>
<script src="index.js"></script>
</body>
</html>
In the code above, we have 2 buttons, which append numbers to 2 separate arrays as we click it by running append
or appendTo2
functions respectively.
Then since we set handler
to 'watch'
, the watch
method in methods
is called, so we’ll see that “nums changed”
is logged if we click any of the buttons.
Conclusions
Off the shelf CSS frameworks are great for reducing styling effort needed for us. Some frameworks have component libraries made from it so that we don’t have to spend time styling them ourselves.
We should use watchers for watching values changes deeply nested objects and array. It has options to start watching if the component loads and also has options to watch deeply nested objects, which computed properties can’t do.