2018年10月

QQ截图20181022125102.png

我们现在开始对上次的代码进行封装,我们上次的代码是截至到我们通过jsonp已经获取到了轮播图的数据array,我们再定义一个轮播图组件即可

首先我们在base下建立一个组件我们将slider组件的模板定义了如下的样子

这个插槽就是起一个占位的作用

我们开始上手写代码,我们定义轮播图组件之前要做这几样事情,首先我们要定义一堆关于轮播图的数据

//定义轮播图的数据

props:{
loop:{
type:Boolean,
default:true
},
autoPlay:{
type:Boolean,
default:true
},
interval:{
type:Number,
default:4000
}

},

定义完成之后我们在钩子中创建几个方法

值得注意的是,由于项目经验,我们在加载这些方法的时候,要定义一个计时器,让他20毫秒进行加载,纯粹经验,不用多问

setTimeout(()=>{

//计算宽
this._setSliderWidth()
//计算点
this._initDots()
//初始化轮播图
this._initSlider()
//自动播放
if(this.autoPlay){
this._autoPlay()
}

},20)

首先我们先计算宽的方法

值得注意的是,我们在写轮播图组件的时候,要自动添加类名匹配到组件中的css样式,所以我们不仅要计算宽,还要动态添加类名

_setSliderWidth(resize){

//设置轮播图的宽
//获取子元素对象
this.children=this.$refs.sliderGroup.children
//设置宽度
let width=0;
//获取父级的宽度
let sliderWidth=this.$refs.slider.clientWidth;
for(let i=0;i<this.children.length;i++){

//给每个元素添加class类名
let childDom=this.children[i];
//调用公共dom方法
addClassName(childDom,"slider-item");
//设置宽度
childDom.style.width = sliderWidth + 'px';
//父级窗口随着递增
width+=sliderWidth;
}
//如果是loop循环,为了切换效果,需要2倍宽度
if(this.loop && !resize){
width += 2*sliderWidth;
}
this.$refs.sliderGroup.style.width=width + 'px'
},

这个方法的思路是,首先获取了父级窗口的宽度,然后通过循环子对象的个数,把父级的宽度设置给子元素,然后在循环的末尾,要自加一个width,等到循环结束之后,
这个width的值会是所有的子元素的宽总和,然后最后会把这个总和附给我们的视口总宽度。

值得注意的是我们这边添加class类名的方法,在common下添加了一个有关于dom操作的js封装。

这个封装主要是2部分,一个是添加class类名,一个是判断有没有class名字

/**

  • 用于添加dom的公用js
    */

export function addClassName(el,className){

//如果有这个class
if(hasClassName(el,className)){
//什么都不做
return

}

let newClass = el.className.split(' ')
newClass.push(className)
el.className = newClass.join(' ')

}
//判断是否有class的方法
export function hasClassName(el,className){
//创建正则表达式
let reg=new RegExp('(^|\s)'+className+'(\s|$)');
return reg.test(el.className);
}

这个动态添加类名的思路是,把他们全部拆分成数组,空格隔开,因为可能实际代码中还有其他的类名。不能和他们冲突,所以push新的类名,
然后再把它join进字符串中,就完成了添加类名的操作

值得注意的是,如果我们有loop循环的数据的话我们需要×2

注意一下,需要在组件中自己定义css样式

.slider
min-height 1px
.slider-group
position: relative
overflow: hidden
white-space: nowrap
.slider-item
float: left
box-sizing: border-box
overflow: hidden
text-align: center
a
display: block
width: 100%
overflow: hidden
text-decoration: none
img
display: block
width: 100%

这个时候我们就可以看一下效果,发现所有的img都是很合理的展示出来了

然后我们展示出来以后,需要能够左右滑动,我们这个时候就用到了better-scroll这个插件,所以我们需要安装它

然后在钩子中定义一个初始化轮播图的方法

//轮播图初始化
this.slider=new BScrool(this.$refs.slider,{
//传递参数配置
//横向滚动
scrollX:true,
scrollY:false,
//惯性
momentum:false,
snap:true,
snapLoop:this.loop,
snapThreshold:0.3,
snapSpeed:400,
click:true
})

然后就可以横向滚动无缝连接了

然后剩下的这个小点点,我们可以通过下面的方法实现,首先循环轮播图的个数来循环span标签

