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

上一篇:【vue:把一个JS项目改成vue框架】forkify项目(二)
在上一篇⚡需求九当中,有个小bug需要完善:我们应该确保用户点击“减少”人数的时候,不出现负值:
在这里插入图片描述
所以在decreaseServings()函数中增加一个条件判断:
在这里插入图片描述
在这里插入图片描述

15. ⚡需求十:搜索另一个食谱时,应从第一页开始展示


在此之前,如果你是按顺序学习课程的话,当你看懂课程【Udemy排名第一的JavaScript课程】2023最新完整JavaScript课程 从入门到精通 – 通过项目、挑战和理论掌握JS(中英文字幕)下的P301时,就会感叹vue实在是太方便了!

  • Vue使用一个响应式系统来追踪数据的变化。当Vue实例的data对象中的属性发生变化时,Vue会自动检测到这些变化,并相应地更新DOM。

  • Vue负责根据数据的变化来更新视图,开发者通常不需要手动操作DOM。

P301, JS代码还在对比dom元素来实现动态更新
在这里插入图片描述


下面开始完成⚡需求十,记得切换分支,我的是withwatchquery

这个bug的起因是,当搜索pizza时,假如选到第四页,再搜索avocado时,我们应该为用户自动跳回到第一页,而不是留在第四页。

造成这个bug的原因是我们直接对curPage进行+1/-1,而没有一个赋初值的操作。

解决:watch:{}
只要query变了,那么curPage就应该重新为1

这里就体现了我们之前预先把query存放在状态管理中的优点了,现在我们可以直接通过状态管理获取到这个query
在这里插入图片描述
在这里插入图片描述
现在是食谱确实是从第一页开始显示,但是按钮还没改变,所以把这两个修改代码也要放到pagination组件中(你看,如果你不用状态管理query,那么你就要在两个地方想办法把query获取到)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

16. ⚡需求十一:添加recipe书签

在这里插入图片描述

记得切换分支withbookmarks


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


在vue中,我们应该考虑上图的JS代码如何搬运到Vue框架下,

书签是在食谱详情页,所以找到相应组件,theRecipe
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

食谱已经加入书签列表,但在页面上按钮还未显示差别,接下去:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

接下来,有一个问题要解决:当点击书签之后,我们选择别的食谱,再选择回点过书签的食谱,这个书签就返回原样了。正常来说,书签应该一直保持被点过的状态直到我们再一次修改它。

这个问题产生的原因就是我们每一次点击食谱的时候,它是从状态管理中的action中每次都重新申请的食谱,

所以我们应该在每一次获取到食谱之后,在bookmarksRecipe序列中查找是否已经存在当前食谱,如果存在则将当前食谱新的属性bookmarked设为true


一种简单一些的解决方案是:在theRecipe中,每一次都把当前recipe和已经存储了数据的bookmarksRecipe对比,如果这个序列中有当前食谱,那么就给当前食谱添加一个新的属性bookmarked并设为true


另一种解决方案是:在每一次点击申请到Recipe之后,就检查是否存在在序列中,如果存在,就把当前的Recipebookmarked属性设为true


第二种方式需要将bookmarksRecipebookmarked属性都更新到状态管理中,虽然听起来比第一种麻烦许多,但是我们应该把数据放在状态中,便于后续的代码优化

(比如我们之后又想新建一个组件,这个组件或者页面就是把用户的书签食谱展示出来,通过state我们就懂了直接getters就能拿到,如果是别人拿到你的代码,并且你用的是第一种方式,那他还必须能猜到,哦,这个书签序列bookmarksRecipe在theRecipe的data中,我要通过props或者别的方式才能获取到)。

而不是直接在theRecipe中判断是否为书签食谱,然后渲染。

在这里插入图片描述
那么,既然我们设置了Action动作,我们也必须把state中的其他代码补全:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

然后我们在action中增加函数,使得外部调用这个函数,从而改变状态中的数据:
在这里插入图片描述
在这里插入图片描述

现在bookmarksRecipe已经变成状态管理的一部分了,所以相应地在theRecipe组件中,我们不再使用data(){},应该使用gettersdispatch来访问这个变量
在这里插入图片描述
在这里插入图片描述

