I’ve been impressed with the mark that Vue.js has been making lately. Having used it in the past and wanting to use it again, I got curious about what it looks like working with Vue in Dart.
Having demonstrated that it’s possible to use JavaScript libraries in Dart web apps, we will go through the Vue.js “Getting started” page and rewrite the examples in Dart, using the js
interop package.
Before we begin:
1. Set up your project
Set-up your web project quickly with Stagehand:
mkdir vue_dart && cd vue_dart stagehand web-simple
2. Install the js interop package
Ensure that the js
dependency is added to your pubspec.yaml
file:
dependencies: js: ^0.6.1+1
Save and run pub get
to update your dependencies.
3. Import the Vue.js library
In web/index.html
in the <head>
before <script defer src="main.dart.js"></script>
import the dev version of the library:
<!-- development version, includes helpful console warnings --> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
Now we can go through the examples!
Getting started
Create a web/app.dart
file with our library declaration and imports:
@JS() library vue_interop; import 'package:js/js.dart'; // TODO: The rest of the code to go here
Declarative rendering
Here’s the first example of a template with the message
property placeholder:
<div id="app"> {{ message }} </div>
Create an annotated factory constructor for Vue
:
@JS() class Vue { external factory Vue(VueOptions options); }
The JavaScript api takes an object literal when a new Vue
instance is declared. Notice the declaration of the VueOptions
type instead of Map
? We cannot use Dart Map
s here since they are opaque in JavaScript.
Therefore, we need to create a factory constructor to house our options:
@JS() @anonymous class VueOptions { external factory VueOptions({ String el, VueDataOptions data }); external String get el; external VueDataOptions get data; }
And the data prop is a VueDataOptions
object:
@JS() @anonymous class VueDataOptions { external factory VueDataOptions({ String message = '', // Set to empty string as default }); external String get message; }
Return to web/main.dart
and lets use these factories:
// Relative imports import './app.dart'; void main() { Vue(VueOptions( el: '#app', data: VueDataOptions( message: 'Hello Vue!', ), )); }
You should now see the text “Hello Vue!” on the screen:
In addition to string interpolation we can also bind element attributes.
<div id="app-2"> <span v-bind:title="message"> Hover your mouse over me for a few seconds to see my dynamically bound title! </span> </div>
No changes needed on our factory, just declare a call:
// web/main.dart ... void main() { ... // App 2 example Vue(VueOptions( el: '#app-2', data: VueDataOptions( message: 'You loaded this page on ${DateTime(2018).toLocal()}', ), )); }
Conditionals
Use the v-if
attribute to toggle the presence of an element:
<div id="app-3"> <span v-if="seen">Now you see me</span> </div>
Since we are watching a new property (seen
), let’s add a getter for this in our factory:
@JS() @anonymous class VueDataOptions { external factory VueDataOptions({ String message = '', bool seen = null, // <-- Added this }); external String get message; external bool get seen; // <-- Added this }
And in web/main.dart
:
... void main() { ... // App 3 example var app3 = Vue(VueOptions( el: '#app-3', data: VueDataOptions(seen: true), )); }
In the snippet above we have assigned the result of calling Vue()
to an app3
variable. The docs demonstrate doing app3.seen = false
, which means we have to add a getter of type boolean to Vue
class in web/app.dart
:
@JS() class Vue { external factory Vue(VueOptions options); external void set seen(bool val); // <-- Added this }
And in web/main.dart
, we will do:
import 'dart:async'; // <-- Added this line to use `Future.delayed` // Relative imports import './todo.dart'; // <-- Added this line import './app.dart'; void main() { ... ... // App 3 example var app3 = Vue(VueOptions( el: '#app-3', data: VueDataOptions(seen: true), )); // Added a delay to see disappearing text Future.delayed(Duration(seconds: 2), () async { app3.seen = false; // Added a delay and then restored text visibility await Future.delayed(Duration(seconds: 2)); app3.seen = true; }); }
Loops
The v:for
attribute is used when iterating over arrays:
<div id="app-4"> <ol> <li v-for="todo in todos"> {{ todo.text }} </li> </ol> </div>
This introduces a new factory constructor, which we’ll call Todo
.
Create web/todo.dart
with our factory class:
@JS() library todo; import 'package:js/js.dart'; @JS() @anonymous class Todo { external factory Todo({String text}); external String get text; }
And in web/app.dart
, let’s define a list of Todo
s:
@JS() class Vue { external factory Vue(VueOptions options); external void set seen(bool val); external List<Todo> get todos; // <-- Added this line } ... @JS() @anonymous class VueDataOptions { external factory VueDataOptions({ String message = '', bool seen = null, List<Todo> todos = const [], }); external String get message; external bool get seen; external List<Todo> get todos; // <-- Added this line }
And in web/main.dart
we’ll use it:
... ... void main() { ... ... // App 4 example var app4 = Vue(VueOptions( el: '#app-4', data: VueDataOptions(todos: [ Todo(text: 'Learn Dart'), Todo(text: 'Learn Aqueduct'), Todo(text: 'Build something awesome!'), ]), )); }
In order to add a new item to the todos list like the docs show:
app4.todos.push({ text: 'New item' });
We’ll need to add a getter for todos
on Vue
:
// web/app.dart ... ... @JS() class Vue { external factory Vue(VueOptions options); external void set seen(bool val); external List<Todo> get todos; // <-- Added this line }
And in web/main.dart
:
... ... // App 4 example var app4 = Vue(VueOptions( el: '#app-4', data: VueDataOptions(todos: [ Todo(text: 'Learn Dart'), Todo(text: 'Learn Aqueduct'), Todo(text: 'Build something awesome!'), ]), )); app4.todos.add(Todo(text: 'New item')); // <-- Added this line
Conclusion
And this brings us to the end of Part 1. In part 2, we will look at handling user input and composition with Vue components.
Continue reading
Further reading
- js package
- How to Use JavaScript libraries in your Dart applications
- Full-stack web development with Dart
Sharing is caring 
If you enjoyed reading this post, please share this through the various social buttons hovering on the left/top side of the screen . Also, check out and subscribe to my YouTube channel (hit the bell icon too) for videos on Dart.
Subscribe to the newsletter for my free 35-page Get started with Dart eBook and to be notified when new content is released.
Like, share and follow me for more content on Dart.