JoyLau's Blog

JoyLau 的技术学习与思考

  • 今天在浏览网站时,http://ai.baidu.com/ ,看到一个CSS3的效果:将鼠标放到图片上,图片会稍稍方大一点,当时很好奇是怎么做的
  • 当即百度了一下,有人用js做的,有人用css做的,首先js做的肯定不够好,一看效果就是css3的效果
  • 于是自己查看了下 这块 div 的效果
  • 将压缩的css展开来
  • 原来是这样的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 鼠标移上去各浏览器的延时效果
.solution-img {
height: 100%;
-webkit-transform-origin: 50% 50%;
-moz-transform-origin: 50% 50%;
-ms-transform-origin: 50% 50%;
transform-origin: 50% 50%;
-webkit-transition: -webkit-transform .2s;
transition: -webkit-transform .2s;
-moz-transition: transform .2s,-moz-transform .2s;
transition: transform .2s;
transition: transform .2s,-webkit-transform .2s,-moz-transform .2s
}

# 鼠标移上去各浏览器的放大倍数
.solution-item:hover .solution-img {
-webkit-transform: scale(1.1);
-moz-transform: scale(1.1);
-ms-transform: scale(1.1);
transform: scale(1.1)
}

将 Scala 依赖 scala-library 和插件 scala-maven-plugin 添加到 Maven 项目中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
    <dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
<version>2.11.7</version>
</dependency>



<plugin>
<groupId>net.alchim31.maven</groupId>
<artifactId>scala-maven-plugin</artifactId>
<executions>
<execution>
<id>scala-compile-first</id>
<phase>process-resources</phase>
<goals>
<goal>add-source</goal>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>scala-test-compile</id>
<phase>process-test-resources</phase>
<goals>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
</plugin>

更新完上面的内容之后,你需要等待Maven下载完所有的依赖。

安装IDEA插件 Scala
现在可以在Java工程中使用Scala代码了
创建新的文件夹src/main/scala;
Scala Maven插件将会识别这些目录,并且编译其中的Scala文件:

1
2
3
4
5
6
object BooksProcessor {
def filterByAuthor(author: String)(implicit books: util.ArrayList[Book]) = {
books.filter(book => book.getAuthor == author)
}

}

今天没有图片

在做单系统的情况下,我还是比较喜欢使用Google 的 Guava 来做缓存的,结合 SpringBoot 使用非常简单 :

1
2
3
4
5
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>23.0</version>
</dependency>

再配置 yml :

1
2
3
4
5
6
spirng:
cache:
type: guava
cache-names: api_cache
guava:
spec: maximumSize=300,expireAfterWrite=2m

上述配置了一个 缓存名为 api_cache 的缓存 ,最大数量为300,超时时间为2分钟

接下来,在类中使用注解 @CacheConfig(cacheNames = “api_cache”) 来配置整个类的配置
@Cacheable() 注解在方法上来 开启方法的注解

使用很透明

今天再次使用时发现guava.spec提示过期了,查了下文档,文档原话是这样说的:

@Deprecated
@DeprecatedConfigurationProperty(
reason = “Caffeine will supersede the Guava support in Spring Boot 2.0”,
replacement = “spring.cache.caffeine.spec”
)

原来,在SpringBoot2.0中推荐使用Caffeine,表达式就是spring.cache.caffeine.spec

更改的方法很简单,改下依赖包,换个配置名,又可以愉快的额使用了:

1
2
3
4
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>

更新配置:

1
2
3
4
5
6
spirng:
cache:
type: caffeine
cache-names: api_cache
caffeine:
spec: maximumSize=300,expireAfterWrite=2m

通常SpringBoot默认的keyGenerator 是SimpleKeyGenerator,这个策略是以参数作为key值,如果参数为空的,就会返回SimpleKey[]字符串,这对于很多无参的方法的就有问题了
我们需要重新这个keyGenerator,实现 org.springframework.cache.interceptor.keyGenerator 这个接口即可,将key值设置为类名+方法名+参数名,这样就不会冲突了