调试之后,发现其实在action中,代码的顺序应该要改一下:
在这里插入图片描述
下面我们理一下逻辑:

 <button class="btn--round" @click="addBookmark">
	   <svg class="">
	     <use :href="bookmarkedIcon"></use>
	   </svg>
 </button>

首先在theRecipe板块中点击书签按钮,我们会触发addBookmark()动作,这个动作会把当前的recipe对象传给action中的addBookmark(),然后通过mutation中的addBookmark(state,payload)改变状态中的bookmarksRecipe序列变量。

有了这个序列变量,我们在每一次通过id请求数据的时候(也就是在action中的showRecipe(context))就可以对比当前请求的数据(Recipe)是否在这个序列中,如果在,我们就把bookmarked属性设为true

最后,theRecipe组件中的bookmarkedIcon变量会通过观察这个bookmarked属性来决定当前的食谱的书签是否应该高亮

由于我们是对每一个请求的数据都添加了一个bookmarked属性,所以无论何时返回到标过书签的食谱,我们都能保持书签高亮。


当然,除了addBookmark我们还应该有removeBookmark的功能,也就是用户再次点击,就取消书签高亮:
在这里插入图片描述
不管你是把 if 条件判断放在theRecipe中还是在action中还是mutation中,到目前为止都是可以的,但我十分建议,addremove功能最好是分开,所以放在mutation中显然就不合适了,因为后续如果想要使用addremove还要重写。

我打算把这个if条件判断放在action中:
在这里插入图片描述在这里插入图片描述

在这里插入图片描述


ps:抱歉,上图有个小错误,改为:const index = state.bookmarksRecipe.findIndex(el => el.id == payload)


现在要做的是:把已经标过书签的食谱渲染在这:
在这里插入图片描述
它位于布局中的theHeader部分,所以我们找到相应的html:
在这里插入图片描述

我不想在theHeader中写bookmarks有关的代码,我们也应该把组件分离、功能分离😉

所以另建bookmarks.vue组件,把代码复制过去,把组件注册好:
在这里插入图片描述
在这里插入图片描述

接下来在bookmarks.vue组件中,我们就可以直接通过getters获取bookmarksRecipe序列数据了:
在这里插入图片描述

渲染部分很像theSearchResults部分,所以我们对照着填一下就可以了
在这里插入图片描述

在这里插入图片描述
最后完善一下,当有书签食谱的时候,不显示错误提示,没有任何书签标记的时候要显示错误提示:
在这里插入图片描述
在这里插入图片描述

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

并且当我们点击书签列表中的食谱时,也能自动跳到所点击的食谱详情页,这是因为,

点击食谱链接,我们会改变url我们食谱详情页是通过window.location.hash.slice(1)获取到的url中改变的 id 号来加载食谱,

多亏了前面的工作,现在我们不需要再做任何工作就把书签功能完成了


接下来,我们不希望每一次用户刷新页面,所标过的书签都消失,我们要把书签食谱数据存在localStorage中:

什么时候存?

在我们点击书签后,触发事件后,改变原数据的时候存
在这里插入图片描述
存下之后,用户刷新,我们还要从localStorage中取出数据,渲染在页面上,

什么时候取?

在加载页面的一开始
在这里插入图片描述
在更新状态时,绝对不能直接this.$store.state.bookmarksRecipe = this.storageBookmarks 这点原因前面强调过,你应该还有印象吧?😉

然后我们写好状态管理里面的函数:
在这里插入图片描述
你看这里,我们当初在mutation中把addremove功能分开是有用的,这里就只需要add,直接commit就好了

这下,当我们重新加载页面之后,就仍然能看到我们打过书签的食谱了
在这里插入图片描述

你可以看到上图有一个问题,那就是书签食谱列表中有重复显示,下面我们解决这个bug:


ps:👀这里我建议你休息一下,自己找找bug原因,这个bug可不容易一眼看出,如果你能独立解决它,相信你会很有成就感👍


原因:

在这里插入图片描述
我错把 更新书签食谱新增书签食谱 弄混了,

我以为循环地新增食谱就等于更新了食谱序列,但其实,新增食谱中除了push食谱还有setItem功能,如果使用循环,那么将反复setItem,就会导致本地存储的食谱序列中产生重复值

