VUE 起步

單頁面 SPA 網頁應用的關鍵在於路由, 過去一個個按鈕都會跳轉到一個個獨立的頁面, 由服務器端渲染, 填充相應的數據, 然後展現給用戶。

作爲一個後端工程師, 這是我曾經熟悉的模式, 無論十多年前的 PHP, JSP 還是後來的 SSH 框架, 無不是如此, 前端做的其實很簡單, 不過是一些 HTML 加上簡單的 JavaScript 做輸入校驗。

多年不寫 Web 應用, 近十年來總在後端耕耘, 探出頭來看看世界已經大不同了, 才學了一點 AngularJS, 又聽說 Google 已經不維護這個舊版本了, Angular 2/4 已經出來了, React 也很火, VUE也是近來大出風頭的框架, 我也實在沒有精力跟在後面亦步亦趨, 爲寫點自己的小工具, 決定學學 VUE, 看起來不難, 畢竟也是老程序員了, JavaScript 不會難過 C++, 看了點教程, 做點筆記備忘。

基礎的東西的看官方文檔, 中文翻譯得很好, https://cn.vuejs.org/v2/guide/index.html, 還是母語看起來舒服。

着重看幾個東西:

組件

組件化編程, 類似於模塊化編程, 把web 頁面分解成一個個組件



<div id="app-todo">
  <ol>
    <!--
      現在我們爲每個 todo-item 提供 todo 對象
      todo 對象是變量,即其內容可以是動態的。
      我們也需要爲每個組件提供一個“key”,稍後再
      作詳細解釋。
    -->
    <todo-item
      v-for="item in todoList"
      v-bind:todo="item"
      v-bind:key="item.id">
    </todo-item>
  </ol>
</div>

Vue.component('todo-item', {
  props: ['todo'],
  template: '<li>{{ todo.text }}</li>'
})

var todoApp = new Vue({
  el: '#app-todo',
  data: {
    todoList: [
      { id: 0, text: 'read book' },
      { id: 1, text: 'see movie' },
      { id: 2, text: 'play basketball' }
    ]
  }
})

實例

這個小程序是改自 codepen 網上的一個小例子, 麻雀雖小, 五臟倶全, 頗能說明問題。
一個筆記本的單頁面程序, 對於筆記的 Create-Read-Update-Delete-Search, 增讀改刪查, 最基本的應用

Html 頁面

我在代碼中加了一些註釋,不過是一些模板的堆砌

注意這裏, 與普通的 HTML 代碼不同, 多了幾個不認識的 HTML Tag:

  • main
  • router-view
  • template

template 還好理解, main 和 route-view 是什麼玩意?
這是 VUE 和一些現代 Web 框架的常用做法, 使用了一些自定義標籤來表示應用層實體的意義

<main id="app">
    <router-view></router-view>
 </main>
<html lang="en">
<head>
  <meta charset="utf-8">
  <link rel='stylesheet prefetch' href='./css/bootstrap.min.css'>
  <link rel='stylesheet prefetch' href='./css/bootstrap-theme.min.css'>
  <link rel='stylesheet prefetch' href='./css/note.css'>
</head>
<body>

<!-- Html 中先聲明一個容器, 分爲標題 header, 內容 app-->
<div class="container">
  <header class="page-header">
    <div class="branding">
      
      <h1>Notebook</h1>
      
    </div>
  </header>
  <main id="app">
    <router-view></router-view>
  </main>
</div>

<!--  note list -->
<!-- 定義若干模板 -->
<template id="note-list">
  <div>
    
    <div class="filters row">
      <div class="form-group col-sm-4">
        <input v-model="searchKey" class="form-control" id="search-element"  placeholder="Title" requred/>
      </div>
      <div class="actions form-group col-sm-4">
      
      <!-- 注意這個 router-link, 把鏈接綁定到添加筆記的路徑上 -->
      <router-link class="btn btn-default" v-bind:to="{path: '/add-note'}">
        <span class="glyphicon glyphicon-plus"></span>
        Add
      </router-link>
    </div>
    </div>
    <table class="table">
      <thead>
      <tr>
        <th>Title</th>
        <th>Content</th>
        <th>Tag</th>
        <th class="col-sm-2">Actions</th>
      </tr>
      </thead>
      <tbody>
      <tr v-for="note in filteredNotes">
        <td>
        <!-- 注意這個 router-link, 把鏈接綁定到顯示筆記的路徑上了 -->
          <router-link v-bind:to="{path: '/note/' + note.id}">{{ note.title }}</router-link>
        </td>
        <td>{{ note.content }}</td>
        <td>
          {{ note.tag }}
        </td>
        <td>
         <!-- 注意這個 router-link, 把鏈接綁定到編輯筆記的路徑上了 -->
          <router-link class="btn btn-warning btn-xs" v-bind:to="{path: '/note/'+ note.id +'/edit'}">Edit</router-link>
          <!-- 注意這個 router-link, 把鏈接綁定到刪除筆記的路徑上了 -->
          <router-link class="btn btn-danger btn-xs" v-bind:to="{path: '/note/'+ note.id +'/delete'}">Delete</router-link>
        </td>
      </tr>
      </tbody>
    </table>
  </div>
</template>

