Build a Vue.js 1.x Single Page Application from Scratch – Step‑by‑Step Guide

This tutorial walks you through the reasons for using SPA, why Vue.js is a lightweight alternative to React, how to set up the Node environment, configure Webpack, create components, manage routing, handle component lifecycles, and implement nested routes with practical code examples.

Tencent TDS Service
Tencent TDS Service
Tencent TDS Service
Build a Vue.js 1.x Single Page Application from Scratch – Step‑by‑Step Guide

In recent years the front‑end ecosystem has shifted rapidly from MVC to MVVM, with frameworks such as Backbone and AngularJS fading while React and the lighter Vue are thriving; this guide demonstrates an initial experience with Vue 1.0.

1. Why SPA?

SPA (Single Page Application) eliminates page reloads, avoiding white‑screen blocking and greatly improving performance for hybrid H5 apps, delivering a near‑native fluid experience.

2. Why Choose Vue?

Compared with a React demo, Vue is far lighter; its view layer works directly on the DOM and custom Vue directives act as custom tags, resulting in lower learning cost.

3. Environment Setup

Initialize the project with Node and npm, then run the following commands:

// Initialize package.json
npm init

// Install Vue and its router
npm install vue --save
npm install vue-router --save

// Install Webpack development dependencies
npm install webpack --save-dev

// Install Babel ES6 loader dependencies
npm install babel --save-dev
npm install babel-core --save-dev
npm install babel-loader --save-dev
npm install babel-preset-es2015 --save-dev

// Install HTML loader
npm install html-loader --save-dev

4. Directory Structure

src – development folder (components and templates sub‑folders)

dist – built output folder

index.html – entry file

package.json – project description generated by npm init webpack.config.js – Webpack configuration file

5. Webpack Configuration

var webpack = require("webpack");

module.exports = {
    entry: {
        bundle: ["./src/app.js"]
    },
    output: {
        path: __dirname,
        publicPath: "/",
        filename: "dist/[name].js"
    },
    module: {
        loaders: [
            {test: /\.html$/, loaders: ['html']},
            {test: /(\.js)$/, loader: ["babel"], exclude: /node_modules/,
                query: {presets: ["es2015"]}}
        ]
    },
    plugins: []
};

6. Entry File

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vue Router Demo</title>
</head>
<body>
    <div id="app">
        <router-view></router-view>
    </div>
    <script src="dist/bundle.js"></script>
</body>
</html>

The div#app serves as the container; router-view is rendered by vue‑router.

7. First Component

// components/index.js
module.exports = {
    template: require('../templates/index'),
    ready: function () {}
};
<h1>Index</h1>
<hr/>
<p>Hello World Index!</p>

8. Component Navigation

Update the index component to use v-link for navigation:

<h1>Index</h1>
<hr/>
<p>Hello World Index!</p>
<p><a v-link="{path:'/list'}">List Page</a></p>

List component:

// components/list.js
module.exports = {
    template: require('../templates/list'),
    data: function(){
        return {items:[{"id":1,"name":"hello11"},{"id":2,"name":"hello22"}]};
    },
    ready: function () {}
};
<h1>List</h1>
<hr/>
<p>Hello List Page!</p>
<ul>
    <li v-for="(index,item) in items">${item.id} : ${item.name}</li>
</ul>

Running webpack --watch automatically rebuilds the bundle on file changes.

9. Component Lifecycle

// components/list.js (with lifecycle hooks)
module.exports = {
    template: require('../templates/list'),
    data: function(){
        return {items:[{"id":1,"name":"hello11"},{"id":2,"name":"hello22"}]};
    },
    init: function(){ console.log("init.."); },
    created: function(){ console.log("created.."); },
    beforeCompile: function(){ console.log("beforeCompile.."); },
    compiled: function(){ console.log("compiled.."); },
    ready: function(){ console.log("ready.."); },
    attached: function(){ console.log("attached.."); },
    detached: function(){ console.log("detached.."); },
    beforeDestroy: function(){ console.log("beforeDestroy.."); },
    destroyed: function(){ console.log("destroyed.."); }
};

Browser console shows the execution order when entering and leaving the List page.

10. Parent‑Child Components

// components/item.js
module.exports = {
    template: require('../templates/item'),
    props: ["id","name"],
    ready: function () {}
};
<p>I am subitem: ${id} - ${name}</p>

Update list.js to register the child component and use it:

// components/list.js
import item from "./item";
module.exports = {
    template: require('../templates/list'),
    data: function(){
        return {items:[{"id":1,"name":"hello11"},{"id":2,"name":"hello22"}]};
    },
    components: {"item": item},
    ready: function () {}
};
<ul>
    <li v-for="(index,item) in items">
        <!-- use item component and pass props -->
        <item v-bind:id="item.id" v-bind:name="item.name"></item>
    </li>
</ul>

11. Navigation with Parameters

// routes.js (add show route)
module.exports = {
    '/': {component: require('./components/index')},
    '/list': {component: require('./components/list')},
    '/show/:id': {name: "show", component: require('./components/show')},
    '*': {component: require('./components/notFound')}
};
// components/show.js
module.exports = {
    template: require('../templates/show'),
    data: function(){return {};},
    created: function(){
        var id = this.$route.params.id;
        if (id == 1){ this.$data = {id:id, name:"hello111", age:24}; }
        else { this.$data = {id:id, name:"hello222", age:28}; }
    },
    ready: function(){ console.log(this.$data); }
};
<h1>Show</h1>
<hr/>
<p>Hello show page!</p>
<p>id:${id}</p>
<p>name:${name}</p>
<p>age:${age}</p>

Modify templates/item.html to link to the detail page:

<p>I am subitem: <a v-link="{name:'show',params:{'id':id}}">${id} : ${name}</a> </p>

12. Nested Routes

// components/tab1.js
module.exports = {template: "<p>Tab1 content</p>"};
// components/tab2.js
module.exports = {template: "<p>Tab2 content</p>"};
// components/index.js (register tabs)
import tab1 from "./tab1";
import tab2 from "./tab2";
module.exports = {
    template: require('../templates/index'),
    components: {"tab1": tab1, "tab2": tab2},
    ready: function () {}
};
// routes.js (nested routes with default)
module.exports = {
    '/': {
        component: require('./components/index'),
        subRoutes: {
            '/': {component: require('./components/tab1')},
            '/tab1': {component: require('./components/tab1')},
            '/tab2': {component: require('./components/tab2')}
        }
    },
    '/list': {component: require('./components/list')},
    '/show/:id': {name: "show", component: require('./components/show')},
    '*': {component: require('./components/notFound')}
};

13. Real‑World Vue Usage

Examples of Vue in production include the Xiaomi Mobile website (http://m.mi.com/1/#/index) and Ele.me’s mobile recruitment site (https://jobs-mobile.ele.me/#!/).

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaScriptWebpackroutingSPAVue.js
Tencent TDS Service
Written by

Tencent TDS Service

TDS Service offers client and web front‑end developers and operators an intelligent low‑code platform, cross‑platform development framework, universal release platform, runtime container engine, monitoring and analysis platform, and a security‑privacy compliance suite.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.