seho 发布的文章

经过了一段时间的学习,对ssm已经有了初步的认识,然后也坎坷的做出了增删改查,实际上放假都是在休息或者游戏,所以憋了2天才写出来。

我觉得一个简单的增删改查是满足不了大家的,所以我会尽可能地详细的讲,也会让大家注意我踩的坑,跟着这篇文章,我相信你能快速的搭建ssm框架并且完成相应的业务需求。

业务没有设计maven,所以我们创建xml等操作都是手动完成。

1.准备jar包,ssm的包以及jstl,还有分页插件pagehelper以及sql解释jar。

QQ截图20181105182645.png

注意:jar包没有截图全部,具体的jar下载直接在文章末尾的github上直接下载

2.创建我们的web工程,目录结构如下

QQ截图20181105182808.png

注释:

action:springmvc控制开发
mapping:mybaties映射接口和文件
pojo:业务实体类
service:业务实现类

创建spring,springmvc,mybaties,数据库连接文件,日志文件

spring:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd ">

<!--读取数据库配置文件 -->
<context:property-placeholder location="classpath:db.properties"/>

<!-- 数据库连接池 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
    destroy-method="close">
    <property name="driverClassName" value="${jdbc.driver}" />
    <property name="url" value="${jdbc.url}" />
    <property name="username" value="${jdbc.username}" />
    <property name="password" value="${jdbc.password}" />
    <property name="maxActive" value="10" />
    <property name="maxIdle" value="5" />
</bean>

<!-- Mybatis的工厂 -->
<bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <!-- 1) 核心配置文件的位置 -->
    <property name="configLocation" value="classpath:mybaties.config.xml"/>
    <!-- 2)扫描指定目录下的所有Mapper.xml -->
    <property name="mapperLocations" value="classpath:com/ssmall/mapping/*.xml"></property>
</bean>

<!-- 配置自动扫描的包 -->
<context:component-scan base-package="com">


<!-- 扫描时跳过 @Controller 注解的JAVA类(控制器) -->
<context:exclude-filter type="annotation"
        expression="org.springframework.stereotype.Controller" />
</context:component-scan>


<!-- 注解事务 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>


<!-- 开启注解 -->
<tx:annotation-driven transaction-manager="transactionManager"/>

springmvc:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
    http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">

<!-- 配置自定扫描的包 -->
<context:component-scan base-package="com" />

<mvc:annotation-driven />
<!-- 配置视图解析器: 如何把 handler 方法返回值解析为实际的物理视图 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/views/"></property>
    <property name="suffix" value=".jsp"></property>
</bean>


<!-- 配置 MultipartResolver -->
<bean id="multipartResolver"
    class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <property name="defaultEncoding" value="UTF-8"></property>
    <property name="maxUploadSize" value="1024000"></property>    
</bean>    

myabites:

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">

<!-- 类型别名是为 Java 类型设置一个短的名字。它只和 XML 配置有关,存在的意义仅在于用来减少类完全限定名的冗余 -->
<typeAliases>
    <typeAlias alias="User" type="com.ssmall.pojo.Userpojo" />
</typeAliases>

<!-- 配置分页插件 -->
<plugins>
    <plugin interceptor="com.github.pagehelper.PageHelper">
        <!-- 设置数据库类型Oracle,MySQL,MarinDBName,SQLite,PostareSQL六种数据库 -->
        <property name="dialect" value="mysql" />
    </plugin>
</plugins>

db.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/sys?characterEncoding=utf-8
jdbc.username=root
jdbc.password=swq891012

web.xml:

<!--?xml version="1.0" encoding="UTF-8"?-->

<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemalocation="http://java.sun.com/xml/ns/javaee

http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<!-- 1.spring容器 listener -->
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
 
<!-- 2.springmvc servlet -->
<servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:springmvc.xml</param-value>
    </init-param>
</servlet>
 
<servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>
  
<!-- 3.spring 中文乱码 filter -->
<!-- 编码过滤器,解决中文乱码 -->
<filter>
    <filter-name>SpringEncoding</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>utf-8</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>SpringEncoding</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
 

<welcome-file>index.jsp</welcome-file>


3.开发mybaties映射接口和mybaties映射xml

接口(所属包mapping):

package com.ssmall.mapping;

import java.util.List;

import com.ssmall.pojo.Userpojo;

public interface UserMapping {

public List<Userpojo> getAll();
public Userpojo getUser(Integer id);
public boolean deleteById(Integer id);
public boolean add(Userpojo user);
public boolean update(Userpojo user);

}

mybaites映射

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- 为这个mapper指定一个唯一的namespace,namespace的值习惯上设置成包名+sql映射文件名,这样就能够保证namespace的值是唯一的

例如namespace="me.gacl.mapping.userMapper"就是me.gacl.mapping(包名)+userMapper(userMapper.xml文件去除后缀) -->

