天天看點

#夏日挑戰賽# HarmonyOS - 實作帶日期效果的待辦事項

作者:俞才彬

本文正在參加星光計劃3.0–夏日挑戰賽

前言

初學鴻蒙JS開發技術不久,想要快速結合官方文檔上手鴻蒙JS元件開發,本文主要結合HarmonyOS官網上的相關元件及API實作一個根據日期持久化存儲待辦事項。

效果示範

#夏日挑戰賽# HarmonyOS - 實作帶日期效果的待辦事項

實作步驟

1. 确定兩個頁面

首先确定有兩個頁面:選擇日期頁面、待辦事項頁面。選擇日期頁面将選擇的日期如:

'2022-6-16'

作為路由參數傳遞到代辦事項頁,後者把這個日期作為緩存的

key

去取資料,并渲染在頁面上。

2. 選擇日期頁面

頁面結構如下:

<!-- index.hml -->
<div class="container">
    <text class="welcome">
        <span>建立你的待辦事項</span>
    </text>
    <div class="date-picker">
        <text class="pick-date" @click="showDatePicker">
            <span>點我選擇日期</span>
        </text>
        <!-- 不寫value,視圖将不會顯示 -->
        <picker
            id="picker"
            type="date"
            start="2002-2-5"
            end="2030-6-5"
            selected="{{ getCurrentDate }}"
            onchange="dateOnChange"
            show="false">
        </picker>
    </div>
</div>
           

樣式如下:

/* index.less */
@theme_color: rgba(120, 132, 206, .8);

.container {
    background-color: @theme_color;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    .welcome {
        color: #fff;
        margin-bottom: 120px;
        font-size: 24px;
        font-weight: 600;
        border-bottom: 2px solid #fff;
    }
    .date-picker {
        justify-content: center;
        .pick-date{
            color: #FFF;
            line-height: 43px;
            border: 2px solid #fff;
            border-radius: 50px;
            padding: 10px 50px;
            font-size: 20px;
        }
    }
}

           

時間選擇器使用

picker

元件,

type

設定為

date

,預設值為今天。選擇日期時,觸發

onchange

事件,拿到選擇的日期,點選确定後,跳轉至待辦事項頁面,并将日期作為路由參數傳遞。

// index.js
import router from '@system.router';

export default {
    data: {
        dateValue: '', // 時間選擇器的值
    },
    // 去待辦事項頁面
    goDay() {
        const self = this;
        router.push({
            uri: "pages/day/day",
            params: {
                currentDate: self.dateValue,
            }
        });
    },
    showDatePicker(){
        this.$element("picker").show();
    },
    dateOnChange(e) {
        this.dateValue = e.year + "-" + (e.month+1) + "-" + e.day;
        this.goDay();
    },
    onInit() {
        // 時間選擇器預設為當天
        this.dateValue = this.getCurrentDate;
    },
    computed: {
        // 擷取目前日期
        getCurrentDate() {
            let now = new Date();
            return now.getFullYear() + "-" + (now.getMonth() + 1) + "-" + now.getDate();
        }
    }
}
           

3. 待辦事項頁面

3.1 進入待辦事項頁面

進入待辦事項頁面需要根據路由參數(傳遞的日期)判斷是否是今天,是今天則展示動态的數字時鐘。

還需要根據路由參數從緩存中讀取待辦事項資料,并設定給

list

,用于頁面展示。調用官網API的

storage.get()

方法,由于後續修改資料可能涉及多層回調,考慮到代碼可讀性,将從緩存中讀資料操作用

Promise

封裝。

// day.js
data: {
	keyword: "", // 輸入框内容
	list: [],
	//        list: [
	//            { title: '學習鴻蒙OS', done: false },
	//            { title: '學習js開發鴻蒙應用', done: true },
	//            { title: '學習java開發鴻蒙應用', done: false },
	//            { title: '學習鴻蒙OS', done: false },
	//        ],
	currentDate: '', // 上個頁面傳來的選擇日期
	clock: '', // 今天的時鐘
	timerID: null,
	istoday: false, // 是否今天
	noTodoTips: {
		todayTxt: '請先添加今天的待辦事項吧!',
		notTodayTxt: '當日還沒有待辦事項!'
	},
	isListEmpty: false,
	isDoneEmpty: false,
	isUnDoneEmpty: false
},
onInit() {
    // 判斷是否是今天
    this.istoday = (new Date(this.currentDate).toDateString() === new Date().toDateString());
    if (this.istoday) { // 如果是今天則顯示時鐘
        this.timerID = setInterval(this.updateTime, 1000);
        this.updateTime();
    }
    this.setList();
},
// 從緩存中拿資料并指派給list
async setList() {
	let res = await this.getListFromStorage(this.currentDate);
	this.list = res;

	// 用于控制總、未完成、完成的視圖顯示
	this.isListEmpty = (this.list.length == 0);
	this.isUnDoneEmpty = (this.list.filter(item => !item.done).length == 0);
	this.isDoneEmpty = (this.list.filter(item => item.done).length == 0);
},
getListFromStorage(key) {
	return new Promise((resolve, reject) => {
		storage.get({
			key: key,
			success: function(data) {
                resolve(JSON.parse(data));
			},
			fail: function(data, code) {
				reject(JSON.parse(data));
			},
			complete: function() {},
			default: [] // key不存在則傳回的預設值
		});
	});
},
updateTime() {
	let now = new Date();
	this.clock =
		this.zeroPadding(now.getHours(), 2)
		+ ':' +
		this.zeroPadding(now.getMinutes(), 2)
		+ ':' +
		this.zeroPadding(now.getSeconds(), 2);
},
zeroPadding(num, digit) {
	let zero = '';
	for (let i = 0; i < digit; i++) {
		zero += '0';
	}
	return (zero + num).slice(-digit);
},
           

3.2 分别展示全部、未完成、已完成待辦事項

使用

tabs

元件和清單元件

list

渲染分别展示全部、未完成和已完成待辦事項。

若無資料,全部區域展示 “請先添加今天的待辦事項吧!”,已完成和未完成區域展示無資料圖檔。

<!-- day.hml -->
<div class="container">
    <div class="time-area">
        <text class="select-date">
            <span>{{ currentDate }} {{ getWeek }}</span>
        </text>
        <text class="today-time">
            <span if="{{ istoday }}">{{ clock }}</span>
        </text>
    </div>
    <tabs class="tabs" onchange="tabChange">
        <tab-bar class="tabBar">
            <text class="tabBarItem all">全部({{ getListSum }})</text>
            <text class="tabBarItem undo">未完成({{ getUndoSum }})</text>
            <text class="tabBarItem done">已完成({{ getDoneSum }})</text>
        </tab-bar>
        <tab-content class="tabContent">
            <div>
                <div if="{{ isListEmpty }}" class="no-data-all">
                    <text>
                        <span>{{ (getListSum == 0) && istoday ?  noTodoTips.todayTxt : noTodoTips.notTodayTxt}}</span>
                    </text>
                </div>
                <list class="todo-list" else>
                    <list-item class="todo-item" for="{{ list }}">
                        <div class="todo-item-inner">
                            <input type="checkbox" onchange="changeStatus($idx)" checked="{{ $item.done }}"></input>
                            <piece content="{{ $item.title }}" closable="true" onclose="remove($idx)" class="piece-item"></piece>
                        </div>
                    </list-item>
                </list>
            </div>
            <div>
                <div if="{{ isUnDoneEmpty }}" class="no-data-img">
                    <image class="no-data-images img-way" src="../../common/images/no_data.jpg" style="width: 200px;"></image>
                </div>
                <list class="todo-list" else>
                    <list-item class="todo-item" for="{{ list }}">
                        <div class="todo-item-inner" if="{{ !$item.done }}">
                            <input type="checkbox" onchange="changeStatus($idx)" checked="{{ $item.done }}"></input>
                            <piece content="{{ $item.title }}" closable="true" onclose="remove($idx)" class="piece-item"></piece>
                        </div>
                    </list-item>
                </list>
            </div>
            <div>
                <div if="{{ isDoneEmpty }}" class="no-data-img">
                    <image class="no-data-images img-way" src="../../common/images/no_data.jpg" style="width: 200px;"></image>
                </div>
                <list class="todo-list" else>
                    <list-item class="todo-item" for="{{ list }}">
                        <div class="todo-item-inner" if="{{ $item.done }}">
                            <input type="checkbox" onchange="changeStatus($idx)" checked="{{ $item.done }}"></input>
                            <piece content="{{ $item.title }}" closable="true" onclose="remove($idx)" class="piece-item"></piece>
                        </div>
                    </list-item>
                </list>
            </div>
        </tab-content>
    </tabs>

    <div class="header">
        <input
            id="addinp"
            class="input"
            type="text"
            value="{{ keyword }}"
            maxlength="20"
            enterkeytype="done"
            placeholder="請輸入待辦事項"
            onchange="change">
        </input>
        <button class="buttons" @click="add">添加</button>
    </div>
</div>

           

在計算屬性中計算全部、未完成、已完成的個數,用于

tabs

展示。

// day.js
	computed: {
		// 全部個數
		getListSum() {
			return
            	Object.prototype.toString.call(this.list) == '[object Array]' ? this.list.length : 0;
		},
		// 傳回未完成項目的個數
		getUndoSum() {
			return this.list.filter(item => !item.done).length;
		},
		// 傳回完成項目的個數
		getDoneSum() {
			return this.list.filter(item => item.done).length;
		},
		// 星期幾
		getWeek() {
			let week = ['天', '一', '二', '三', '四', '五', '六'];
			let day = (new Date(this.currentDate)).getDay();
			return '星期' + week[day];
		}
    },
           

3.3 添加待辦事項

在輸入框中輸入内容,點選添加按鈕,添加待辦事項,并調用

storage.set()

API将

list

存在緩存中,成功之後更新

list

以更新視圖。若輸入框無内容,使用

prompt.showToast

提示輸入内容。

// day.js
change(e) {
    this.keyword = e.value;
},
add() {
    if (this.keyword === "") return prompt.showToast({
        message: "請輸入内容"
    })
    this.list.push({ title: this.keyword, done: false });
    this.keyword = "";
    this.setStorage();
},
// 封裝函數供修改或者添加緩存中的資料
setStorage() {
	const self = this;
	storage.set({
		key: this.currentDate,
		value: JSON.stringify(this.list),
		success: function() {
			self.setList();
		},
		fail: function(data, code) {}
	});
},
           

3.4 完成 / 取消待辦事項

點選選擇框,勾選或者取消勾選待辦事項,并設定緩存。

// day.js
changeStatus(index) {
    this.list[index].done = !this.list[index].done;
    this.setStorage();
},
           

3.5 删除待辦事項

使用

piece

元件的

onclose

事件删除待辦事項,删除前使用

prompt.showDialog

彈窗方法詢問是否删除,點選确認後删除,并設定緩存。

// day.js
showDialog(options = {}) {
    if (JSON.stringify(options) == "{}") return;
    prompt.showDialog(options);
},    
remove(index) {
    let self = this;
    let options = {
        message: "确定要删除嗎?",
        buttons: [
            {
                text: '确定',
                color: '#87cbff',
            },
            {
                text: '取消',
                color: '#666666',
            },
        ],
        success: function(data) {
            if(data.index == 0){
                self.list.splice(index, 1);
                self.setStorage();
            }
        },
        cancel: function() {
            console.log('dialog cancel callback');
        },
    };
    this.showDialog(options);
},
           

總結

以上就是完成帶日期緩存效果的待辦事項的全部過程了,算是對鴻蒙JS開發快速上手的初步認識吧, 後期還可以對其完善,比如在樣式、功能方面等等,希望可以和大家共同學習鴻蒙更多的知識,一起進步。

更多原創内容請關注:中軟國際 HarmonyOS 技術團隊

入門到精通、技巧到案例,系統化分享HarmonyOS開發技術,歡迎投稿和訂閱,讓我們一起攜手前行共建鴻蒙生态。

繼續閱讀