1
2
3
4
5
6
7
8
9
10
11
12
@Bean
public KeyGenerator caffeineKeyGenerator() {
return (target, method, params) -> {
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getName());
sb.append(method.getName());
for (Object obj : params) {
sb.append(obj.toString());
}
return sb.toString();
};
}

感觉无缝切换,继续使用吧!!!

制作背景

  • 有时候宅在家里实在不知道玩什么游戏
  • 英雄联盟都玩烂了
  • 哥们提议玩红警
  • 红警是单机啊,一个人玩另一个人怎么办,一个人打电脑有啥意思 =_=|
  • 找对战平台啊,首先下载安装了红警玩家自制的战网对战平台
  • 我个人电脑从来不安装杀毒软件,Windows Defender 一直报毒搞个不停
  • 战网的平台体验也很不好,消息弹个不停,感觉像广告软件
  • 后来换了腾讯对战平台,进入红警起个名字老说含有敏感信息,结果起了半个小时,MDZZ
  • 决定自己了解下对战平台的原理,打算自己写个简单好用的玩

原理

通过socket hook + udp,针对war3来说,支持tcp,先在本地通过hook模拟建立tcp连接,然后将tcp的数据转成外网udp数据发给外网服务器转发给其他客户端,客户端接收到后通过本地tcp
模拟连接转发到游戏进程。这个过程中通过中转服务器协助进行p2p。
JoyGame-zhihu

上面是知乎上的回答
用我自己的话说就是

使用JoyGameClient客户端,在本地创建了一个虚拟的IP地址,每一个客户端通过连接远程服务器形成了一个虚拟局域网,这样在游戏的【局域网】选择项中就能找到彼此,这样自然一方创建一个游戏,其他人都可以加入进来了就能愉快的玩耍了。底层通信使用的就是TCP和UDP连接,在同一个房间的玩家都会向服务器发送和下载游戏的实时数据。服务器会向房间里的玩家的客户端上转发数据包,这样就间接形成了一个局域网,就能在一起玩游戏啦。

使用

  • 解压,打开JoyGameClient.exe
  • 选择中间的网络服务器,因为你本地肯定是没有服务端的,只能连接远程部署好的服务器
    JoyGame-Login
  • 没有账号,就注册一个账号,注册成功后登录平台
    JoyGame-Login
  • 这是主界面
  • 接下来进入一个你想玩的游戏的房间
  • 设置你的游戏启动主程序
    JoyGame-Login
  • 下面可以设置启动时游戏的参数,比如玩红警时,加入参数 -win,可以窗口启动
  • 之后点启动,进入游戏就可找到在一个房间的小伙伴了
  • 使用都很简单,看一遍就会

特色

  • 可以聊天,发表情,可以加好友。。。额,这些好像没有什么特色
    JoyGame-Login

我想说

如果你想玩玩以前的一些怀旧游戏,或者你想看看该平台是如何操作实现联机的,还等什么,跟着Joy一起来玩吧
私聊我可以给你开个 VIP 、等级直接升到将军哦!虽然没什么用,纯粹装*

下载

一款将 SpringBoot 项目做成Windows Service 的 Maven 插件

包括但不限于 SpringBoot ,任何打成 java jar 包运行的 Maven 项目都可以使用

编写初衷

  • 公司有个项目
  • Java 部分的全部使用的是SpringBoot
  • 该项目的部署环境是 Windows
  • 公司想把 各个 SpringBoot 的模块托管一下
  • 托管的使用方式要简单,易用,测试在打包部署的时候要很容易上手
  • 期间尝试过 Spring Boot Admin 和 Jenkins,都说不好用…
  • 于是就想着 将Spring Boot 的服务制作成 Windows 服务,这样基本上会操作电脑的人都会使用了,够简单易用的了吧
  • 花了一上午时间将其中一个 Spring Boot 模块制作成了 Windows Service
  • 发现再做其他的模块的时候,很多工作都是重复的,心想着能够将这个功能提取出来就好了
  • 于是就写了这个 Maven 插件

使用演示地址:

