【验证模型】3-7 「今晚,我想来点⋯⋯」动手做的餐点选择器进化!(上集)

实作餐点选择器,进化!

在 2-7 章节中,我们曾经实作了一个餐点选择器:

function getTodayCatFood(food) {
    var result = '';
    var randomFood = food[Math.floor(Math.random() * food.length)]

    switch(new Date().getDay()){
        case 1:
        case 2:
        case 4:
        case 5:
        case 6:
            result = randomFood
            break;
        case 0:
        case 3:
            result = randomFood + ' 肉泥' // 透过引数传入
            break;
    }
    return result
}
getTodayCatFood(['杜格','喜碗','优格','金罐','星球']) // 透过引数传入

而今天我们就要透过这个函式再将它进化得更完整一点,并让它能够藉由浏览器来呈现!

厘清问题

与上次同样的是,我们在进行开发之前要先来厘清问题究竟在哪,如此一来当我们在实作的时候才不会既没有解决到痛点,也不会在中途才改变解决的方向,造成开发上不必要的浪费,因此我们再来快速回顾一次当时的情境:

在我们家中有两只猫咪,一只叫做橘橘、一只叫做黑黑,每当下班的时候,总是要思考今天到底要喂什麽食物给他。

有关於饲料的部分,在我们家总共有杜格(乾饲料)、喜碗(乾饲料)、优格(乾饲料)、金罐(罐头)、星球(罐头)等等饲料,另外还有点心肉泥。

每个礼拜一到日的时候,我们会从乾乾或罐罐中随机选择一种饲料作为他们当日的主食,另外我们还会在礼拜三以及礼拜日的时候加上肉泥当作他们的点心。

而我们平常很难决定到底今天要喂什麽食物给他们,并且还要记得给予点心,你能做出功能提醒我今天要给他们吃什麽样的食物吗?

经过上面的情境与需求方 (也就是自己?) 讨论过後,我们可以列出下面几个基本的需求:

  • 画面上要显示出今日的饲料,并且要有储存的功能以方便忘记的时候可以回来察看。
  • 画面上要有地方可以填入饲料清单,而每日饲料便是从这里面筛选出其中一种。
  • 需求方是个手机重度使用者。

因此为了使用者体验我们规划了以下的 Wireframe:

https://ithelp.ithome.com.tw/upload/images/20201011/20119062kxN5UUXwKJ.png

後续经由一些页面、功能流程以及设计确认等等流程或许还会有微调的事项,但最终最好要有个完整的设计稿来确认,再进入到下个环节。

流程一:刻画页面

经过漫长的讨论之後,现在假设我们已经拿到了确认好的设计稿,而我们第一步就是先按照设计稿的需求,先将页面刻画出来。

在这个流程中,我们最主要是透过 HTMLCSS 与素材等等先刻画出整体的页面,此时先不考虑到有些内容是往後要透过 JavaScript 产出的,因为到时候要产生 样板(template) 的过程中,我们可以藉由已经刻画好的画面将 HTML 的部分直接复制回我们的函式中使用。

另外,在刻画画面时,可以藉由事先规划好之前提过的逻辑流程,藉此帮助你厘清哪些区块需要成为一个整体,方便後续调整区块时使用,例如 headerfooter 等等区块。

若还是不太清楚有哪些区块可以拆分的话,可以参考底下样式库中的元件(component)页面,这些样式库基本上实作的元件都是网站中常用功能元件,例如分页(pagination),卡片(card)等等功能区块。

而最後完成的 画面 大概会长成这个样子:

https://ithelp.ithome.com.tw/upload/images/20201011/2011906290p8vJhlth.png

此时的版应该是什麽都不能点,但基本上功能都有在画面中呈现。

流程二:渲染页面函式

在刻画完画面之後,接着我们最大的目标之一就是要先将各个页面各自拆分出去,接着我们才可以依照各个页面来实作里面的功能。

然而依照现代网页开发的设计,我们现在可以透过部分渲染的单页式设计(Single Page Application)来完成我们的实作。因此,我们会需要一个函式来帮助我们渲染出不同的页面,

而整体预计的流程逻辑是:

  1. 初始化页面
  2. 渲染主页面
  3. 後续依照点击的页面

