vuejs入門:簡單的ToDoList

一、工具

  • 具備html、css、js的基礎知識
  • chrome瀏覽器
  • vscode文本編輯器
  • vuejs的官方文檔

二、我理解的vuejs

  • vue(讀/vju:/,與view同音)是一套用於構建用戶界面的js框架,它是輕量級的,易上手(作爲一個前端小白本人用事實證明確實易上手)

  • 官方提供了webpack等腳手架工具,提供了一整套前端集成框架,所有依賴都已經包辦,只需要下載好然後根據要求在指定目錄下開發自己的項目內容即可(但本博文沒有使用此方法)

  • 另一種引入vue的方法是,直接在.html靜態文件中通過<script>標籤的方式引入(本文采取的方式),可以根據需要選擇版本,這僅適用小小型應用:

    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
  • 我理解的vue是一個寫好的js類,我們需要先new一個vue的實例並綁定標籤,才能使用它

  • vue能夠動態地將html中的元素與vue中定義的data雙向綁定起來,動態更新,能夠方便地將數據操作與頁面渲染展示的工作分割開來,能更專注於展示,屏蔽底部細節。下面的介紹也會體現這一點,這裏僅概括一下我的理解

三、編寫一個簡單的todolist

3.1 引入vuejs

  • html部分的靜態文件非常簡單,如下所示:

    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="utf-8" />
            <title>TodoList</title>
            <link href="index.css" rel="stylesheet" type="text/css" />
            <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
        </head>
        <body>
            <div id="app">
                <todo-body></todo-body>
            </div>
            <script src="../src/main.js"></script>
        </body>
    </html>
  • 注意到<body>部分有一個<todo-body>的標籤,這是一個vue組件(component),正確定義和註冊就可以直接在html文件中以標籤的形式使用

  • 引入vuejs之後,在chrome瀏覽器中可以觀察到文件目錄結構如下所示:
    文件目錄結構

3.2 註冊一個vue的實例,並綁定id

// main.js
new Vue({
    el: '#app', 
})
  • 這裏的elelement的意思
  • #app表示id="app"的元素是一個vue實例
  • 缺少這一句註冊,是無法正確渲染的
  • 曾嘗試過將el設爲'body',會報錯說不要將vue掛載在<html><body>元素上,讓我使用一般的元素:
[Vue warn]: Do not mount Vue to <html> or <body> - mount to normal elements instead.

3.3 註冊一個vue組件

(1)什麼是vue組件
  • 任何應用界面都可以抽象爲一個組件樹(圖源自vuejs官方文檔):
    組件樹

  • 在vue中,組件的本質是一個擁有預定義選項的vue實例,因此組件也擁有vue的四大選項:data數據、methods方法/函數、watch監聽事件、props組件自定義屬性

(2)註冊一個名叫todo-body的vue組件
//main.js
Vue.component('todo-body', {
    data: function() {
        return {
            title: 'This is a ToDoList'
        }
    },

    template: '<h2>{{ title }}</h2>',

    methods: {},
    watch: {}
})
  • 意思是註冊一個名叫todo-body的vue組件,其擁有一個數據變量title(一個擁有初始值的字符串)
  • 這樣註冊以後,在靜態html中使用<todo-body>標籤就會套入組件中定義好的template部分(如3.1所述),而template中的雙花括號會顯示組件中的title變量的值
  • 需要注意的是,註冊組件用到的data必須是以函數返回值的形式,避免複用組件時因數據共享導致的意想不到的錯誤

3.4 完善todo-body的vue組件

//main.js
Vue.component('todo-body', {

    data: function() {
        return {
            title: 'This is a ToDoList',
            newLabel: '',
            items: []
        }
    },

    template: '<div>\
    <h2>{{ title }}</h2> \
    <input v-model="newLabel" v-on:keyup.enter="addNewLabel"> \
    <ul> \
        <li v-for="item in items" \
            v-bind:class="{finished: item.isFinished}" \
            v-on:click="finishState(item)" \
            style="cursor:pointer"> \
        {{ item.label }} \
        </li> \
    </ul> \
    </div>',

    methods: {
        addNewLabel: function() {
            this.items.push({
                label: this.newLabel,
                isFinished: false
            });
            this.newLabel = '';
        },
        finishState: function(item) {
            item.isFinished = !item.isFinished;
        }
    },

    watch: {}
})