怎么使用?

  • 使用方法很简单,和普通的 Maven 插件一样使用就可以了,如下
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <plugins>
    <plugin>
    <groupId>cn.joylau.code</groupId>
    <artifactId>joylau-springboot-daemon-windows</artifactId>
    <version>1.0.RELEASE</version>
    <executions>
    <execution>
    <id>make-win-service</id>
    <phase>package</phase>
    <goals>
    <goal>make-win-service</goal>
    </goals>
    </execution>
    </executions>
    </plugin>
    </plugins>

注意:

  1. 这里的 phase 写的是 package,意思是该插件在 mvn package 的时候调用,你也可以根据不同的需求来更改,比如 install, test等等
  2. goal 写 make-win-service 就可以了,不需要改动
  3. 一般情况下我们的SpringBoot项目会有其他父项目,这时打包会使用 spring-boot-maven-plugin 插件的 repackage,这样的情况的话,请将该插件放置最后面,否则服务运行的话将提示没有主属性
  • 在你的项目中按照以上的方式引入插件后,现在可以 打包了
    1
    mvn package

打包过程中,看到如下日志信息,便制作成功了:
joylau-springboot-daemon-windows-package-info

此时,在你项目的target目录下会生成一个 jar 包名字 一样的压缩包
进入文件夹,解压这个压缩包,你会看见如下内容的文件
joylau-springboot-daemon-windows-package-file
注意:

  1. 5个 bat 文件,请右键以管理员的身份运行
  2. 各文件的文件名无特殊情况,不需要修改
  3. 一旦安装成了 Windows 服务,目录下的文件就不要移动了
  4. 命令运行时,可能会提示安装.NET,安装完成就可运行命令了,不过现在大部分的 Windows 服务器或者个人电脑都会默认安装了.NET,没有的话启用一下就好了,如下图:
    joylau-springboot-daemon-windows-.NET
  5. 运行各个命令是注意提示信息,例如卸载完服务都的状态为NonExistent,刚安装完服务后的状态为Stopped,服务成功启动的状态为Started…等等
    joylau-springboot-daemon-windows-service-status

扩展参数

想要在服务启动时添加自定义参数,如 SpringBoot 的配置参数或者 JMV 参数?
像如下配置即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<plugin>
<groupId>cn.joylau.code</groupId>
<artifactId>joylau-springboot-daemon-windows</artifactId>
<version>1.0.RELEASE</version>
<executions>
<execution>
<id>make-win-service</id>
<phase>package</phase>
<goals>
<goal>make-win-service</goal>
</goals>
</execution>
</executions>
<configuration>
<arguments>
<argument>--server.port=9090</argument>
</arguments>
</configuration>
</plugin>

上面配置了一个 Spring Boot 应用的启动端口9090

使用注意

  • 打包使用过程中需要联网
  • 文档中有些图片可能看不到,再次刷新下页面就可以
  • 服务的id为artifactId,服务的名称为artifactId+version,服务的描述为description

GitHub 地址

源码已开源,地址 : https://github.com/JoyLau/joylau-springboot-daemon-windows

前言

效果展示

JoyMusic-NoReferer
JoyMusic-NoReferer
JoyMusic-NoReferer

在线地址

问题说明

  • 为什么解析的 MV 地址无法直接播放,在上一篇文章上我也说明了
  • 相应的解决办法我在上一篇文章上也说明了
  • 这样的方法有很明显的缺点,在上一篇文章也说明了
  • 这个方法只能实现播放的功能,但是距离完美或者说好的展示效果来说,并不满意
  • 我自己就很不满意

开始动手

先说下我是怎么解决的

  • 解决的方法还是一样:去除referer
  • 同时去除了原来使用的jPlayer播放器,因为这个播放器在移动设备下的表现并不是很好,现在改为浏览器自带的视频播放空控件
  • 这个东西就没有什么兼容性了,只要IE10 以上支持HTML5 的都可以观看
  • 正如上面我截图所示的那样,我使用的是 Safari 浏览器,表现效果还是很好的
  • 同时也加入了一些比较棒的小功能:比如下滑看评论的时候,会出现小视频框在右下角
  • 我个人是比较喜欢看评论的,一些音乐或者 MV 页面打开后并不是先听或者先看,都是翻到下面看看评论
  • 这也正是我喜欢网易云音乐的原因之一,网易云音乐的评论大部分都很精彩,有时候听歌不如看评论