因此我们按照这个顺序来一步一步写出函式。

一开始我们先撰写 初始化页面 用的函式,而这个函式乘载着之後所有在第一次进入页面时所需要的各种资源,常见的会有渲染页面事件、绑定操作事件、初始化资料等等步骤都会在这里出现,而这里我们暂时先关注在渲染页面的逻辑上即可,因此在这里除了撰写初始化页面韩式之外,另外也先预期将会有个渲染页面用的函式:

function initPage(){
  renderPage('mainpage') // 在初始化页面後,这里预期要有个渲染页面函式
}

initPage() // 初始化页面

接着,我们开始撰写渲染页面用的函式,在这里我们指定了需要更新的区域,并透过 取得样板函式 来取得需要渲染的样板:

var view = document.querySelector('.view-wrapper')

function renderPage(pagename){
  view.innerHTML = getTemplate(pagename) // 预期藉由传入不同的页面名称来取得各自的样板
}

这里你可能会觉得为什麽我不把样板直接写进去就好,而最大的原因是因为考量到函式的作用尽量要 保持在做同一件事情上,而渲染页面与组装样板这件逻辑其实是可以再切分开来的,因此我选择将它列为另一个函式,来强调各自的作用。

而在负责提供样版的函式,由於我们刚刚已经将渲染的逻辑切到 renderPage 函式当中,因此在 getTemplate 的逻辑当中,我们可以关注在於要提供什麽样版给各自的页面,这时我们就可以直接从 HTML 上拷贝需要渲染的内容:

function getTemplate (pagename){
  var template = {
    mainpage: `
      <div class="card-wrapper">
        <h1 class="card-title">Today's meal</h1>
        <div class="card-content">
            <p class="meal-text">Gooold</p>
        </div>
        <div class="card-footer">
            <div class="btn btn-get">Get Meal</div>
        </div>
      </div>
    `,
    settingpage: `
      <div class="card-wrapper">
        <h1 class="card-title">Menu</h1>
        <div class="card-content">
            <ol class="meal-list">
                <li class="meal-item">test <div class="btn btn-delete">delete</div></li>
            </ol>
        </div>
        <div class="card-footer">
            <div class="btn btn-add">Add Meal</div>
        </div>
      </div>
    `
  }
  return template[pagename]
}

最後渲染页面所需要的各个函式都已经撰写完毕了,接着我们回到初始化页面的函式中,将点击渲染页面的事件绑上:

var btn_mainpage = document.querySelector('.tab-item.mainpage')
var btn_setting = document.querySelector('.tab-item.setting')

function initPage(){
  renderPage('mainpage')

  btn_mainpage.addEventListener('click', function(){
    renderPage('mainpage')
  })

  btn_setting.addEventListener('click', function(){
    renderPage('settingpage')
  })
}

完成後的程序码大概会像 这样,在这份程序码当中你会发现我们可以透过 initPage 这只函式来追查程序码(tracing code)中的逻辑。

若一开始自己尝试撰写时没办法将逻辑拆分的比较清楚也是在正常的范围内,因为这些得要靠大量时间的练习与观摩他人的程序码慢慢练习而来。

後续第五章节中也会提到如何藉由重构来逐步提升撰写逻辑的技巧。

而以上是在浏览器中实作出餐点选择器的渲染功能部分,接下来我们会将剩下的功能逐一的完成。


<<:  Node.js 最佳实践

>>:  新手学习JavaScript:day28 - Todolist(1)

[Day21] NLP会用到的模型(四)-Seq2Seq

一. Sequence to Sequence 在说明transformer之前,先介绍一下何谓Se...

生成模式-builder

今天要介绍的是生成模式中的 builder (生成器模式) 这模式的目的是从复杂物件的布局中抽取生成...

D-16 中介软件 ? middleware

自定义中介软件 昨天小光认识了路由,所以很好奇为什麽可以做到这样的功能,然後又回想老K说明的请求流水...

【Day 13】 浅谈 OSM

Open Street Map 开放街图,OpenStreetMap,简称 OSM,我们把它当成一个...

使用 VS code 开发

在 Visual Studio Code 开发 Sail 成功的帮我们把专案建立好了,可以来开始写程...