【vue:把一个JS项目改成vue框架】forkify项目(二)

上一篇:【vue:把一个JS项目改成vue框架】forkify项目(一)

12. ⚡需求七:请求一系列数据并渲染在TheSearchresults组件中

在JS中:
在这里插入图片描述


对于vue来说,这个query肯定是在theHeader中的<input>得到,并传递给请求数据的函数,该函数中,通过添加query的API得到的数据将存储一个state中。所以上面的JS代码应该移到action中。同样是状态管理,与前面不同的是,现在action中的函数也要获取外部的参数了(query),可以通过this.$store.dispatch('actionWithParams', param1, param2)

首先,切换分支,
在这里插入图片描述
先获取到query
在这里插入图片描述
再把query交给action,由action请求数据,
在这里插入图片描述


搭建好recipeList这个state,
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


接下来就剩在action中,请求数据,并根据请求结果格式把数据存放在recipeList

请求数据,然后看看数据是什么样的:
在这里插入图片描述

在这里插入图片描述
success表示请求成功了,点开看看数据:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
状态管理是正常的,

  • 但是出现一个这样的问题:

第一次查询pizza的时候:没有数据
在这里插入图片描述
当我再次点击提交的时候:出现pizza的查询结果
在这里插入图片描述
但当我查询avocado的时候:仍然出现pizza的查询结果
在这里插入图片描述
我再次提交avocado的时候:才出现avocado的查询结果
在这里插入图片描述
不知道你看到这里有没有明白错误的地方在哪里?

实际上,这个错误在前面的⚡需求中同样出现过,就是:这个状态值还没来得及更新,就打印出来了,而这一次打印的结果是上一次更新的结果。

回看代码:问题出在异步的调用:
在getters中console.log(state), console.log(state.recipeList)
在这里插入图片描述
在这里插入图片描述
在函数中尝试调用getters,并查看控制台结果:
在这里插入图片描述
控制台打印出getters中的打印结果和submit函数中的打印结果:
在这里插入图片描述
可以发现,是异步函数在执行的时候,我们并没有等它更新完state就着急打印了。

  • 解决:await

在这里插入图片描述
在这里插入图片描述
跟前面一样,我们有了一个重大经验,在调用action中的async函数时,我们应该要采取await,因为虽然状态管理会实时更新状态,但是更新状态本身这些代码也需要时间,我们应该等待这个dispatch行为,从而才能保证我们的状态是完完全全地实时更新。


在JS中,也有类似的经验:
在这里插入图片描述


ps:虽然存储query到state里看似多余,但实际上也有作用,比如其他组件万一需要这个query值来渲染界面就可以从state里调用。虽然在这好像多写了代码,但请相信我,未来肯定有用。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


现在我们终于可以开始渲染部分了(把得到的数据在TheSearchresults组件页面中显示)