现在是怎么在页面上去除referer的?

  • 动态生成一个iframe,我本身是比较反对使用iframe的,因为以前使用的extjs使用的多了,都用吐了,而且性能还不是很好
  • 但是在这里它可就起了大作用了
  • iframe 里的页面就放一个<video>
  • iframe 的宽度高度及video的宽度高度都要调节好,其实这一步花了我不少时间,因为并不是所有的MV宽高的比例是一样的
  • iframe 的src不能直接写MV的MP4地址,因为那样的话就没有作用了
  • 在src里写js脚本动态生成html页面,页面里面包括的之前提到的video
  • 使用这种方法就可将网站的referer去除掉
  • 这就类似于直接在浏览器的地址栏上输入MP4的地址然后播放
  • 在前一篇的文章分析中,我们知道,这种方法是可以播放的

编写代码

动态渲染iframe:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
return '<iframe \
style="border 1px solid #ff0000" \
scrolling="no" \
frameborder="no" \
allowtransparency="true" ' +
/*-- Adding style attribute --*/
objectToHtmlAttributes( iframeAttributes ) +
'id="' + id + '" ' +
' src="javascript:\'\
<!doctype html>\
<html>\
<head>\
<meta http-equiv=\\\'Content-Type\\\'; content=\\\'text/html\\\'; charset=\\\'utf-8\\\'>\
<style>*{margin:0;padding:0;border:0;}</style>\
</head>' +
/*-- Function to adapt iframe's size to content's size --*/
'<script>\
function resizeWindow() {\
var elems = document.getElementsByTagName(\\\'*\\\'),\
width = parent.document.getElementById(\\\'panel-c\\\').offsetWidth-7,\
height = 0,\
first = document.body.firstChild,\
elem;\
if (first.offsetHeight && first.offsetWidth) {\
width = first.offsetWidth;\
height = first.offsetHeight;\
} else {\
for (var i in elems) {\
elem = elems[i];\
if (!elem.offsetWidth) {\
continue;\
}\
width = Math.max(elem.offsetWidth, width);\
height = Math.max(elem.offsetHeight, height);\
}\
}\
var ifr = parent.document.getElementById(\\\'' + id + '\\\');\
ifr.height = height;\
ifr.width = width;\
};\
</script>' +
'<body onload=\\\'resizeWindow()\\\'>\' + decodeURIComponent(\'' +
/*-- Content --*/
encodeURIComponent(html) +
'\') +\'</body></html>\'"></iframe>';

注意这里的反斜杠不要去掉,是用来转义的,代码的样式虽然丑了点,但是并不影响使用

  • 这里面有个方法是encodeURIComponent(html),这个是转义了video里面的url链接
  • 在iframe的body加载完成后会调用resizeWindow()函数自适应下iframe的宽高
  • html里面写的就是要放入iframe的body里的代码,这里我们放的肯定是video
  • 于是,可以将上述代码封装成一个函数,在父页面是直接调用
  • 封装的时候我们还可以传一些参数,比如上面的iframe的初始的宽高,style,scrolling,frameborder等等

扩展一下

  • 这个方式使用的是video
  • 那么<img>呢?现在有些网站的图片也是经过了防盗链处理,这种方法也是可以实现去掉referer,直接访问图片的额

欢迎大家来看看试试看!😘 http://music.joylau.cn (当前版本 v1.5)

前言

效果展示

在线地址

开始

需要准备

  • 这次要解析的是 网易云音乐的 MV
  • 需要准备的解析的有
  • 获取 MV 信息列表
  • 获取 MV 详细信息
  • 获取 MV 播放地址
  • 在线播放 MV
  • 获取 MV 排行榜
  • 获取最新 MV

说明

  • 大部分解析提供的接口都和我以前2篇文章类似,之前的文章有分析过,这里就不再多说了
  • 这里重点说明下 MV 的播放问题

