VUE 起步

作者: 老瓦在霸都 | 来源:发表于2018-10-02 17:54 被阅读0次

    单页面 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')
    

    相关文章

      网友评论

        本文标题:VUE 起步

        本文链接:https://www.haomeiwen.com/subject/kekzvftx.html