_initDots(){
this.dot=new Array(this.children.length);
},

这样就就可以循环长度了,这个时候就可以看到点了

循环之后,我们就开始可以做自动播放了

首先自动播放的原理就是,延时器+自增数字就可以做

首先我们定义一个data数字属性为0

_autoPlay(){
let pageIndex = this.pageIndex+1;

if(this.loop){
    pageIndex += 1
}

this.timer = setTimeout(()=>{
this.slider.goToPage(pageIndex , 0 ,400)
},this.interval)
}

这边我们做了一个判断,如果是循环播放的话,那么就自加一
因为betterscroll在初始化的时候会增加多一页,要把第一页跳过。

然后定义一个定时器timer,使用了betterscroll中的一个方法,跳转页数,pageIndex是跳转到第几页,0指的是x轴,400指的是速度
我们跟初始化的速度参数保持一致都是400;
然后延时时间是定义的数据interval。

然后我们会发现在循环第一次的时候就不会有第二次了,这个是因为页面被挂载的时候autoplay方法只执行了一次。

解决方案是这样的:

在我们初始化轮播图后面写方法,因为在即将进入下一页的时候会派发一个事件,我们可以监听这个事件来做一些逻辑

this.slider.on('scrollEnd',()=>{
//pageX是横向滚动的索引

let ApageIndex = this.slider.getCurrentPage().pageX
if(this.loop){
//因为自动会给第一个拷贝到最后一个形成轮播图,所以这里要减一
ApageIndex -= 1

}

this.pageIndex=ApageIndex
if(this.autoPlay){
clearTimeout(this.timer)
this._autoPlay();
}

})

这里我们通过betterscroll的api来获取索引,然后把这个索引附给pageIndex,然后然后清除计时器,这个再重新执行自动播放的方法

为什么要清除计时器,因为如果在即将进入下一页的时候,我们人工手滑一下,就直接造成轮播图滚动异常,所以要每次清除。

现在我们的自动播放已经完成了,现在就改操作,这个点了,如果让他滚动到哪里,那个点就放大呢??

这个其实非常简单,我们只需要绑定一个class动态属性即可。

然后就大功告成。

但是还没有完毕,我们如果调整一下视口的宽度,会发现轮播图不会适应窗口了,那么该如何解决这个bug?

//监听视口宽度
window.addEventListener('resize',()=>{
//如果slider还没被初始化,就返回掉
if(!this.slider){
return
}
this._setSliderWidth(false)
})

通过监听视口宽度,来重新计算我们的宽度,那么为什么要传递一个false,那是因为我们计算宽度的时候由于是loop循环
要把宽×2,如果每次改变视口宽度,就一致要把宽×2,这样显然是不合适的,所以我们要通过一个参数来判断。

我们在宽度计算的方法中传递一个参数,如果这个参数不是false,那我们就可以×2

if(this.loop && !resize){

width += 2*sliderWidth;

}

下载.jpg

我们可以通过jsonp跨域来获取qq音乐的数据,所以我们需要安装jsonp的插件

npm install jsonp --save

然后我们进行jsonp的封装,首先我们写jsonp.js放在common目录下,在这个文件中我们要写封装的jsonp

import originJSONP from 'jsonp'

export default function jsonp(url,data,option){

    url+=(url.indexOf('?') < 0 ? '?' : '&') + param(data);
    return new Promise((resolve,reject)=>{
    //调用jsonp
    originJSONP(url,option,(err,data)=>{
    if(!err){
        resolve(data)
    }else{
        reject(err)
        }
    })
})

}

export function param(data){

    let url='';
    //循环data
    for(var i in data){
        //如果data值不等于undefined 就把值附给value,否则把空字符串传递给value
        let value= data[i] !== undefined ? data[i] : '';
        //拼接
        url+=`&${i}=${encodeURIComponent(value)}`;
    }
        return url ? url.substring(1) : ''
}    

我们的jsonp分为2种部分,一种是url接口,一种是参数,才能发送正确的请求。

那么我们在param这个方法中主要做一个参数循环的作用,这里把具体的参数转换为url编码附给了拼接url,然后返回一个url作为jsonp函数用

传入的url参数我们拼接data参数,然后通过Promise来调用我们的jsonp的库