关于 MV 的播放

  • 解析 MV 详细信息,可获得 MV 的真实播放的 MP4 的地址
  • 但是这个地址,网易云做了防盗链处理
  • 什么是防盗链?
  • 一般情况下,我的资源文件,比如 图片, css,js,视频,我们自己放到服务器上可以直接引用
  • 同样的道理,别人可以访问你的服务器,也可以直接引用
  • 那么,不想被别人引用怎么办呢?
  • 这就引申出了防盗链的操作
  • 最常见的防盗链的处理就是加上 referer识别,就是来源网址信息
  • referer 其实是个错误的拼写,这个就是有历史原因了,以前的开发人员在定义这个属性的时候,把这个单词写错了,后来没有人注意到,一直使用到他作为标准
  • 后来,也没有人去特意改他了,就这么用着吧
  • 这个是简单防盗链处理
  • 还有更复杂的,比如 js 加密路径信息,每次请求路径都会变化,这个就复杂了
  • 很幸运,网易云的 MV 采用的就是 referer 的识别方式
  • 那么就有相应的破解方法了

关于 referer

  • MP4 的地址在浏览器地址栏直接粘过去是可以播放的,但是由其他网站跳进去的则不能访问,因为带进了 rerferer
  • 那么,要做的就是去除 请求的 rerferer
  • 我找了很多资料也尝试了很多次,想在浏览器端把 rerferer 去除掉,基本是实现不了的,如果你实现在页面里单独请求 mp4 地址时不带referer, 请联系我
  • 那么要做的就是在服务端操作了
  • 在服务端操作很简单,就是伪造头信息进行请求

这个是带 referer 的请求,被网易云直接拒绝了

joymusic-mv-referer

这个是复制地址到地址栏,则可以直接播放

joymusic-mv-no-referer

服务单去除 referer

  • 严格来说不能说去除 refere,我们需要将原本我们自己服务器的 referer 修改为网易云服务器的 referer

Java 版

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public void playMV(HttpServletResponse res, String mvurl) throws IOException {
if (StringUtils.isEmpty(mvurl)){
return;
}
res.setContentType("video/mpeg4; charset=utf-8");
URLConnection connection = new URL(mvurl).openConnection();
connection.setRequestProperty("referer", "http://music.163.com/");
connection.setRequestProperty("cookie", "appver=1.5.0.75771;");
connection.connect();
InputStream is = connection.getInputStream();
OutputStream os = res.getOutputStream();
byte bf[] = new byte[2048];
int length;
try {
while ((length = is.read(bf)) > 0) {
os.write(bf, 0, length);
}
} catch (IOException e) {
is.close();
os.close();
return;
}
is.close();
os.close();
}

解释:

  1. 首先我们请求的资源不是本地的资源,是存储在其他服务器上的,这里用到的是URL
  2. 这里我们需要设置 referer 和 cookie,结合前面使用的 URL, 这里使用的是URLConnection
  3. 后面的就很好理解了,相当于做了一个管道,将读取的文件流原封不动的通过Response返回给调用者
  4. 不要忘了设置 setContentType 为 MP4 的格式

nodejs 版

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const express = require("express");
const router = express();
const request = require("request");

router.get("/", (req, res) => {
const url = req.query.url;
const headers = {
"Referer": "http://music.163.com/",
"Cookie": "appver=1.5.0.75771;",
'Content-Type': 'video/mp4',
'Location': url
};
const options = {
header: headers,
url: url
};
request(options).on('error', err => {
res.send({ err })
}).pipe(res)
});

module.exports = router;

解释:
和上面的 Java 版代码是一个意思,主要是 pipe 流管道将文件流返回给调用者

功能完成

  • 那么这样解决了 MP4 地址防盗链的问题

缺点

  • 不足之处也暴露了
  • 首先这段代码必须部署到服务端
  • 部署到服务端就需要服务器去拉去 MV 的流信息,这无疑给服务器增加过多的流量压力
  • 其次,由于使用的流传输,这个 MP4 的播放是不支持快进操作的

有个简单的解决方式

  • 在 html5 之后,想去除 referer 信息, a标签有个属性 rel
  • rel="noreferrer" 即可在 a 标签的 href 的链接上去除 referer信息
  • 这一属性已被我使用在播放器的右下角的一个小飞机的按钮上
  • 点击小飞机按钮就可以直接看 MV 视频了,流量走的是网易云的CDN,不再试自己的服务器

