组件涉及+动态组件应用
下面我们先来继续编写书架列表吧即ShelfList.vue书架的数据我们之前就已经获取到了,通过引入mixin即可。
for循环书架数据展示一堆item(图书列表中的方框)
我们要实现图书列表的图书数据显然应该用v-for循环来循环每个方框的图书,书架图书数据之前讲过就是数组中一个个图书状态,可能是一本书可能是一个分类,然后每一个方框即ShelfItem.vue中不是一个图书就是一个分类,所以应该获取数据,然后对这个数据循环给子组件ShelfItem,所以循环中应该把item传给子组件ShelfItem中,所以如下
然后通过component在ShelfItem中实现动态组件
因为每个ShelfItem都有三种状态,而我们根据某些值判断只展示其中的一种状态,所以我们要用动态组件,如下
就是在其中加入<component>标签就代表动态组件,这个组件有三种可能嘛,三个组件中的一个,然后这个动态组件是哪个组件是通过:is="item"来判断它展示哪个组件的,computed计算属性中定义这个item,我们书架数据中type是表示它是哪种状态的,所以我们用this.data.type=1还是=2来判断展示什么,然后是1就展示book,book在data中定义是ShelfItemImage组件,同理如果是=2就展示category...
这种动态组件就是只需要引入不需要components中注册,然后在data中定义属性来分别表示这些组件分别是什么
书架图书列表布局
我们希望这里的方框会随着我们屏幕尺寸变化而变化,我们采用动态羁绊的方式来算出这里每一个方框的高度,因为它的宽度其实是确定的因为我们一排固定排三个方框,所以宽度是固定的,所以我们需要来计算这个高度。这里的一个难点就是来解决计算方框的高度。
首先实现一行三个方框,即做它的宽度
给它flex布局,然后给他flex-flow:row wrap;即让方框们水平布局并且可以换行;然后每个item都flex:0 0 33.33%;即可实现每个框固定一行3个,因为可以换行所以第四个就换行,第二行就又三个这样子,然后给每个方框宽度为整个图书列表宽度的三分之一即width:33.33%。然后item组件那边就给width:100%,height:100%
然后给它高度
如下,我们给方框绑定一个样式即:style,让它高度为itemHeight;然后我们到计算属性computed中定义这个itemHeight,如下
我们给每个方框一些边距,我们用个小技巧:给整个列表左右边距15px然后再给每个方框上下左右各15px边距
然后我们继续做高度
因为屏幕尺寸是会变的嘛,所以我们要先计算出当前屏幕宽度下每个方框的宽度,因为我们获取的数据中每本书的图片宽是250高是350,是有宽高比的,比如此时方框宽度为250时高度应该变成350,这样才能不拉伸坏图书图片。
所以宽:高=5:7,所以5高=7*宽,所以高=7*宽/5
我们先计算当前屏幕尺寸下每个方框的宽度,window.innerWidth/3,但是因为还有边距,所以还要减去边距才是每个方框的正确宽度,最简单的就是直接屏幕宽度减去左右全部边框然后除以3即可得到每个边框的宽度
因为整个列表有左右15px即30px然后每个方框有左/右15px所以每个方框左右边距30*3=90+30=120
但是我们这里不能直接减去120px,我们要先换成rem,我们之前写过一个方法叫realPx,它是将我们的120px转换成rem的自适应的120,所以如下
然后我们就可以把图片放进去展示啦,单书封面+分类书籍封面实现
我们先做单书封面
要获取封面图片,所以shelfitem中的component中要绑定数据data,把其传到那三个组件中
然后我们做分类书籍封面
我们这个分类书籍封面是一个九宫格的布局,当不够9个的时候图片展示在左上进行显示
我们先来看看分类书籍方框中接收的数据是什么样的,因为有两个type=2的所以分类图书组件被动态展示了两次即两个这个分类图书框,所以有两个数据,如下一个是标题为category的分类框的一个是标题为education的分类框的
这个数据我解释一下:书架数据我们获取后是保存在vuex中的ShelfList变量中的,然后我们在列表ShelfList组件中for循环这个ShelfList变量,把里面的每一个item如下分别给一个个ShelfItem中。所以每个ShelfItem中有可能接收到的是一本书也有可能是一个分类书籍;然后我们是在ShelfItem中做判断如果这个ShelfItem中接收的数据是一本书即type=1就展示状态1组件并且把这本书数据传过去,如果这个ShelfItem中接收的数据是一个分类数据即type=2就展示状态2组件并且把这个分类书籍数据传过去;所以状态1组件中接收的数据是一本图书,状态2中接收的数据是一个分类书籍这样子
下面就是vuex中ShelfList保存的数据
这里一个就是一个ShelfItem接收到的,有13个ShelfItem
因为请求回来的书架数据有13个,所以ShelfItem有13个,其中有2个是分类书籍有11个是单书,所以ShelfItem中有2个展示状态2组件,有11个展示状态1组件
回到做分类书籍封面中,清楚了数据是怎样的,我们就来做,分类书籍中图书放在ItemList中,然后我们写布局
九宫格布局,分类书籍中我们是固定只放9本书,所以高不用想书架列表中那样计算,因为九宫格嘛所以肯定就三行所以高度就直接三分之一就好,书架列表你添加的图书多了可能就很多行嘛所以高度就需要计算
有点类似,flex布局让每个图书宽度占三分之一,高度也占三分之一
我们不希望第9本书后显示出来,所以比较简单的做法是直接在最外一层增加一个overflow:hidden;将超出的部分隐藏掉即可
然后增加边距,直接给每本图书上下左右边距即可
但是这样子第一本书距离左侧5px和距离右侧第二本书距离10px不一样,所以改,通过nth-child去分别获取第一个,第二个,第三个元素,第一个元素距离左侧就5px距离右侧就2.5px,中间元素就左右都距离2.5px,最后元素就距离左侧2.5px距离右侧5px这样子
最后做状态3的添加组件封面
状态3表示去到书城首页。因为我们获取回来的书架数据中没有type=3的数据,我们是要手动添加进去,我们在utils下的store.js中添加两个方法,一个方法是往书架数据中添加这个type=3的数据,一个方法是删除书架数据中type=3的数据后面会用
然后我们获取到这个书架数据后先用这个方法把type=3这条数据插入进去,然后再保存到vuex中
然后我们添加样式
接下来做方框点击,先实现点击图书展示详情页以及点击加号转到书城首页
然后我们来实现点击添加+编辑
我们先来实现点击编辑下面方框中都出现一个灰色勾图标,点击方框这个方框的这个勾图标就高亮
方框中添加一个图标,然后v-show编辑模式中才显示
不过我们状态2和状态3时不需要显示
然后点击编辑的时候状态2有一个变暗的显示,我们给它动态组件绑定一个样式,样式条件是在编辑模式下在状态2中才显示这个样式,样式中平时就透明度100%,该绑定样式中透明度就50%
然后编辑状态下,点击方框图书是不能进入详情页才对,所以点击事件中加个判断就好了,不是编辑下才能点击。
然后我们做编辑状态中点击图书展示高亮,我们书架数据中每个数据中都有一个selected属性,这个属性为布尔类型,表示当前是否被选中,默认为false,所以我们利用这个,给勾图标绑定一个样式,如果这个selected为true即被选中时就展示这个样式,样式就给图标改变颜色即可。那什么时候改变这个selected属性呢,你编辑状态下一点击图书就把这个图书的这个属性改为true即可
接下来我们有一个关键动作,我们在vuex中定义一个ShelfSelected变量,用来保存书架图书中选中的图书们。
为什么要增加这个,如果不增加这个变量,我们所有的选中状态就都要到ShelfList中判断,而且ShelfList里面有三种状态,而选中的图书只是在状态1中,统计被选中的图书时就比较麻烦。所以我们定义了一个变量专门用来统计被选中的图书们,放到vuex中
第一步是我们要把选中的图书放到这个shelfSelected中,这个还比较麻烦,我们先实现这一步
如下点击这本书的时候判断这本书是否是选中状态,如果是选中状态就把这本书追加到这个shelfSelected变量中,但是这时候如果是如下用push可能会出现重复的问题
我们在utils下做一个扩展方法,如下给数组的原型中添加一个叫pushWithoutDuplicate的方法,这个方法是用来处理往数组中添加东西的方法。这个atguments是一个类数组对象,它只在函数内部使用,用于存储函数被调用时传递的所有参数。方法中做的就是遍历你传过来的图书,如果这个图书在shelfSelected数组中有过,那就不再添加这本书,如果没有就添加这本书。
然后push改为这个方法
然后取消勾选这本书时,这本书应该从vuex的shelfSelected数组中删除
然后我们编辑中点击这本书,即这本书是被选中就会看那个方法追加到那个shelfSelected变量中,如果我再点击这本书,这本书应该从shelfSelected变量中移除,接下来我们来实现这个移除
所以如果是未被选中状态,我们就把这本书从shelfSelected数组中过滤掉即可,如下改变这个vuex中的变量,改变的值是过滤后的值
这样选中图书保存到vuex的shelfSelected数组就实现了,取消点击时也可以从shelfSelected数组中取消了
我们选中图书的目的是要让它进行一些操作
我们点击编辑后,下方需要出现一些操作栏。当我们一本书都没选的时候操作栏是灰色,选中一本书后它就可以判断这本书的状态,同时还会根据这本书的状态来展示不同的操作栏名称,操作完成后它会有操作完成的提示
先做出菜单栏,并且有点击图书前后的透明度变化
首先我们实现一下操作栏这个tab,给它固定定位,在StoreShelf中引入
然后我们可以看到这个出现的时候,滚动条滚动到最后的时候,这个菜单栏会把最下面那行的书名给遮盖住,这是因为我们滚动条组件不应该按全屏显示,它应该在编辑模式下底部向上有一个这个菜单栏这么高的距离,这样菜单栏才不会遮住这个书名这样子。我们的scroll组件之前有定义这个bottom,所以我们在StoreShelf的scroll组件中直接传入bottom即可
这个bottom平时是0,编辑状态下就变成48,所以我们定义一个变量scrollBottom,然后在watch中去监听编辑状态,如果是编辑状态那么就让scrollBottom变成48,并且调scroll的刷新方法去重新计算滚动条组件的高度
如上,发现并没有成功,这是因为我们切换编辑的时候不应该立即执行refresh(),而是应该等,因为我们编辑的时候会触发一些DOM的操作,比如点击编辑的时候我们会让这个菜单栏这个DOM的显示与否,我们应该在整个DOM对界面变化完成之后再来实现refresh()即等菜单栏渲染出来后再计算滚动条的高度,所以需要调$nextTick,等界面响应变化完了之后我们再来refresh这个scroll
接下来我们做菜单栏的布局,这个tab我们也做过,在computed中建一个tabs方法,方法中返回一个数组,数组中就是这几个tab值,一般有index,然后for循环展示这个数组,然后做一个点击事件点击事件中把数组中这个tab的index传进去,一般就是这样子
每个tab图标不一样,所以在循环里面把四个图标都加进去,根据index来判断当前item的tab显示哪个图标。然后平时图标透明度为50%即灰灰的,然后点击一本图书后就把透明度变成1,所以给这四个图标都绑定一个样式,样式判断就是当前有图书被选中即shelfSelected有值
我们点击编辑然后选中几本图书后又不想选这些书了,然后点击取消后我们再次点击编辑发现刚才选的图书还是选中状态,我们需要的是取消了下次再次点击时这几本书不再是选中状态了,现在做这个
即在点击取消时即非编辑状态时,我们要将vuex中的shelfSelected置回空数组,并且把书架中的每一本书的selected置回原来的false
使用create-api实现tab的弹出框
接下来我们来做点击tab然后出现弹出框,这些弹出框被大量使用,但是每处使用的弹出框中的文字是不一样的,所以怎么实现这个弹出框
这个弹框组件就是我们之前做到 toast.vue,我们的Toast组件,这里也要多次被使用,但是每次其他组件要用它的时候每次都要先引入它然后注册它使用它然后每次还要调用弹框组件中的show方法让这个弹框显示,就比较麻烦
介绍一个重要的方法,叫create-api,这个库可以让我们组件与组件之间实现真正的解构,而我们只要通过javaScript的API就可以实现组件的调用
我们安装这个库
然后到main.js中引入这个库
在cerate-api.js中我们将这个vue-create-api引用进来,然后将vue也引入进来,把我们要用的Toast组件也引入进来
通过Vue.use(CreateAPI)来使用这个插件,use完后我们就会在Vue中挂载一个createAPI方法,通过这个createAPI方法传入Toast,然后就可以通过api的形式调用我们的Toast,我们调用这个cerateAPI方法的时候create-api这个插件就会帮我们在Vue的实例上面扩展出一个前面叫create后面叫我们引入的组件名称Toast即$createToast的方法
具体这么用:
我们直接通过this.$createToast(),然后我们通过里面的¥props属性传入一个对象,这个对象就是我们toast组件需要的参数,然后这个this.$createToast()就是创建了这个弹出框的DOM,然后调用弹出框组件中show方法即可显示出这个弹出框。就不用引入弹出框也不用注册使用,就直接下面这样就可以直接使用这个组件了就比较方便。注意用这个的话toast组件中要加属性name:'toast'
我们可以更加简化,我们在create-api.js中,直接调用mixin,通过全局mixin增加一个方法,方法我们就叫toast,传入一个setting,然后把我们这个this.$createToast({ $props:setting }),这样我们要用这个组件的时候就直接通过this.toast()即可使用这个组件啦,贼啦方便
我们来到元素中看看它,它这个是在最外层给我们创建的toast,不是在我们vue渲染的app中,和我们vue渲染的app那个是不一样的,是添加在我们body后面而不是vue的app中,所以对于这一类添加的样式,我们通常建议比如像弹窗这种全屏的,建议是做全屏的用这个,如果你是想直接嵌在vue里面那就不要用这个
然后我们再建那个白色的弹窗组件,也多处用,所以我们也使用create-api,如下
然后写popup布局,因为各处的按钮数量可能不同,而按钮中有标题属性有的还有danger,所以我们把btn定义为一个数组,然后如下我们给这个弹窗一个固定定位。然后哪里用这个弹窗就哪里调用它
接下来我们增加一些按钮,每个地方按钮文字标题文字是不一样的,是在当前组件中传不同的值过去给弹窗组件的,所以如下,按钮中又有点击事件
然后给背景和弹窗分别添加过渡动画,但是隐藏的时候发现没有过渡动画,这是因为你点击背景隐藏的时候直接popupVisible变为false了,popupVisible控制着整个弹窗,你这个过渡动画就在这个popupVisible里面,popupVisible为false即隐藏了,所以自然过渡动画就显示不了,所以我们再定义一个Visible来控制弹窗的显示隐藏
补充一下:这个阅读器电子书今天又展示不出来,发现是192.168.xx又改了,修改一下环境变量就又好了,每次改环境变量的时候记得重新运行项目,不然不行