JS中,渲染,不过是通过template string把变量插入到html元素中,再通过querySelectorinsertHtml,把数据插入到页面中,这其中就涉及到html的清空,整理,插入,数据变量的传递等。通常这些操作还会涉及到一些重复代码,会用到父类子类继承等等。
(可以查看JS课程P296,就能明白我的意思:【Udemy排名第一的JavaScript课程】2023最新完整JavaScript课程 从入门到精通 – 通过项目、挑战和理论掌握JS(中英文字幕)下


而在vue中我们只需要关注当前的vue文件中的<template> 需要什么变量,从而在<script>中从状态state中拿取所需变量就可以了。

在搜索框headers中,我们只需要存储好query和根据query调用数据,不需要获取任何state的数据,所以整理如下:
在这里插入图片描述
在theSearchresults中,我们从state获取recipeList,再用v-for渲染:
在这里插入图片描述
在这里插入图片描述
这样我们就会产生多个(对pizza来说,应该有59个)一样的(因为我们还没有修改这段html中的变量)这段html。
在这里插入图片描述
修改html,随着具体数据渲染:
在这里插入图片描述
在这里插入图片描述
此时,我们随便选择一个,右方都会根据id去渲染(点击,url的id改变,recipe状态中的action会重新请求数据,recipe状态更新,TheRecipe组件获取到的状态是实时的,TheRecipe组件重新渲染)
在这里插入图片描述
主要功能已完成,现在修修边幅:
左边列表不应该全部高亮:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


如果用户输入一个乱七八糟的值,我们应该反映一个错误,而不是不渲染任何东西,比如这样:在这里插入图片描述
和TheRecipe中一样,把error组件注册好:
(你可以看到组件化有多方便!)
在这里插入图片描述
然后把错误信息的显示条件hasError写好:
在这里插入图片描述
在这里插入图片描述
接着我们在error中:
在这里插入图片描述
下面,我们把上图中的errorFromRecipeList写好:
几乎和errorFromRecipe一样,复制粘贴就完事儿
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


在这里插入图片描述


ps:忘记切换分支了,所以有关这个错误警告的修改在withpagenation的分支里,而不是在withrecipelist


13. ⚡需求八:Pagination 翻页

记得切换分支:
在这里插入图片描述
在这里插入图片描述

获得了一系列食谱之后,我们不希望结果全部列出来,应该让用户翻页查找。
在这里插入图片描述
在我们的searchResults组件中,recipeList代表的是全部的查询结果,然而,我们应该只获取前十个,然后再获取之后十个,再之后十个,每一次这个recipeList都应该是十个但又随着用户的操作(比如点击下一页)而更新。
在这里插入图片描述
(ps: 抱歉,这里config.js的路径错了,应为../config.js)
在这里插入图片描述

recipePerPage 可以用config.js管理,之后如果要修改一次性列出的结果数,就可以在一处地方修改,这里的代码也更易理解。

然后可以试着将<template>中的recipeList修改为只返回十个结果的getRecipePerPage变量
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
没有报错,只返回了十个结果,接下去要做的工作就是动态修改page这个变量,以及渲染“上一页”,“下一页”的按钮。


在JS中:
在这里插入图片描述
针对不同的情况,产生不同的html


在theSearchResults中,有pagination有关的html,我们应该另建一个组件,使得这个功能能够重复使用,也利于单独管理和调整代码。
在这里插入图片描述
先把组件建立好,注册好:
在这里插入图片描述
在这里插入图片描述
查看是否建立好,可以把pagination组件中的注释代码还原:
在这里插入图片描述
接下来,我们要做的是让theSearchresults组件获取到pagination组件中动态变化的page,使得渲染的十个食谱是根据页码进行筛选的。


在JS中,是通过分类讨论情况,然后插入不同的html来实现按钮的显示:
在这里插入图片描述


那么在vue中,可以通过变量来空值v-if显示不同的html,

在pagination中:pagination的输入页数numPages(因为要根据这个判断最后一页显示的按钮情况);输出当前的页码curPage(因为父组件searchresults需要借助这个当前页码来显示相应的食谱)
在这里插入图片描述
numPages是从theSearchresults组件中传递过来的值,
curPage是我们需要传递给父组件theSearchresults的值,
在这里插入图片描述
此时,我们可以修改pagination中的curPage变量,看看结果是否符合:

curPage = 1

在这里插入图片描述

curPage = 6 //最后一页

在这里插入图片描述
现在我们就要思考,如何将这个curPage值传出去,使得渲染的结果也跟着页码改变:这里的技术是从子组件向父组件传递值,可以采用

// 子
this.$emit('事件名',要传出去的变量)
// 父
<pagination @事件名="xxx"></pagination>
methods:{
	xxx(传过来的变量名){
		
	}
}

在pagination中:释放一个事件passing-curpage,并打包第二个参数this.curPage
在这里插入图片描述
同时,也要触发事件(调用函数的操作):
在这里插入图片描述
当点击按钮的时候,curPage改变,然后通过passingCurPage()释放passing-curpage事件并传递curPage,事件被触发后再与updateCurpage()操作绑定,从而实现改变theSearchreults中的curPage变量。


在theSearchresults中,注册好事件,并绑定操作,
在这里插入图片描述
在这里插入图片描述
alert检查是否成功传递,或者打印newCurPage更好


接下来在pagination中,要根据按钮的变化,获取到最新的curPage变量。


在JS中,是通过在html中设置dataset,从而获取到curPage+1/-1的值
在这里插入图片描述

在这里插入图片描述
把gotoPage传出去
在这里插入图片描述
获取到gotoPage,改变食谱
在这里插入图片描述


在Vue中,我们已经把curPage存为data了,所以可以这样解决:
设两个方法(分别对应curPage-1curPage+1操作,当然你也可以只用一个方法,然后用if设置这俩操作),这两个方法都要释放pagination的事件,从而把新的curPage值传出去。
那么,我们可以将原来的passingCurpage方法分出两个方法,分别对应“上一页”,“下一页”。
在这里插入图片描述
记得调用这两个方法,
在这里插入图片描述
在这里插入图片描述
然后可以检查一下是否正确传递:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
那么在theSearchresults组件中,就会根据这个curPage渲染不同的食谱。翻页功能完成!


或许我在前面未强调清楚,在pagination组件和theSearchresults组件中,都有一个名为curPage的变量,他们不是同一个变量,只是在不同的组件中有不同的功能的同名变量,他们的内在联系仅仅是代码的理解:

  • 在theSearchresults组件中,curPage用于
//根据页码筛选出每一页展示的食谱
getRecipePerPage(){
      const start = (this.curPage - 1) * this.recipePerPage // 0
      const end = this.curPage * this.recipePerPage // 9 

      return this.recipeList.slice(start,end); 
    }
// 这个页码来自newCurPage
methods:{
    updateCurpage(newCurPage){
      this.curPage = newCurPage;
      console.log(this.curPage)
    }
  }

它的目的是把newCurPage接过来,从而反映在这个组件的data中,提供一个数据的功能,使得其他变量能调用这个变量,而不是直接地使用newCurPage

如果直接使用,弊端就在于别人拿到代码,一时半会儿会搞不清楚这个newCurPage-1是什么东西,为什么要从pagination获取,又为什么要获取;如果还有其他函数想要调用当前页码,功能就会不明晰,updateCurpage的功能就不单一了,我们应该保留谁干什么就干什么的编程思想,我想这也是vue想体现的精华所在。

  • 在pagination组件中,

curPage主要用于和button交互,不仅button的click行为会改变curPage,并且也需要一个data中的变量能够动态地更改<template>模板中的显示

14. ⚡需求九:按钮更改servings(食谱适用人数),能相应更新食材数目

记得切换分支,我的名称是withservings
在这里插入图片描述
这个操作在theRecipe布局中,所以在theRecipe组件中找到按钮的html。

要做的工作:设置点击事件,并绑定操作,该操作中要改变recipeingredients中的quantity就行,有点类似paginantion,我们对增加和减少servings要区别对待。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
基本ok,存在一个小问题,一般食材的数量我们不好用小数去表达,通常会适用比例或分数,并且,如果食材是根据口味自行决定,我们在食谱中也不会表达数值或0,我的意思是,请看下图:
在这里插入图片描述
首先解决0的事,把未改变之前的食谱打印出来,
在这里插入图片描述
我们应该做的是:如果ing.quantity是null,则不做任何修改:
在这里插入图片描述
其次解决小数的事,可以用一个第三方库,这里我用fracty,
百度npm fracty
当我们需要对template中的变量进行处理再返回处理后的值,在以往JS中是直接调用库,就可以,但是在vue中,template中不会识别出库,所以只能在script模块中使用库。


在JS中
在这里插入图片描述


在vue中,我们需要通过调用方法,由于方法是放在script模块中,所以方法中可以使用库fracty。
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述


下一篇:【vue:把一个JS项目改成vue框架】forkify项目(三)

  • 22
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值