joymusic-mv-no-referer-href

不完美

  • 总感觉这个解决不够完美
  • 如果你看到这篇文章能有更好的解决办法,请联系我

欢迎大家来看看试试看!😘 http://music.joylau.cn (当前版本 v1.4)

前言

效果展示

JoyMedia - Search

在线地址

解释

  • 正如文章图片那样,在搜索框中输入想听的音乐/歌手/专辑
  • 在输入过程中及输入完成后,显示搜索结果的列表供用户选择

材料

  • REST 接口
  • jquery-autocomplete插件

优美的开始

准备工作

  • 引入插件 css: jquery.autocomplete.css
  • 引入插件 js : jquery.autocomplete.min.js
  • 写一个数据返回的 REST 接口

开始操作

  • 定义搜索的 input 的 id 值
1
2
3
4
5
6
7
8
9
10
<div class="navbar-form navbar-left input-s-lg m-t m-l-n-xs hidden-xs">
<div class="form-group" style="display: inline">
<div class="input-group">
<span class="input-group-btn">
<button class="btn btn-sm bg-white btn-icon rounded"><i class="fa fa-search"></i></button>
</span>
<input id="keywords" type="text" class="form-control input-sm no-border rounded" placeholder="搜索 单曲/歌手/专辑...">
</div>
</div>
</div>
  • 这里我定义的是 keywords
  • 接下来在我们的 js 文件里调用 : $(“#keywords”).autocomplete
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
$("#keywords").autocomplete("/music/neteaseCloud/search", {
width : 350, // 提示的宽度,溢出隐藏
max : 30,// 显示数量
scrollHeight: 600,
resultsClass: "ac_results animated fadeInUpBig",
autoFill : false,//自动填充
highlight : false,
highlightItem: true,
scroll : true,
matchContains : true,
multiple :false,
matchSubset: false,
dataType: "json",
formatItem: function(row, i, max) {
//自定义样式
},
formatMatch: function(row, i, max) {
return row.name + row.id;
},
formatResult: function(row) {
return row.id;
},
parse:function(data) {
//解释返回的数据,把其存在数组里
if (data.data.length === 0) {
return [];
}else {
return $.map(data.data, function(row) {
return {
data: row
}
});
}

}
}).result(function(event, row, formatted) {
jQuery(this).val(row.name + ' ' + row.author);
addSearchResult(row.id);
});

接下来重点解释这个配置项

  • autocomplete 的第一个参数是url, 值得注意的是,这个 url 我们返回的结果数据是 JSON
  • 后面要专门针对返回的 JSON 数据进行解析
  • 再往后面来,看到的是一些配置项参数,一些简单的我就不在这多解释了,我这边主要说下我觉得比较重要的
  • resultsClass : 这个参数是生成的候选项的父 DIV,如下图所示:

JoyMedia - AutoComplate-Div

  • 默认提供的样式很不好看,默认提供的样式都写在 jquery.autocomplete.css 里面
  • 在这里面,能看到刚才截图的 div : ac_results
  • 那么我们要美化的就是 这个 div 和其子元素 li 的样式了
  • 为了跟契合本站的主题,我采用的黑色主题风格
  • 给ac_results添加了黑色背景色:background-color: #232c32
  • 在js文件里搜索ac_results,添加动画效果,并将这个配置写到配置项里:resultsClass: “ac_results animated fadeInUpBig”
  • ul 里的 li 是交替的样式的,class 分别为ac_odd和 ac_even,鼠标滑上去的效果为 ac_over,这几个地方自定义下样式
  • 还有一个配置: matchSubset,设置为 false ,可以避免输入大小写转换的js错误
  • formatItem : 返回的每一个结果都会再次处理,这里要做的事是以自己想要的样式显示出来
  • formatMatch : 匹配自己在结果集中想要的属性
  • formatResult : 自己最终要取的数据是什么
  • parse : 针对返回的JSON 数据进行转换,这里通过$. map 转化为 数组
  • result : 点击了列表项以后要做什么事情

完美的结束

欢迎大家来听听试试看!😘 http://music.joylau.cn (当前版本 v1.3)

0%