<!-- 創建筆記的模板 -->
<template id="add-note">
  <div>
    <h2>Add new note</h2>
    <form v-on:submit="createNote">
      <div class="form-group">
        <label for="add-title">Title</label>
        <input class="form-control" id="add-title" v-model="note.title" required/>
      </div>
      <div class="form-group">
        <label for="add-content">Content</label>
        <textarea class="form-control" id="add-content" rows="10" v-model="note.content"></textarea>
      </div>
      <div class="form-group">
        <label for="add-tag">Tag</label>
        <input type="text" class="form-control" id="add-tag" v-model="note.tag"/>
      </div>
      <button type="submit" class="btn btn-primary">Create</button>
      <router-link class="btn btn-default" v-bind:to="'/'">Cancel</router-link>
    </form>
  </div>
</template>

<!-- 顯示筆記的模板 -->
<template id="note">
  <div>
    <h2>{{ note.title }}</h2>
    <b>Description: </b>
    <div>{{ note.content }}</div>
    <b>Price:</b>
    <div>{{ note.tag }}</div>
    <br/>
    <span class="glyphicon glyphicon-arrow-left" aria-hidden="true"></span>
    <router-link v-bind:to="'/'">Back to note list</router-link>
  </div>
</template>

<!-- 編輯筆記的模板 -->
<template id="note-edit">
  <div>
    <h2>Edit note</h2>
    <form v-on:submit="updateNote">
      <div class="form-group">
        <label for="edit-title">Title</label>
        <input class="form-control" id="edit-title" v-model="note.title" required/>
      </div>
      <div class="form-group">
        <label for="edit-content">Content</label>
        <textarea class="form-control" id="edit-content" rows="3" v-model="note.content"></textarea>
      </div>
      <div class="form-group">
        <label for="edit-tag">Tag</label>
        <input type="text" class="form-control" id="edit-tag" v-model="note.tag"/>
      </div>
      <button type="submit" class="btn btn-primary">Save</button>
      <router-link class="btn btn-default" v-bind:to="'/'">Cancel</router-link>
    </form>
  </div>
</template>

<!-- 刪除筆記的模板 -->

<template id="note-delete">
  <div>
    <h2>Delete note {{ note.title }} ?</h2>
    <form v-on:submit="deleteNote">
      <p>The action cannot be undone.</p>
      <button type="submit" class="btn btn-danger">Delete</button>
      <router-link class="btn btn-default" v-bind:to="'/'">Cancel</router-link>
    </form>
  </div>
</template>


<script src="./js/vue.js"></script>
<script src="./js/vue-router.js"></script>
<script src="./js/note.js"></script>
<script type="text/javascript">
  

</script>
</body>
</html>

note.js

//定義供測試的預設的筆記數據
var notes = [
  {id: 1, title: 'Plan', content: 'what to do', tag: 'tip', createTime: "2018-1-1T07:10:10Z"},
  {id: 2, title: 'Do', content: 'do one thing one time', tag: 'tip', createTime: "2018-1-1T08:10:10Z"},
  {id: 3, title: 'Check', content: 'review and organize', tag: 'tip', createTime: "2018-1-1T09:10:10Z"},
  {id: 3, title: 'Action', content: 'adjust plan and do', tag: 'tip', createTime: "2018-1-1T10:10:10Z"}
];

//尋找筆記的函數, 從上述列表中尋找
function findNote (noteId) {
  return notes[findNoteKey(noteId)];
};

function findNoteKey (noteId) {
  for (var key = 0; key < notes.length; key++) {
    if (notes[key].id == noteId) {
      return key;
    }
  }
};

//筆記列表對象, 綁定模板到 note-list, 指定數據和 computed 函數
var List = Vue.extend({
  template: '#note-list',
  data: function () {
    return {notes: notes, searchKey: ''};
  },
  computed: {
    filteredNotes: function () {
      return this.notes.filter(function (note) {
        return this.searchKey=='' || note.title.indexOf(this.searchKey) !== -1;
      },this);
    }
  }
});

//筆記對象

var Note = Vue.extend({
  template: '#note',
  data: function () {
    return {note: findNote(this.$route.params.note_id)};
  }
});

//筆記編輯對象, 包括一個筆記修改方法 updateNote
var NoteEdit = Vue.extend({
  template: '#note-edit',
  data: function () {
    return {note: findNote(this.$route.params.note_id)};
  },
  methods: {
    updateNote: function () {
      var note = this.note;
      notes[findNoteKey(note.id)] = {
        id: note.id,
        title: note.title,
        content: note.content,
        tag: note.tag
      };
      router.push('/');
    }
  }
});

//筆記刪除對象, 包含一個刪除方法 deleteNote
var NoteDelete = Vue.extend({
  template: '#note-delete',
  data: function () {
    return {note: findNote(this.$route.params.note_id)};
  },
  methods: {
    deleteNote: function () {
      notes.splice(findNoteKey(this.$route.params.note_id), 1);
      router.push('/');
    }
  }
});

//添加筆記對象, 包含一個創建筆記的方法 createNote

var AddNote = Vue.extend({
  template: '#add-note',
  data: function () {
    return {note: {title: '', content: '', tag: ''}}
  },
  methods: {
    createNote: function() {
      var note = this.note;
      notes.push({
        id: Math.random().toString().split('.')[1],
        title: note.title,
        content: note.content,
        tag: note.tag
      });
      router.push('/');
    }
  }
});

//重點來了, 這裏定義的路由表, List 以及 CRUD
var router = new VueRouter({routes:[
  { path: '/', component: List},
  { path: '/note/:note_id', component: Note, title: 'note'},
  { path: '/add-note', component: AddNote},
  { path: '/note/:note_id/edit', component: NoteEdit, title: 'note-edit'},
  { path: '/note/:note_id/delete', component: NoteDelete, title: 'note-delete'}
]});

var app = new Vue({
  router:router
}).$mount('#app')
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章