vue之TodoMVC項目實戰


一、初始化項目

1、下載模板

進入github中https://github.com/tastejs/todomvc-app-template,並且在命令行將其clone下來

git clone https://github.com/tastejs/todomvc-app-template.git

2、安裝依賴

進入項目目錄中安裝依賴

npm install

3、引入vue.js文件

首先在命令行中安裝vue

npm install vue

然后再index.html中引入

然后再app.js文件中寫入相應的邏輯代碼

二、實現功能

1、數據列表渲染功能

1.1 功能分析

  • 有數據
每一個數據對象:
{
  id:1,
 content:'',
complated:''  #表示是否已經完成的任務true(false)  

}
並且每一個數據對象有三個狀態:
            未完成(沒有樣式)
            已完成(.completed )
            編輯中( .editing )
  • 無數據

輸入框下面的部分應該隱藏起來

 

1.2 實現

  • 創建一個數據源
                    items:[
                    {id:1,content:'dddd',completed:false},
                    {id:2,content:'aaaa',completed:false},
                    {id:3,content:'bbbb',completed:false},
                    {id:4,content:'cccc',completed:false},
                ]

  • 處理有數據的情況
<ul class="todo-list">
            <!-- These are here just to show the structure of the list items -->
            <!-- List items should get the class `editing` when editing and `completed` when marked as completed -->
                    <!-- 根據不同狀態獲取相應的樣式,三種狀態  -->
            <li v-for="(item,index) in items" :class="{completed:item.completed}">
                <div class="view">
                    <!-- v-model進行雙向綁定,checkbox是否選中  -->
                    <input class="toggle" type="checkbox" v-model="item.completed">
                    <!-- 獲取對應對象的內容  -->
                    <label>{{item.content}}</label>
                    <!-- 將id傳入用於刪除對應的數據  -->
                    <button class="destroy" :value="item.id"></button>
                </div>
                <input class="edit" value="Create a TodoMVC template">
            </li>

        </ul>
  • 處理無數據的情況

利用v-show指令判斷數組長度是否為0,也就是是否為false

<footer class="footer" v-show="items.length">
        <!-- This should be `0 items left` by default -->
        <span class="todo-count"><strong>0</strong> item left</span>
        <!-- Remove this if you don't implement routing -->
        <ul class="filters">
            <li>
                <a class="selected" href="#/">All</a>
            </li>
            <li>
                <a href="#/active">Active</a>
            </li>
            <li>
                <a href="#/completed">Completed</a>
            </li>
        </ul>
        <!-- Hidden if no completed items are left ↓ -->
        <button class="clear-completed">Clear completed</button>
    </footer>

 2、添加任務功能

2.1 功能分析

  •  將輸入的內容添加到任務列表中
  • 如果輸入為空,不做任何事情
  • 按enter鍵添加到任務列表,並清空輸入框

2.2 實現

<header class="header">
        <h1>todoapp</h1>
        <!--綁定鍵盤事件添加數據-->
        <input @keyup.enter="addItem" class="new-todo" placeholder="What needs to be done?" autofocus>
    </header>

在app.js文件的methods參數寫入方法

                addItem(event){
                    //獲取文本框中的值
                    const newValue=event.target.value.trim();
                    //判斷是否為空,如果為空什么也不做
                    if(!newValue.length){
                        return
                    }
                    //如果不為空將新值添加到數組中
                    newObject={
                        id:this.items.length+1, //生成一個新的id
                        content:newValue,
                        completed:false
                    };
                    this.items.push(newObject);
                    //將文本框置空
                    event.target.value=''
                }

3、顯示所有未完成任務數功能

3.1 功能分析

  • 當數組發生變化時計算內部對象的個數,可通過計算屬性
  • 利用filter函數篩選出未完成任務的個數
  • 任務數量為單數時為item,為復數時為items

3.2 實現

    <!-- 返回所有未完成任務的數量,並且如果為單數就為item,否則為items -->
        <span class="todo-count"><strong>{{ incomplete }}</strong> item{{ incomplete===1? '' : 's' }} left</span>