解决方案就只能是把更新食谱功能单独拎出来

(因为在addBookmarksetItem是不可分离出来的,它应该要紧跟新增食谱state.bookmarksRecipe.push(payload)之后,把这个食谱也新增到本地中)


解决:

我们在取了数据的之后,任务有两个:
①把原来存的多个本地食谱加载到本地;
②把原来存的多个本地食谱更新到状态中的bookmarsRecipe序列。

①已经通过原来的add和remove功能中的localStorage.setItem('bookmarks',JSON.stringify(state.bookmarksRecipe))实现了
②就需要loadBookmarks()来执行

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
完成后,我们看看效果:
在这里插入图片描述
在这里插入图片描述

17. ⚡需求十二:用户自己上传食谱

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


首先新建组件,粘贴html,注册好组件

在这里插入图片描述
在这里插入图片描述
这里再调整一下,App.vue中就应该只放布局的组件,把upload-recipe组件移到theHeader组件中(这个上传食谱的按钮本身也是放在header中)
在这里插入图片描述


下面,我简要记录一下这里遇到的一个问题:
在这里插入图片描述
也就是说我们要把showOverlay变量传到子组件
在这里插入图片描述
而我们如果也要改变父组件的showOverlay变量,又要从子组件把新的showOverlay传回去,

这个问题的解决方案光是听起来就一头雾水 吧👀(可能有更好、更清晰的解决办法,反正我已经晕了🙃)
在这里插入图片描述


所以,为了避免我们在子组件和父组件之间传来传去,让人一头雾水,我想到方案是把”打开上传食谱的按钮“和”关闭按钮“放在一个文件中处理
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

现在我们打开和关闭操作都在theHeader中操作了。

打开:
在这里插入图片描述
关闭:
在这里插入图片描述

在这里插入图片描述
既然两个函数一样,我们就写一个,调用同一个就可以了(@click=”closeForm“
在这里插入图片描述

接下来我们要处理的是upload按钮,点击它,提交表单,把用户的食谱数据整理出来,并且由于这又是一个数据,我们还是应该采用状态管理,所以收集数据应该放在action中…mutation改变…

此外,我们的思路是应该把这个用户数据变成一个类似从API获取的数据,再由我们去获取到这个用户数据,这样渲染部分就不需要重写了。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
我们希望抛出的错误不止是在控制台,还应该在页面显示,因为用户点击按钮,错误显示在控制台的话,用户不会打开控制台,只会看到页面无反应。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
然后用户点击upload按钮,如果没有错误的时候,这个表单应该自动关闭,

这里可以使用$emit释放事件来由子组件告诉父组件“我有变化了”
在这里插入图片描述
在这里插入图片描述

现在,把这个用户数据变成一个类似从API获取的数据,再由我们去获取到这个用户数据,
在这里插入图片描述
在这里插入图片描述
接着,在action中的uploadRecipe函数中写:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
最后,请求成功!
在这里插入图片描述
渲染在theRecipe中
在这里插入图片描述

也要将用户自己的食谱作为书签食谱存在书签列表中,很简单,我们前面已经实现过

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

然后url的id也应该变为用户上传食谱中的食谱id,
在这里插入图片描述
在这里插入图片描述


在这里插入图片描述
在这里插入图片描述
如果在请求的url中也加入KEY,那么用户的食谱中如果包含关键词,搜索关键词就也会出现用户的食谱
在这里插入图片描述


现在要实现如果是用户上传的食谱,那么就显示这个图标,如果不是,就没有这个图标
在这里插入图片描述
首先要为每一个食谱都加上key属性,
在recipe/action中:
在这里插入图片描述
在theRecipe中:
在这里插入图片描述

同理对于左边的食谱列表:
在recipeList/action中:我们要添加key属性
在这里插入图片描述
在theSearchresults中:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

好的,基本完成了,比较粗糙,但是完成比完美更重要,你说对吗?😉
在这里插入图片描述

我的代码可以在GitHubhttps://github.com/yudengisemily/forkify-from-js-to-vue.git找到,感谢你陪我到这,你肯定发现了一些代码不精简的地方,希望你能多多包涵,如果有合理建议,可以直接联系我,谢谢!💕💕💕

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值