如何寫一個拖拽日曆組件(附源碼)

作者簡介 Kid 螞蟻金服·數據體驗技術團隊

本文會介紹如何寫一個可拖拽日曆組件,偏重點在於日曆組件的功能挖掘以及對於開發過程的一些思考,編碼部分會介紹核心部分的實現。代碼在最後也會放出來給大家。

效果演示

先看下項目最後的實現效果:

running.gif | left | 663x480

前期調研

要做一個可拖拽日曆組件,先得去看一圈市場上已有的日曆組件做成什麼樣了。主要是爲了收集功能以及避免重複造輪子。我調研了google日曆,tower,fullcalendar,teambition,webmail等的日曆控件。其中google日曆和fullcalendar算是使用感受比較好的了,以下是他們的使用動圖:

google日曆

google.gif | left | 464x372

fullcalendar

QQ20180402-115350-HD.gif | left | 470x397

功能對比

以下是功能細節的對比列表:

拖拽已有事件
(拖拽默認起始位置)
拖拽已有事件拖拽中效果
(產生遮擋)
左右拖拽事件
(只實現了單方向,並且產生遮擋)
拖拽空白區域新建
事件智能佈局
(跨周後事件佈局亂了)

從表格的對比可以看到,這幾家實現的還算不錯的日曆組件功能都沒有實現全,而且在一些細節上都沒做好。能找到的開源的只有fullcalendar,不過他是jquery版本的,而且功能實現的並不好,細節上也有不少錯誤,所以就打算自己寫一個了(終於找到重複造輪子的理由了~)。

功能

根據之前的調研,一個較好的可拖拽日曆控件需要實現的功能:

  • 拖拽已有事件
  • 雙擊添加事件
  • 左右拖拽事件
  • 拖拽空白區域新建事件

除了功能之外,還有用戶可用性上的細節打磨:

  • 拖拽已有事件的陰影效果
  • 拖拽已有事件拖拽中隱藏
  • 左右拖拽的預覽以及陰影效果
  • 事件智能佈局,包括堆疊和換行後的冗餘清理
  • 拖拽態的處理(偏移量計算以及dragLayer的重寫)

編碼

需求調研完了進入到編碼過程,項目主要基於react和react-dnd。編碼的整體步驟包括:

  • 繪製日曆
  • 根據事件列表繪製事件
  • 事件佈局整理,堆疊效果和換行清理
  • 讓事件可拖動
  • 讓事件可左右拖動
  • 讓空白區域可拖動勾選
  • 拖拽陰影處理 細講的話文章太長,大家看着累,我講一下關鍵實現點。

可拖拽區域

image.png | left | 463x253

主要是用了react-dnd的拖拽能力,圖裏的4種顏色的圈分別對應了4種可拖拽組件的source。

  • 紫色是事件本身
  • 紅色是向左拖拽區域
  • 黑色是向右拖拽區域
  • 綠色是拖拽空白的區域(這個設計最有意思,用拖拽的行爲來模擬選中~)

爲這4種source分別處理好對應的拖拽事件。爲每個source定義好各自的hover事件可以處理不同的陰影效果。定義好layer可以處理拖拽時鼠標的預覽效果。

事件智能佈局

image.png | left | 334x193

事件分類

就是把一天的事件分爲如圖所示的5種:

  • 1是有前一天,有後一天
  • 2是無前一天,有後一天
  • 3是有前一天,無後一天
  • 4是無前一天,無後一天
  • 5是空白的填充事件

渲染某一天的時候,先渲染1和3這種有前一天的,因爲他們有個穩定的index,然後按照優先級渲染事件2,然後是4,填不滿空白的渲染事件5。然後將1和2的index傳到下一天。這樣就能較好的佈局了。

新周事件清理

image.png | left | 503x180

如圖,檢測到新一週開始的時候,我會先清理中間的空白。然後再根據優先級排序事件。

整個開心的代碼編碼過程結束後,居然發現自己內心有些拒絕這份代碼..爲啥寫完代碼,調試完成後,自己不願意再回頭看了呢。哦,是因爲真的寫的不好看啊!不好看換句話說就是代碼的內在質量差。