在app.js文件的computed參數中寫入對應的方法

    incomplete(){
                    //箭頭函數返回未完成任務的個數
                    return this.items.filter(item=>!item.completed).length
                    // this.items.filter(function (item) {
                    //     return !item.completed
                    // }).length
                }

 4、切換所有任務狀態

4.1 功能分析

  • 點擊輸入框前面的復選框后,將所有任務標記為與復選框相同的狀態

     (1)使用計算屬性中的set方法,此時需要v-model進行數據的雙向綁定,通過監聽數據屬性,獲取新的checkbox的值

     (2)將獲取的值賦給每一個任務項

  • 當 選中/取消 某個任務后,復選框 也應同步更新狀態

     (1)使用計算屬性的get方法,判斷所有incomplete是否為 0 ,

     (2)綁定了 incomplete,當 incomplete發生變化后, 自動更新復選框狀態(如果為0說明任務已經全部完成,復選框會自動選中,反之不選中

4.2 實現

index.html

<input id="toggle-all" v-model="isSelectAll" class="toggle-all" type="checkbox">

app.js

    isSelectAll:{
                    //循環數據源中的每一個對象,並且將通過v-model雙向綁定獲取的值賦給每一個item中的狀態,從而根據input checkbox的狀態去頂任務的狀態
                    set:function (newState) {
                        this.items.forEach(function (item) {
                            item.completed=newState;
                        })
                    },
                    
                    //根據任務完成的狀態完成綁定v-model的input checkbox框的狀態獲取
                    get:function () {

                        return this.incomplete===0
                    }

                }

5、刪除任務項

5.1 功能分析

  • 懸停在某個任務項上顯示 X 移除按鈕,可點擊移除當前任務項

        (1) 移除按鈕處添加點擊事件

        (2)通過數組函數 splice 移除任務

5.2 實現

 index.html

<button class="destroy" :value="item.id" @click="removeItem(index)"></button>

app.js

//移除對象 splice(),傳入移除對象的索引,以及從此處開始完后刪掉的數量
                removeItem(index){
                    this.items.splice(index,1)

                },

6、編輯任務項

6.1 功能分析

  • 雙擊 <label> (某個任務項)進入編輯狀態(在 <li> 上通過 .editing 進行切換狀態)
  • 進入編輯狀態后輸入框顯示原內容,並會自動獲取編輯焦點
  • 輸入狀態按 Esc 取消編輯,editing 樣式應該被移除
  • 按 Enter 鍵 或 失去焦點時 保存改變數據,移除 editing 樣式

6.2 實現

  • 雙擊 <label> (某個任務項)進入編輯狀態(在 <li> 上通過 .editing 進行切換狀態)
<!-- 獲取對應對象的內容,在內容的標簽上綁定雙擊事件--> 
  <label @dblclick="toEdit(item)">{{item.content}}</label>
                //雙擊進入編輯模式,也就是加入.editing樣式
                toEdit(item){
                    this.currentItem=item
                },
  • 進入編輯狀態后輸入框顯示原內容,並會自動獲取編輯焦點
    <!-- 顯示點擊編輯后的默認值:value="item.content"  -->
                <input class="edit" v-todo-focus="item===currentItem"  :value="item.content"  >
    //自定義局部指令,用於聚焦編輯框修改內容,當進入編輯模式的對象與傳入的對象是同一個時聚焦,防止聚焦到別處
            directives:{
                "todo-focus":{
                    //當指令的值更新后會調用此方法
                    update(el,binding){
                        //el表示作用的元素
                        //binding表示指令后輸入的內容
                        if(binding.value){
                            el.focus()
                        }

                    }

                }
            },
  • 輸入狀態按 Esc 取消編輯,editing 樣式應該被移除
    <!-- 顯示點擊編輯后的默認值:value="item.content"  -->
                <input class="edit" @keyup.esc="cancelEdit"
                       v-todo-focus="item===currentItem"
                       :value="item.content"  >
                //點擊鍵盤的esc取消編輯
                cancelEdit(){
                    this.currentItem=null
                },
  • 按 Enter 鍵 或 失去焦點時 保存改變數據,移除 editing 樣式
    <!-- 顯示點擊編輯后的默認值:value="item.content"  -->
                <input class="edit" @keyup.esc="cancelEdit"
                       @keyup.enter="saveData(item,index,$event)"
                       @blur="saveData(item,index,$event)"
                       v-todo-focus="item===currentItem"
                       :value="item.content"  >
    //通過enter以及blur事件,保存數據,只有當獲取焦點才會觸發該事件
                saveData(item,index,event){
                    //獲取對應文本框中去除空格后的內容
                    const content=event.target.value.trim();
                    //判斷內容是否為空,如果為空,刪除任務項
                    if(!content){
                        //重用removeItem函數刪除
                        this.removeItem(index)
                    }
                    //否則對數據進行更新
                    item.content=content;
                    //更新后移除編輯樣式,.editing
                    this.currentItem=null

                },

7、清除所有任務項

 7.1 功能分析

  • 單擊右下角 Clear completed 按鈕時,移除所有已完成任務
  • 當列表中沒有已完成的任務時,應該隱藏 Clear completed 按鈕

7.2 實現

  • 單擊右下角 Clear completed 按鈕時,移除所有已完成任務

在index.html添加點擊事件,然后再app.js中通過filter函數鍋爐出所有未完成任務,並且賦給items

index.html

    <!-- Hidden if no completed items are left ↓ -->
<!--在對應的地方添加點擊事件-->
        <button @click="removeAllCompleted" class="clear-completed">Clear completed</button>

app.js

                //過濾出所有未完成的任務項,並且將過濾后的數據賦值給items
                removeAllCompleted(){
                    this.items= this.items.filter((item)=>!item.completed)
                },
  • 當列表中沒有已完成的任務時,應該隱藏 Clear completed 按鈕

判斷總的任務數與沒有完成任務數的大小,如果當總任務數 ( items.length ) > 未完成數 ( incomplete) ,說明列表中還有已完成數據,則是顯示按鈕;反之不顯示。

index.html

        <button @click="removeAllCompleted" class="clear-completed" v-show="items.length > incomplete">Clear completed</button>

app.js

//計算屬性
incomplete(){
                    //箭頭函數返回未完成任務的個數
                    return this.items.filter(item=>!item.completed).length
                    // this.items.filter(function (item) {
                    //     return !item.completed
                    // }).length
                },

8、 過濾出不同狀態 的數據

8.1 功能分析

  • 根據點擊的狀態不同,獲取不同狀態下的數據
  • 改變不同狀態下的樣式

8.2 實現

  • 根據點擊的狀態不同,獲取不同狀態下的數據

      (1)在 data 中定義接收狀態變化的值filterStatus 

      (2)通過 window.onhashchange 獲取點擊的路由 hash (# 開頭的),來獲取對應的那個狀態值,並將狀態值賦值給 filterStatus 

      (3)定義一個計算屬性 filterItems 用於過濾出目標數據, 用於感知 filterStatus 的狀態值變化,當變化后,通過 switch-case + filter 過濾出目標數據。

app.js

//1、定義變量
data:{
        filterState:'all',

            },

//2、獲取路由hash值,並且截取需要的路由,當截取的為空時返回‘all’
        window.onhashchange=function () {
        // window.location.hash  獲取的是這樣的數據 #/active
            const hash=window.location.hash.substr(2) || 'all';
            //將狀態值賦值給vm實例中的filterState
            vm.filterState = hash
        };

    //第一次訪問生效,手動調用一次
        window.onhashchange()

//3、定義計算屬性filterItems //過濾出不同狀態下的數據,以this.filterState為過濾條件 filterItems(){ switch (this.filterState) { case "active": return this.items.filter(item=>!item.completed); break case "completed": return this.items.filter(item=>item.completed); break default: return this.items; break } },

index.html

<!--將v-for循環的items替換為filterItems-->
<li v-for="(item,index) in filterItems" :class="{completed:item.completed,editing:item===currentItem}">
  • 改變不同狀態下的樣式
        <ul class="filters">
            <li>
                <a class="selected" href="#/">All</a>
            </li>
            <li>
                <a href="#/active">Active</a>
            </li>
            <li>
                <a href="#/completed">Completed</a>
            </li>
        </ul>

將上述被選中的樣式切換為:

class="selected"

如下:

        <ul class="filters">
            <li>
                <a :class="{selected:filterState === 'all'}" href="#/">All</a>
            </li>
            <li>
                <a :class="{selected:filterState === 'active'}" href="#/active">Active</a>
            </li>
            <li>
                <a :class="{selected:filterState === 'completed'}" href="#/completed">Completed</a>
            </li>
        </ul>

 9、數據持久化(localStorage

9.1 功能分析

目前數據只是單純的放在內存中,自己定義的數組:

data:{
                items:[
                    {id:1,content:'dddd',completed:false},
                    {id:2,content:'aaaa',completed:false},
                    {id:3,content:'bbbb',completed:false},
                    {id:4,content:'cccc',completed:false},
                ],
                currentItem:null,
                filterState:'all',

            },

如果需要保存在本地,可以使用localStorage ,它主要是用於本地存儲數據。語法如下:

//保存數據語法:
localStorage.setItem("key", "value");

//讀取數據語法:
var data= localStorage.getItem("key");

//刪除數據語法:
localStorage.removeItem("key");

本項目中使用的步驟如下:

  • 定義 itemStorage 數據存儲對象,內部自定義 fetch 獲取本地數據 ,save 存數據到本地。
  • 修改 Vue 實例中 data 選項的 items 屬性,通過 itemStorage.fetch() 方法初始化數據
  • Vue 實例中增加一個 watch 選項,用於監聽 items 的變化,一旦變化通過 itemStorage.save() 重新保存數據到本地

9.2 實現

  • 定義 itemStorage 數據存儲對象,里面自定義 fetch 獲取本地數據 ,save 存數據到本地。
var STOREGE_KEY = "todo-items";

    //定義localstorege對象,注意是在Vue實例外面定義的
    const itemStorage = {
        //獲取本地數據的方法
        fetch:function () {
            //獲取數據並且數據反序列化,變成數組對象,如果為空,則是空數組
            return JSON.parse(localStorage.getItem(STOREGE_KEY) || '[]')
        },
        //保存數據到本地,items就是需要保存的數據源,並且以JSON字符串的格式存儲
        save:function (items) {
            localStorage.setItem(STOREGE_KEY,JSON.stringify(items))
        }

    };
  • 修改 Vue 實例中 data 選項的 items 屬性,通過 itemStorage.fetch() 方法初始化數據
var vm = new Vue({
            el:'#todoapp',
            data:{
                // items:[
                //     {id:1,content:'dddd',completed:false},
                //     {id:2,content:'aaaa',completed:false},
                //     {id:3,content:'bbbb',completed:false},
                //     {id:4,content:'cccc',completed:false},
                // ],
                //從本地獲取數據
                items:itemStorage.fetch(),

                currentItem:null,
                filterState:'all',

            },
  • Vue 實例中增加一個 watch 選項,用於監聽 items 的變化,一旦變化通過 itemStorage.save() 重新保存數據到本地
//監聽器,用於本地化數據的存儲,一旦數組對象有變化,立即存儲
            watch:{
            //監聽items,一旦items發生變化就會執行
            items:{
                deep:true,//需要監聽數組對象內部的變化,需要指定deep:true
                handler(newitems,olditems){
                    // newitems:新的數組對象
                    // olditems:之前的數組對象
                    itemStorage.save(newitems)
                }
            }
            },

 

項目地址:https://github.com/ShenJianPing0307/todo-demo

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM