vue-cli从零开始实现一个仿豆瓣app(二)

接着上文,接下来就是实现首页的功能了。

首页的功能是展现最新的片子等等。

主要有顶部搜索框,中间主体部分又分为电影、电视剧、综艺、书籍四类,每一类都是复用同一个组件来实现图片轮播功能。首页每个类别只展现最新的5部影片,其中显示在浏览器上的有三部,可通过按钮左右切换来查看其他两部影片。


先讲一下轮播图实现。

说一下考虑到总共四个类别会在屏幕上,如果设置自动定时切换会看的人眼花缭乱所以我就没有设置定时切换而是由用户手动切换。
四个轮播组件是由一个mainEntertainment组件复用的,组件复用形式是在父组件引入子组件,和使用一般的HTML标签一样使用它。

import showpicture from './mainEntertainmentType'export default{    data{        return{        ...        }    },
    components:{showpicture},//在这里注册该子组件之后就可以使用了}
<showpicture id='1' :movies='movie' v-if='movieFlag' v-on:scrollEvent='executeScroll'></showpicture>

注意一下这里父子件向子组件传递数据是通过movie变量,在子组件的props中注册这个变量就可以用了。
而子组件向子组件传递信息是通过触发事件。
this.$emit('scrollEvent','3');

三张图片的轮播原理是一样的,以左边那张为例。HTML代码如下:
<!-- 三个录播图片模块中的左边 --> <div class='slidediv'> <transition-group tag="ul" :name="imageleft"> <li v-for='(item,index) in filmItem' v-if='index===markLeft' :key='index'> <a @click='goToDetail(item.id)'> <img :src="require('../../static/entertainimg/'+item.eimage)"> <span class='itemNameSpan'>{{item.ename}}</span> </a> </li> </transition-group>
</div>

transition-group是vue中有的为多元素组合运动定义的标签,其中的name动态绑定,如果点击图片向左移动,则将name赋值为‘transition-to-left-left’(意味左边的图片向左移动),向右移动赋值为'transition-to-left-left'(意为左边图片向右移动),我就被自己的命名方式给搞晕了,mark一下。
轮播实现原理就是设一个markLeft记录当前要展示的图片的index,如果5张图片中某一张index和markLeft相等,意味着这张图片是当前要展示的图片(因为此时v-if为true)。
如果点击向左移动则触发methods里的一下方法
 
slideToLeft:function(){ this.imageleft = 'transition-to-left-left'; //将transition-group的名字设为这个变量 var lengthOfPicture = this.filmItem.length-1; //当前要展示的图片的数量,设定为5张,不过有可能数据库中的比5张小嘛,所以要勇length if(this.markLeft === 0){ //已经移到最左边则跳到最右边 this.markLeft = lengthOfPicture; }else{ this.markLeft--; //否则当前index减一跳到左边 }
}

注意:有一个问题让我耗了很长世间,就是动态引入静态资源的问题。
看上面轮播的HTML代码部分,有这样一句<img :src="require('../../static/entertainimg/'+item.eimage)">
这句是为当前影片动态绑定一张展示的图片,在数据库中我存储的是图片的相对路径,所以在进入页面时首先是在created钩子中用axios请求最新的5部影片,请求返回的数据包括影片的名称、图片路径等等信息,也就包括上面那句代码中的 item.eimage。
而要在页面中加载相应的图片,由于图片不是存在src文件夹(也就是具体代码文件夹)而是在static文件夹中的entertaining文件夹中,所以 要用require方式引入图片。注意是动态绑定src哦

实现之后这几天我发现有个问题,就是连续点击图片会导致重影很难看,暂时还没解决,先记着。

然后就是点击某张图片可以切到该影片的详细信息页。

这里又是用到路由跳转,先到路由映射表注册一下路由映射,然后就是点击触发跳转。
goToDetail:function(eno1){
            this.$router.push({path:'/detail',query:{eno:eno1}});
        }


第二部分

顶部搜索框的设定是可以搜索某影片中间几个字,如果有结果则在搜索过程中在搜索框下边列出最新的几条匹配的结果。用户可以通过点击这个结果列表中的某一个跳转,也可以在搜索框按enter搜索。

<!-- 顶部搜索栏 -->
        <div class='top-banner'>
            <div class='sreach'>
                <input class='search-input' type='text' @keyup.enter='enterSearch' @blur='leaveSearch' v-model.trim='searchContent' @keyup='searchEvent' placeholder='影视 图书等'>
                <div class='seUlDiv'>
                    <ul class='searchUl'>
                        <li v-for='(item,index) in mySearchList' v-if='index<5' @mousedown='goToDetail(item.eno)' class='wordList'>{{item.ename}} </li>
                    </ul>
                </div>
            </div>
        </div>

v-model.reim是去掉搜索框前后的空格。

按enter触发enterSearch事件进行搜索,鼠标焦点离开搜索框时会收起搜索时出现的提示框,输入并放开按钮则触发向后台请求查询的事件。

searchEvent:function(){//用户在输入框中输入输入后向后台查询项目
            var _this = this;
            this.clearTimer();                                         //如果当前有等待向服务器请求查询,则中止该请求
            if(this.searchContent&&this.searchContent.length>0){       //用户在输入后500ms内没有再次输入则发送请求,此举可以避免频繁发送请求
                this.timer = setTimeout(function(){_this.$emit('searchhandler',_this.searchContent);}
                ,500);
            }else{
                this.$emit('searchhandler',this.searchContent);
            }
        },
        clearTimer:function(){//用户在500ms内又输入则重新计时
            if(this.timer){
                clearTimeout(this.timer);
            }
        },
        searchHandler:function(Content){       //请求查询搜索关键词操作
            var _this = this;
            if(Content.length==0){
                this.mySearchList = null;
                return ;
            }
            if(this.cancel){//当检测到之前有请求时,取消该请求
                this.cancel('cancel by user');                    //cancel不为空则说明之前向服务器请求了一条数据正在执行,将该请求中止,执行新请求
            }
            this.$axios.post('/api/search/getMySearch',{word:Content,cancelToken:new this.CancelToken((c)=>{
                _this.cancel = c;
            })}).then(function(res){
                if(res.data=='-1'){//在数据库查询不到包含该关键词的影片时
                    _this.mySearchList = null;
                }else{
                    _this.mySearchList = res.data;
                }
            }).catch(function(err){
                console.log(err);
            });
        },

很关键的点就是要执行查询的控制,避免频繁请求。
还有一个问题是,我们子组件即轮播组件中的各个影片的信息是从父组件传来的,而父组件的信息又是从后台获取到的,从后台获取的过程中,很可能父子件已经在渲染子组件并向其传入参数,而这是子组件获取到参数就是空的。最后我的解决办法是让父子间在还没获取到数据之前不渲染,也就是在axios返回之后才把该组件v-if设为true。

对了,还要在轮播组件中用box-sizing,这个很重要
-moz-box-sizing:border-box;
-webkit-box-sizing:border-box;
box-sizing:border-box;
本次项目很多地方都要用到这个CSS,因为忽略了这个问题,导致有一个查了好久的bug 哭
则个布局主要是因为我把很多地方width设为100%,本意是和屏幕宽度一致,结构后来由于padding而溢出了。

对了还有一个问题就是做搜索框的时候为input绑定了blur事件,又为下面的提示列表每一项设置了onclick事件这样click事件是不能被触发的,因为blur事件会先被触发,解决办法就是把click改为mousedown。

首页就大概写这么多,接下来就是各个类别详细列表页了。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值