preface

We will choose to use some libraries around VUE, vuE-CLI, vue-Router, VUE-Resource,vuex

Use vue-CLI to create a project. 2. Use vue-router to implement single-page routing 3. Manage our data flow with VUex 4. Request our Node server with vuE-resource 5. PS: Node v6.2.2 NPM v3.9.5 vue v2.1.0 vue-Router v2.0.3 vuex v2.0.0

Eventually we’ll build a little demo, so without further ado, we’ll go straight to the diagram above.

The installation

1. We will use Webpack to package, preprocess and hot load our modules. If you’re not familiar with Webpack, it helps us pack multiple JS files into a single entry file and load them on demand. This means that we don’t have to worry about too many HTTP requests due to using too many components, which is very beneficial to the product experience. But we don’t just use Webpack for this, we need to use Webpack to compile.vue files, and if we don’t use a loader to convert the style, JS and HTML in our.vue files, the browser won’t recognize it.

2. Module hot loading is a great feature of WebPack that will make our single page applications a lot easier. In general, when we change the code to refresh the page, all the state in the application is gone. This can be very painful to develop a single page application because you have to run the process all over again. If you have module hot loading, when you modify the code, your code will be modified directly, the page will not refresh, so the state will be preserved.

3.Vue also provides CSS preprocessing, so we can choose to write LESS or SASS in the.vue file instead of native CSS.

4. We used to download a bunch of dependencies using NPM, but now we can choose vue-CLI. This is a great initiative in a VUE ecosystem. This means we don’t have to build our project manually, and it can be generated for us very quickly.

First, install vuE-CLI. (Make sure you have Node and NPM)

npm i -g vue-cli

Then create a Webpack project and download the dependencies

vue init webpack vue-tutorial

cd vue-tutorial

npm i

We then run our application in hot load using NPM run dev

This line of command means it will go to the scripts object of package.json and execute Node bulid /dev/server.js. In this file, Webpack is configured to compile the project file and run the server to view our application at localhost:8080.

With all this in place, we need to download three libraries for our routing, XHR requests, and data management, which we can find on vue’s official website. In addition, we used Bootstrap as my UI library

npm i vue-resource vue-router vuex bootstrap --save

Initialize (main.js)

Looking at our application files, we can find app.vue and main.js in the SRC directory. Main.js will be the entry file for our App and app.vue will be the initialization component for our App. Let’s start by refining main.js

// src/main.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import VueResource from 'vue-resource'

import App from './App'
import Home from './components/Home'
import 'bootstrap/dist/css/bootstrap.css'

Vue.use(VueRouter)
Vue.use(VueResource)

const routes = [{
  path : '/'.component : Home
},{
  path : '/home'.component : Home
}];

const router = new VueRouter({
  routes
});

/* eslint-disable no-new */
// instantiate our Vue
var app = new Vue({
  el: '#app', router, ... App, });Copy the code

There are two differences from 1.0

The parameters of vue-router route are changed from objects to arrays. In addition, the el parameter to instantiate vue can no longer set HTML and body because vue2 replaces the tag we specified