質量

軟件質量可以分爲外在的和內在的。外在質量包括:

  • 可用性
  • 正確性
  • 健壯性
  • ....

外在質量是用戶關心的唯一軟件特性,我上面一直追求和打磨的其實都屬於軟件的外在質量。用戶是爽的~

可我內心有些拒絕這份剛寫的代碼的原因是因爲軟件的內在質量出了問題,內在質量包括:

  • 可讀性(可能是最重要的了)
  • 可維護性
  • 可接入性(現在支持自定義form,感覺還是不錯的~)
  • ....

寫着寫着發現代碼不好理解了,耐下心細看一下發現:

  • 代碼有冗餘
  • 子程序命名沒有起好
  • 代碼結構混亂
  • 瞎定義css名
  • ....

接着幹嘛,先重構咯~

  • 整理代碼結構,抽抽抽,讓整體流程清晰
  • 重新思考子程序命名,寫註釋
  • 思考對外提供的接口,加強可接入性
  • .....

重構完成一波後思考爲什麼內在質量會出現問題呢?

質量上的追求是無窮盡的,無論是內在的還是外在的。很多技術都可以提升質量:補充測試用例,良好的編程風格,合理的註釋,分層抽象,合理的接口...讓所有的特性都表現的盡善盡美絕無可能。根據一組互相競爭的目標找出一套解決方案,正是這種情況讓軟件成爲一個真正的工程學科

設計

爲什麼質量會差呢?當然是因爲設計的有問題,纔會在開發中發現設計不符合而不斷調整設計,導致破壞了軟件中非常重要的“系統完整性”(人月神話相當推崇的重點)。最終就導致了質量差。

那麼爲什麼沒有好好設計呢?我估計是因爲沒有抵擋住“趕緊開始編碼”的誘惑! 在思考了如何拖拽已有事件之後我就迫不及待的開始編碼。沒有進行更爲詳細的設計。其實這個階段我在大腦裏已經隔絕了後續的需求了(爲了智力上可管理採取的自我保護吧~)。而在實現完拖拽已有事件之後,我開始思考如何拖拽空白區域新建,發現已有的設計需要調整。然後在想到了一個還不錯的點子之後就又開始了編碼。設計不完備的循環導致了質量的下降。

其實軟件的產生與現實中的食物鏈一樣,需求->設計->編碼。一環套一環,越靠近上游出了問題影響面越大。歸納就是我每次的設計都是基於並不完整的需求來做的。

應該怎麼做呢,應該在最開始的時候儘可能的設計全才行。應該加大在初期投入的設計時間。

迭代式開發

可能有朋友看到這裏感覺,不對啊,設計本來就是“險惡的問題”(也就是必須被解決或者部分解決才能定義的問題)。所以開發過程採用迭代式開發沒問題啊。迭代式的好處在於有利於規避風險。不斷小成本的嘗試來降低失敗的風險。所以本來迭代式的開發就必須配備不斷的重構來保證質量的。

對於這個問題。我覺得應該看項目的規模。看我們腦海中可控的複雜度。可能更好的方式是進行原型的開發進行試驗,試驗發現可能之後立刻重新整體設計,然後再編碼,這樣的成本會更小些。

就是在初次迭代進行了一些難點的驗證之後,進行整體設計,這樣可以減少迭代式開發後必不可少的重構環節,減少整體的開發成本,也提高了項目的質量。

總結

本文分享了可拖拽日曆組件的實現過程,編碼細節以及對於整體開發的思考。之所以會探討對於開發的思考是因爲各種方法論都被用於大小不同的項目,對於小項目,方法論的應用顯得很不經意且趨於本能。如果我們有選擇的使用一些方法論的話是能夠減少開發時間以及提升產品質量的。最後附上代碼的傳送門,具體的接入使用可以看下項目的README,還是有相當多缺陷的,歡迎提PR~

對我們團隊感興趣的可以關注專欄,關注github或者發送簡歷至'tao.qit####alibaba-inc.com'.replace('####', '@'),歡迎有志之士加入~

原文地址:https://github.com/ProtoTeam/blog/blob/master/201804/1.md

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