<!-- 在select标签中编写查询的SQL语句, 设置select标签的id属性为getUser,id属性值必须是唯一的,不能够重复 使用parameterType属性指明查询时使用的参数类型,resultType属性指明查询返回的结果集类型 
    resultType="me.gacl.domain.User"就表示将查询结果封装成一个User类的对象返回 User类就是users表所对应的实体类 -->
<!-- 根据id查询得到一个user对象 -->

<select id="getUser" parameterType="int" resultType="com.ssmall.pojo.Userpojo">
    select * from t_user where id=#{id}
</select>
<select id="getAll" resultType="com.ssmall.pojo.Userpojo">
    select * from t_user
</select>
<delete id="deleteById" parameterType="int">
    delete from t_user where id=#{id}
</delete>
<insert id="add">
    insert into t_user(username,password,account) values
    (#{username},#{password},#{account})
</insert>
<update id="update">
    update t_user set username=#{username},password=#{password},account=#{account} where id=#{id}
</update>

注意:这边的查询语句由于使用了分页插件pageHelper,所以无需做变化
1)id要与接口的方法名对应上,并且放在一个包下,命名空间namespace是唯一的,所以建议写映射包名+类名的写法(写的是接口)
2)mybaties映射xml文件名和映射接口文件名要一样,后缀不同即可

4.开发dao层,service层

dao层(接口省略):

package com.ssmall.dao;

import java.util.List;

import javax.annotation.Resource;

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import org.springframework.stereotype.Repository;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.ssmall.mapping.UserMapping;
import com.ssmall.pojo.Userpojo;

@Repository
public class IPublicDaoImpl extends SqlSessionDaoSupport implements PublicDao{


/*super.setSqlSessionFactory(sessionFactory):调用父类方法,将sqlsessionfactory注入进去*/
@Resource
public void setSessionFactory(SqlSessionFactory sqlSessionFactory) {
    super.setSqlSessionFactory(sqlSessionFactory);
}

/**
 * 公共dao层方法
 */
public Userpojo get(int id) {
    
    UserMapping mapper = this.getSqlSession().getMapper(UserMapping.class);
    Userpojo user = mapper.getUser(id);
    return user;
}


//查询数量
public static final int PAGE_SHOW_NUMBER=5;
@Override
public PageInfo<Userpojo> getAll(Integer index) {
    UserMapping mapper = this.getSqlSession().getMapper(UserMapping.class);
    PageHelper.startPage(index, PAGE_SHOW_NUMBER);
    List<Userpojo> all =mapper.getAll();
    //用PageInfo对结果进行包装
    PageInfo<Userpojo> pageInfo = new PageInfo<Userpojo>(all);
    return pageInfo;
}

//查询数据的总页数


@Override
public boolean deleteById(Integer id) {
    UserMapping mapper = this.getSqlSession().getMapper(UserMapping.class);
    return mapper.deleteById(id);
}

@Override
public boolean addUser(Userpojo user) {
    UserMapping mapper = this.getSqlSession().getMapper(UserMapping.class);
    return mapper.add(user);
}

@Override
public boolean updateUser(Userpojo user) {
    UserMapping mapper = this.getSqlSession().getMapper(UserMapping.class);
    return mapper.update(user);
}

}

注意:在我们的查询方法中,返回的不是List集合,而是分页插件提供的类PageInfo,我们通过映射接口取得list可以通过PageInfo的方法转换进行包装,在PageInfo类中有许多我们常用的方法,比如数据库的分页页数,长度等等,非常有利于我们开发,所以在查询的这个方法中我们定义了常量,这个常量就是一页显示多少条,第一个参数index,是第几页

service层:

package com.ssmall.service;

import java.util.List;

import javax.annotation.Resource;

import org.springframework.stereotype.Service;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.ssmall.dao.PublicDao;
import com.ssmall.pojo.Userpojo;

@Service
public class IUserServiceImpl implements UserService {

@Resource
private PublicDao dao;

//根据ID查询单条
public Userpojo get(Integer id) {
    
    return this.dao.get(id);
}



//查询全部
public PageInfo<Userpojo> getAll(Integer pageNum) {
    return this.dao.getAll(pageNum);
}


//删除单条
public boolean deleteById(Integer id) {
    
    return this.dao.deleteById(id);
}


@Override
public boolean addUser(Userpojo user) {
    
    return this.dao.addUser(user);
}


@Override
public boolean updateUser(Userpojo user) {
    
    return this.dao.updateUser(user);
}
    

}

action层:

package com.ssmall.action;

import java.util.List;

import javax.annotation.Resource;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import com.github.pagehelper.PageInfo;
import com.ssmall.pojo.Userpojo;
import com.ssmall.service.UserService;