(1)首先,一個組件的template只能包含一個根標籤,本例是<div>

(2)template的根標籤中包含三個子標籤:<h2><input><ul>,分別表示標題、輸入待辦事項的輸入框、待辦事項列表

(3)data部分新增兩個變量:newLabel用於接收輸入的新的待辦事項,初始值爲空字符串;items用於存儲當前已經輸入的所有待辦事項,初始值是一個空數組,數組的每一個元素都是一個json格式的數據,包括labelisFinished兩個字段

(4)下面重點解釋一下template中的vue指令(可以參考官方文檔

  • v-model="newLabel":表示<input>輸入框中輸入的內容在回車後直接賦值給newLabel
  • v-on:keyup.enter="addNewLabel":表示當觸發回車鍵時,將會調用組件的methods中定義好的addNewLabel函數
  • v-for="item in items":表示循環取出items數組中的每一個元素item,以列表的方式渲染item.label的內容,如果數組爲空則不渲染<li>標籤
  • v-bind:class="{finished: item.isFinished}":根據雙引號中的表達式的布爾值決定是否使用class=finished屬性(配合css使用)
  • v-on:click="finishState(item):表示當觸發click事件時,將會調用組件的finishState(item)函數

3.5 使用localStorage存儲待辦事項

  • window對象表示瀏覽器的一個實例,它既是通過js訪問瀏覽器窗口的一個接口,又是ECMAScript規定的Global對象

  • localStorage是瀏覽器提供的一個本地存儲,其文件存放在瀏覽器目錄下的某個文件夾中,只要不去手動刪除它,每次刷新瀏覽器頁面這個文件都還是存在的,那麼我們就可以通過它存儲我們剛輸入的待辦事項

  • localStorage有兩個方法:setItem(文件名, 存儲內容)用於設置保存內容到本地存儲,getItem(文件名)用於提取本地存儲的內容

    //main.js
    const STORAGE_KEY = 'todo-list';
    
    function initalItems() {
        return JSON.parse(window.localStorage.getItem(STORAGE_KEY) || '[]')
    }
    
    function saveItems(items) {
        window.localStorage.setItem(STORAGE_KEY, JSON.stringify(items))
    }
    
    Vue.component('todo-body', {
    
        data: function() {
            return {
                title: 'This is a ToDoList',
                newLabel: '',
                items: initalItems()
            }
        },
    
        template: '...',
        methods: {...},
    
        watch: {
            items: {
                handler: function(items) {
                    saveItems(items);
                },
                deep: true
            }
        }
    })

    這裏的代碼增加了兩個函數用於設置和提取本地存儲內容,並修改了vue組件中的兩個地方:

  • 數據變量中的items的初始值不再是空數組,而是從本地瀏覽器中提取到的內容,如果提取不到則設爲空
  • watch監聽items變量的變化,只要items發生變化,就會調用handler函數,將變化後的items存儲到localStorage,並且是深複製(類似於python的深複製機制)
  • localStorage的內容可以在chrome瀏覽器中查看,如下圖所示:
    localStorage

  • 這樣一來即使關掉瀏覽器本地存儲的內容也還會存在,再次打開使用瀏覽器打開該html時,依然能正確加載先前存儲好的待辦事項。如果想要清空,只需要選中localStorage下對應的html文件目錄,右鍵,clear即可

四、未解決問題記錄

main.js調用store.js中定義的函數:

//main.js
new_element = document.createElement("script");
new_element.setAttribute("type", "text/javascript");
new_element.setAttribute("src", "../src/store.js"); //引入store.js
document.body.appendChild(new_element);

然後出現了store.js中的函數能在main.js的vue組件中的watch中調用,但不能在data中調用的情況,報錯爲initialItems未定義。

疑似與vue的生命週期有關,查閱一些資料可以使用createdmounted,似乎無法解決上述調用問題,因此直接將store.js的函數寫在main.js中了,仍未能解決js相互調用函數的vue渲染問題。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章