然后我们在api下新建一个js文件,是存放我们的推荐页面抓取数据的js

然后在这页面进行数据传输

值得注意的是我们定义url的参数的时候,有很多可重复的参数,比如说编码和option jsonpcallback等等,所以我们将这些公共的数据抽取出来放在config.js中

export const commonParams = {

    g_tk:5381,
    inCharset : 'utf-8',
    outCharset : 'utf-8',
    notice : 0,
    format : 'jsonp'

}

    //jsonp需要的option
    export const options = {
        param : "jsonpCallback"
    }

//错误异常的语义化常量

export const ERR_OK = 0;

在抓取的json中,如果为0就是抓取成功,所以定义的语义化常量是0

然后我们到推荐页面的apijs中去调用方法

//导入jsonp
import jsonp from 'common/js/jsonp'
//读取公共配置
import {commonParams,options} from 'api/config'

export function getrecommend(){

//定义url接口
const url='https://c.y.qq.com/musichall/fcgi-bin/fcg_yqqhomepagerecommend.fcg'
//拼接url后的参数,用es6的语法assign塞进去
const data=Object.assign({},commonParams,{
platform: 'h5',
uin : 0,
needNewCode : 1
})
return jsonp(url,data,options);

}

一切都是那么简单,之所以我第一次写的时候很懵逼,等到整理笔记的时候才发现原来是这样,所以要适应这样的封装环境,很不错nice

然后我们去组件中调用

created(){
//加载执行方法
this._getData();
},
methods:{
_getData(){
getrecommend().then((val) => {
if(val.code===ERR_OK){
this.recommend=val.data.slider;
}
})
}
}

这样就调用成功了!!

然后我们把它遍历出来即可。

下载.jpg

在进行准备工作之前,我认为从这次的项目开始将挑选非常精致的代码来分享自己的笔记,让自己能够时时刻刻的复习知识

首先我们进行cli快速构建项目,这次项目依旧是一个移动wap页面,是做一个音乐app,所以我们将引入我们所需要的东西。

首先我们必须引入的fastclick,还有我们的css编译器,stylus和其驱动加载器

还有

"babel-polyfill": "^6.26.0",
"babel-runtime": "^6.26.0",

安装成功后我们将骨架进行分析整理

首先我们看一下我们的目录

api //存放一些和数据相关的接口js
assets
base //存放一些封装的组件
common //存放一些css和js的资源
components
router
store //vuex存放的仓库

然后我们这次项目定义的css比较多,一些公用的样式库我们都选择用styl来存储

然后我们的准备工作都完毕了

hello,好久不见了,最近博客很久没更新了,因为一直在学习新的东西,但是很久没给大家分享一些东西,vue的第一个项目完成了,我已经得到了很多的开发经验,然后这一篇文章教大家怎么玩这个github,如果你是一名程序员或者在校学生,没有听过这个git或者github,那么我推荐你看完这个教程久立马自己动手跟我一起来搭建github,属于自己的代码仓库。

首先老沈在这里简要介绍一下,这个github到底是干什么的,github是git环境提供支持,是一个代码托管仓库,在官网上可以下载其他人的开源项目来提高自己的技术,也可以将自己写的轮子分享出去,话不多说,我们来一睹为快吧!

第一步:安装git,这个git安装跟office安装很一样,百度以后下载安装包,然后点击next下一步就好了,安装成功以后,恭喜你已经成功一半了。

第二步:我们打开github官网,注册一个账号,并且创建一个自己的仓库,如下图

QQ截图20181013225006.png

第三步:创建之后,我们可以看到下面的界面,提供了2种上传的方式,一个是http一个是ssh,我们选择http

博客图片

第四步:然后来到我们的本地,选择一个项目文件夹,然后右键,你会看到git Bush here,点击它出现命令窗口,然后做一些操作

QQ截图20181013225540.png

中文解释:

1.初始化项目
2.加入项目 git add . 这里的.不要忘记写,意思是把文件夹里的所有文件提交到队列中
3.""引号里面写你的项目描述
4.后面的http地址换成你的仓库地址
5.然后把队列push出去,然后按照要求输入github的账号和密码,然后等待提交成功即可。

第五步:然后看到自己的github中有项目代码了,成功!