@Controller
public class UserAction {

@Resource
private UserService userService;

/**
 * 查询所有信息
 * 
 * @param null
 * @return
 */
@RequestMapping("/user/all/{index}")
public ModelAndView getUserAll(@PathVariable("index") Integer index) {
    ModelAndView model = new ModelAndView("list");
    PageInfo<Userpojo> all = userService.getAll(index);
    List<Userpojo> list = all.getList();
    model.addObject("allList", list);
    //存储当前索引在域中
    model.addObject("index", index);
    //计算能分多少页
    int pages = all.getPages();
    model.addObject("lastnum", pages);
    return model;
}

/**
 * 根据id查询单条信息
 * 
 * @param id
 * @return
 */
@RequestMapping("/user/get/{id}")
public String getUserById(@PathVariable("id") Integer id) {
    Userpojo userpojo = userService.get(id);
    return "success";
}

/**
 * 根据id删除
 * 
 * @param id
 * @return
 */
@RequestMapping("/deleteById")
public String DeleteById(@RequestParam("id") Integer id) {
    // 执行删除
    boolean deleteById = userService.deleteById(id);
    // 删除成功后查询
    return "redirect:/user/all/1";
}

/**
 * 新增用户
 * 
 * @param user
 * @return
 */
@RequestMapping("/user/addUser")
public String addUser(Userpojo user) {
    userService.addUser(user);
    return "redirect:/user/all";
}

// 新增用户的跳转方法
@RequestMapping("/user/addready")
public String addReady(Model model) {
    model.addAttribute("itemForm", "form");
    // 添加用户之后,在请求域中添加一个判断添加或者修改页面的依据
    // 根据这个依据,可以通过jstl共用form.jsp页面
    return "form";
}

/**
 * 修改用户
 * 
 * @param user
 * @return
 */
@RequestMapping("/update")
public String update(Userpojo user){
    userService.updateUser(user);
    return "redirect:/user/all/1";
}
@RequestMapping("/updateById")
public String updateReady(@RequestParam("id") Integer id,Model model) {
    Userpojo userpojo = userService.get(id);
    model.addAttribute("userlist", userpojo);
    return "form";
}

}

注意:
主要难点还是查询的方法,只要理解了查询的方法,其他的增删改都是非常之简单。

主要的是我们的jsp页面,我们大量的用到了jsp页面,在WEB-INF/views下很多jsp,其中我们的增加的表单和修改的表单都是form.jsp,我们通过action设置的请求域值来区分当前是增加操作还是修改操作。

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<base href="<%=basePath%>">

<title>My JSP 'form.jsp' starting page</title>

<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">    
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->

    <c:if test="${itemForm != null}">
      <form action="user/addUser" method="post">
  </c:if>
  <c:if test="${itemForm == null}">
      <form action="update" method="post">
  </c:if>
       <input type="hidden" name="id" value="${userlist.id}">
        用户名:<input type="text" name="username" value="${userlist.username}">
        <br>
        密码:<input type="password" name="password" value="${userlist.password}">
        <br>
       详情:<input type="text" name="account" value="${userlist.account}">
       <br>
       
       <c:if test="${itemForm != null}">
           <input type="submit" value="添加">
       </c:if>
       
       <c:if test="${itemForm == null}">
           <input type="submit" value="修改">
       </c:if>
       
  </form>


下面就是我们的list展示页面,上一页和下一页,都是利用el表达式来编码,也巧妙地用了if判断,来在首页隐藏上一页,末页隐藏下一页避免了逻辑错误

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%

String path = request.getContextPath();
String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort()
        + path + "/";

%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">


list






<!--

<link rel="stylesheet" type="text/css" href="styles.css">
-->

<a href="user/addready">添加用户</a>
<table>
 <thead>
   <tr>
     <th>id</th>
     <th>用户</th>
     <th>密码</th>
     <th>详情</th>
     <th>操作</th>
    </tr>
 </thead>
 <tbody>
  <c:forEach items="${requestScope.allList}" var="list">
     <tr>
         <c:if test="${requestScope.allList==''}">
             <td>暂无记录</td>
         </c:if>
         <td>${list.id}</td>
         <td>${list.username}</td>
         <td>${list.password}</td>
         <td>${list.account}</td>
         <td><a href="deleteById?id=${list.id}">删除</a></td>
         <td><a href="updateById?id=${list.id}">修改</a></td>
     </tr>
     </c:forEach>
 </tbody>
</table>
<a href="user/all/1">首页</a>
<c:if test="${index != 1}">
    <a href="user/all/${index-1}">上一页</a>
</c:if>
<c:if test="${index != lastnum}">
    <a href="user/all/${index+1}">下一页</a>
</c:if>
    <a href="user/all/${lastnum}">末页</a>


好了,我们的整个整合就结束了:

源码下载地址,bug都测试完了,没有任何问题,欢迎下载demo:

https://github.com/1018715564/ssm-CRUD 下载地址

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中有项目代码了,成功!