Second, we must specify what components to render when instantiating vue. We used to specify router. Start (App, ‘# App ‘) via routing, but in vue2 we don’t need to do that

You can see that we use two components app.vue and home.vue in main.js. Let’s implement them later.

Our index. HTML just needs to keep

. Our Vue instantiates el: ‘#app’ so it replaces this tag with the content of our app component

//index.html
<div id="app"></div>Copy the code

That’s where our initialization ends, and let’s start creating the component.

Create the Home Page component

First we write a top navigation for our App in app.vue.

// src/App.vue

<template>
  <div id="wrapper">
    <nav class="navbar navbar-default">
      <div class="container">
        <a class="navbar-brand" href="#">
          <i class="glyphicon glyphicon-time"></i>Planning board</a>
        <ul class="nav navbar-nav">
          <li><router-link to="/home">Home page</router-link></li>
          <li><router-link to="/time-entries">Plans to list</router-link></li>
        </ul>
      </div>
    </nav>
    <div class="container">
      <div class="col-sm-3">

      </div>
      <div class="col-sm-9">
        <router-view></router-view>
      </div>
    </div>
  </div>
</template>Copy the code

In addition to our Navbar, we also need a. Container for the rest of the information we need to display. And here we put a router-view tag, which is where the vue-Router switch starts.

There’s a difference here from 1.0

In the past, we can directly redirect routes by writing the A tag and then the V-link attribute. In VUe2, it is changed to write the

tag and then the corresponding attribute (TO) to redirect routes

Next, we need to create a home.vue as our Home page

// src/components/Home.vue

<template>
  <div class="jumbotron">
    <h1>Task tracking</h1>
    <p>
      <strong>
        <router-link to="/time-entries">Creating a Task</router-link>
      </strong>
    </p>
  </div>
</template>Copy the code

If not, you can see the following effect

Create the sidebar component

We currently have a space to the left of our home page that we need to put down a sidebar to count the total time of all projects.

// src/App.vue

  //...

  <div class="container">
    <div class="col-sm-3">
      <sidebar></sidebar>
    </div>
    <div class="col-sm-9">
      <router-view></router-view>
    </div>
  </div>/ /...Copy the code
<script>
  import Sidebar from './components/Sidebar.vue'

  export default {
    components: { 'sidebar': Sidebar },
  }
</script>Copy the code

In Sidebar. Vue, we need to obtain the total time through store, and our total time is shared data

// src/components/Sidebar.vue <template> <div class="panel panel-default"> <div class="panel-heading"> <h1 Class = "text - center" > has long < / h1 > < / div > < div class = "panel - body" > < h1 class = "text - center" > {{time}} hours < / h1 > < / div > < / div > </template> <script> export default { computed: { time() { return this.$store.state.totalTime } } } </script>Copy the code

Create the plan list component

Then we need to create our time tracking list.


// src/components/TimeEntries.vue

<template>
  <div>// '$route.path' is the path of the current routing object, which will be resolved to an absolute path when // '$route.path! == '/time-entries/log-time' 'true' indicates display, 'false' indicates no display. //to Indicates the forward address of the route<router-link
      v-if="$route.path ! == '/time-entries/log-time'"
      to="/time-entries/log-time"
      class="btn btn-primary">create</router-link>

    <div v-if="$route.path === '/time-entries/log-time'">
      <h3>create</h3>
    </div>

    <hr>

    <router-view></router-view>

    <div class="time-entries">
      <p v-if=! "" plans.length"><strong>Nothing is planned yet</strong></p>

      <div class="list-group">
      <--
        v-forLoop, note that the order of parameters is (item.index) in items
      -->
        <a class="list-group-item" v-for="(plan,index) in plans">
          <div class="row">
            <div class="col-sm-2 user-details">

            <--
            `:src'Property, this isvueProperty binding short for 'v-bind'can be shortened to':` such asaThe label `href'can be written as':href` and invueDo not write interpolation expressions (':src={{xx}}`),vueI'll do it myself-->

              <img :src="plan.avatar" class="avatar img-circle img-responsive" />
              <p class="text-center">
                <strong>
                  {{ plan.name }}
                </strong>
              </p>
            </div>

            <div class="col-sm-2 text-center time-block">
              <h3 class="list-group-item-text total-time">
                <i class="glyphicon glyphicon-time"></i>
                {{ plan.totalTime }}
              </h3>
              <p class="label label-primary text-center">
                <i class="glyphicon glyphicon-calendar"></i>
                {{ plan.date }}
              </p>
            </div>

            <div class="col-sm-7 comment-section">
              <p>{{ plan.comment }}</p>
            </div>

            <div class="col-sm-1">
              <button
                class="btn btn-xs btn-danger delete-button"
                @click="deletePlan(index)">
              X
              </button>
            </div>

          </div>
        </a>

      </div>
    </div>
  </div>
</template>Copy the code

The explanation of template, it’s all in one place, so let’s look at our script

// src/components/TimeEntries.vue

<script>
    export default {
        name : 'TimeEntries'.computed : {
          plans () {
            // Retrieve data from store
            return this.$store.state.list
          }
        },
        methods : {
          deletePlan(idx) {
            // More on the method here later
            // Subtract the total time
            this.$store.dispatch('decTotalTime'.this.plans[idx].totalTime)
            // Delete the plan
            this.$store.dispatch('deletePlan',idx)
          }
        }
    }
</script>Copy the code

Don’t forget to write some desired styles for our component

// src/components/TimeEntries.vue

<style>
  .avatar {
    height: 75px;
    margin: 0 auto;
    margin-top: 10px;
    margin-bottom: 10px;
  }
  .user-details {
    background-color: #f5f5f5;
    border-right: 1px solid #ddd;
    margin: -10px 0;
  }
  .time-block {
    padding: 10px;
  }
  .comment-section {
    padding: 20px;
  }
</style>Copy the code

Since our data is shared, we need to store our data in the Store

We create a directory called store under SRC

Under the store respectively create four js file actions. Js, index. Js, mutation – types. Js, mutations. Js

From the name, you can know what these four are for. I suggest you read more vuex documents and practice with multiple poses and hands. Slowly, you will understand.

// src/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex);

// Write false data first
const state = {
  totalTime: 0.list: [{
    name : 'two zhe'.avatar : 'https://sfault-avatar.b0.upaiyun.com/147/223/147223148-573297d0913c5_huge256'.date : '2016-12-25'.totalTime : '6'.comment : 'On the night of December 25th, it takes six hours to spend Christmas with your girlfriend'}};export default new Vuex.Store({
  state,
})Copy the code

Because of the new page and store configuration in our entry js file

// src/main.js
import store from './store'
import TimeEntries from './components/TimeEntries.vue'
/ /...

const routes = [{
  path : '/'.component : Home
},{
  path : '/home'.component : Home
},{
  path : '/time-entries'.component : TimeEntries,
}];

var app = new Vue({
  el: '#app', router, store, ... App, });Copy the code

Unsurprisingly, you can see this page under the /time-entries route

With vue-devTools we can see that our store has been constructed and successfully retrieved from the store

Creating a Task component

This is a little bit easier and we’ll just give you the code

// src/components/LogTime.vue

<template>
  <div class="form-horizontal">
    <div class="form-group">
      <div class="col-sm-6">
        <label>The date of</label>
        <input
          type="date"
          class="form-control"
          v-model="date"
          placeholder="Date"
        />
      </div>
      <div class="col-sm-6">
        <label>time</label>
        <input
          type="number"
          class="form-control"
          v-model="totalTime"
          placeholder="Hours"
        />
      </div>
    </div>
    <div class="form-group">
      <div class="col-sm-12">
        <label>note</label>
        <input
          type="text"
          class="form-control"
          v-model="comment"
          placeholder="Comment"
        />
      </div>
    </div>
    <button class="btn btn-primary" @click="save()">save</button>
    <router-link to="/time-entries" class="btn btn-danger">cancel</router-link>
    <hr>
  </div>
</template>

<script>
  export default {
        name : 'LogTime',
        data() {
            return {
                date : ' '.totalTime : ' '.comment : ' '}},methods:{
          save() {
            const plan = {
              name : 'two zhe'.image : 'https://sfault-avatar.b0.upaiyun.com/888/223/888223038-5646dbc28d530_huge256'.date : this.date,
              totalTime : this.totalTime,
              comment : this.comment
            };
            this.$store.dispatch('savePlan', plan)
            this.$store.dispatch('addTotalTime'.this.totalTime)
            this.$router.go(- 1)}}}</script>Copy the code

This component is pretty simple just three inputs, and then two buttons, save and we push the data into our store list

LogTime is a subroute of our TimeEntries component, so we still need to configure our route and use Webpack to make it lazy to load, so as to reduce the traffic of our first screen loading

// src/main.js
/ /...
const routes = [{
  path : '/'.component : Home
},{
  path : '/home'.component : Home
},{
  path : '/time-entries'.component : TimeEntries,
  children : [{
    path : 'log-time'./ / lazy loading
    component : resolve= > require(['./components/LogTime.vue'],resolve),
  }]
}];

/ /...Copy the code

Vuex part

In Vue2.0, the use of events for communication is abolished, so we can use Event Bus for small projects, and it is better to use Vuex for the rest. In this article, we use Vuex for data communication

This.$store. Dispatch (‘savePlan’, plan).

If you think about it, we need two global data points, one for the total time of all schedules, and one for an array of schedule lists.

SRC /store/index.js doesn’t have much to say, it’s just passing in our state,mutations,actions to initialize our store. We might also want to create our getter if we need to but we won’t in this case.

Mutation -types. Js = mutation-types. Js = mutation-types

// src/store/mutation-types.js

// Increase total time or decrease total time
export const ADD_TOTAL_TIME = 'ADD_TOTAL_TIME';
export const DEC_TOTAL_TIME = 'DEC_TOTAL_TIME';

// Add and delete a schedule
export const SAVE_PLAN = 'SAVE_PLAN';
export const DELETE_PLAN = 'DELETE_PLAN';Copy the code
// src/store/mutations.js
import * as types from './mutation-types'

export default {
    // Increase the total time
  [types.ADD_TOTAL_TIME] (state, time) {
    state.totalTime = state.totalTime + time
  },
  // Reduce the total time
  [types.DEC_TOTAL_TIME] (state, time) {
    state.totalTime = state.totalTime - time
  },
  // Add a new plan
  [types.SAVE_PLAN] (state, plan) {
    // Set the default value, in the future we can do login directly read the nickname and avatar
    const avatar = 'https://sfault-avatar.b0.upaiyun.com/147/223/147223148-573297d0913c5_huge256';

    state.list.push(
      Object.assign({ name: 'two zhe'.avatar: avatar }, plan)
    )
  },
  // Delete a plan
  [types.DELETE_PLAN] (state, idx) {
    state.list.splice(idx, 1); }};Copy the code

Finally, look at our actions

// src/store/actions.js

import * as types from './mutation-types'

export default {
  addTotalTime({ commit }, time) {
    commit(types.ADD_TOTAL_TIME, time)
  },
  decTotalTime({ commit }, time) {
    commit(types.DEC_TOTAL_TIME, time)
  },
  savePlan({ commit }, plan) {
    commit(types.SAVE_PLAN, plan);
  },
  deletePlan({ commit }, plan) {
    commit(types.DELETE_PLAN, plan)
  }
};Copy the code

Our Actions are just for triggering events and passing in parameters

After adding these three files, our store is finally complete. Let’s update our code

// SRC /store/index.js

import Vue from 'vue'
import Vuex from 'vuex'
import mutations from './mutations'
import actions from './actions'

Vue.use(Vuex);

const state = {
  totalTime: 0.list: []};export default new Vuex.Store({
  state,
  mutations,
  actions
})Copy the code

This.$store.dispatch(‘savePlan’, plan) calls savePlan in actions.js, SavePlan triggers the types.SAVE_PLAN on mutations and finally changes the data view

PS: One trick here is that in mutations, we connect them with uppercase underscores, but in actions, we use lowercase humps.

Personally, I understand that this is a publish-subscribe model

Mutation -types records all of our event names

Mutations register our methods for all kinds of data changes

Actions can write asynchronous logic or some logic to commit our events

If we have a getter we can just put some of the data that we need to process and return in there and not do any business

Finally, don’t forget to use our store in our main.js

// src/store/main.js

import store from './store'
// ...

var app = new Vue({
  el: '#app', router, store, ... App, });Copy the code

Start experimenting with your own mission planner!

The last

In this article, you can learn a lot about vUE’s features.

1. Understand vuE-CLI scaffolding

2. I have a preliminary understanding of Webpack

3. How to use. Vue to develop happily

4. Use VUEX for component communication

5. Application of routing (subrouting)

6. Use vue-devTools to observe our data


Personal website: www.meckodo.com

Github address: github.com/MeCKodo/vue…

Have a nice day