0%

小说章节合并插件-第二篇

小说章节合并插件-第二篇

前面我们已经把动手前的踩点工作做的差不多了, 接下来编写程序来实现就可以了! 至于这些结论我不在解释了, 如果忘了在回头看看, 或者自己分析网页源代码。

限制运行范围

首先我们的运行条件必须在小说的页面上, 不能到处运行, 所以我们检测当前页面是不是一个小说的主页, 如果不是就应该停止运行。

我们可以使用正则表达式来匹配当前页面的URL, location.href可以获取当前页面的完整URL。

不过我们用不着完整URL, 只要拿到路径部分就可以了, 所以用location.pathname来获取域名后面的路径。

我们在main.js文件里添加一个叫main的函数。

function main()
{
if (new RegExp("^\\/xs\\d+\\/$").test(location.pathname))
{
alert("运行");
}
}

main();

这样脚本就不会到处运行了, 只会处理小说主页的内容。

封装一个Ajax函数

既然我们的插件需要网络功能, 那么我们自己封装一个, 学习阶段可以自己动手, 如果实际干活就用一些成熟的库, 比如我们这次就是在探索axios是怎么工作的, 而axios是一个使用非常广泛的Ajax库。

我们的Ajax函数接受URL和两个回调函数, 成功回调和失败回调, 如果大家不熟悉XMLHttpRequest对象就找一个教程来看看。

function download(url, successCallback, failCallback)
{
let xhr = new XMLHttpRequest();
xhr.onreadystatechange = () =>
{
if (xhr.readyState === 4)
{
if (xhr.status === 200)
{
successCallback(xhr.responseText);
}
else
{
failCallback(new Error(`http ${xhr.status} ${xhr.statusText}`));
}
}
}
xhr.open("GET", url, true);
xhr.overrideMimeType(`Text/html; charset=${document.characterSet}`); // 让返回的文档字符编码保持和当前文档一致,
xhr.send();
}

有了这个我们可以编写我们的主要业务逻辑了。

回调地狱

异步调用是一个好主意, 它提高了程序的运行速度, 但是也带来了一些和我们的直觉不太相同的思考方式,

程序运行顺序分析总结

比如说我们这次项目的所有步骤是这样的,

  • 第一步 获取章节列表的第一页

  • 第二部获取章节列表的更多页面

  • 第三步 获取每个章节的第一页内容

  • 第四步 获取章节的更多内容

    然后这些步骤有他们的运行顺序,

  • 第二部必须运行玩第一步后才能运行,

  • 第三步必须运行玩第一步或者第二部后才可以运行

  • 第四步必须运行玩第三步后才可以运行

那么我们首先用异步加回调试着编写一个函数完成我们的第一步和第三步, 看看能不能行得通。

大家可以看看这个函数好不好看懂, 如果不好看懂有没有更好的设计方法呢?

把如下函数放在main函数的if语句块里运行, 里面用到的DOM方法大家自行参考js手册。

function chapters()
{
let url = null;
for (let el of document.getElementsByClassName("ablum_read")[0].getElementsByTagName("a"))
{
if (el.innerText.includes("正序"))
{
url = el.getAttribute("href");
break;
}
}
if (url === null)
{
alert("获取章节列表失败");
return;
}

// 获取章节列表 第一层回调
download(url, (text) =>
{
// 把返回的数据放在一个div元素里生成一个新的html DOM
let div = document.createElement("div");
div.innerHTML = text;
// 便利每一个章节
for (let a of div.getElementsByClassName("chapter")[0].getElementsByTagName("a"))
{
// 下载章节的内容, 第二层回调
download(a.getAttribute("href"), (content) =>
{
let nr = document.createElement("div"); // 开始和人家学坏了, 暂时就叫nr吧
nr.innerHTML = content;
document.write(nr.getElementsByClassName("nr_nr")[0].innerText);
}, alert);
}
}, alert);
}

运行一下试试, 结果不完整, 只有第一页章节列表的内容, 而且乱序的, 此外每个章节只有第一页。

如果我们把这个半成品继续完善的话, 势必添加更多的代码, 这样是不是代码变得难以理解, 不要说你们, 过两天我自己都不知道这些代码都在干嘛。

所以如果想要编写更好的代码当前这样:

download(url, (result) => 
{
.......
download(url, (result) =>
{
.....
download(url, (result) =>
{
......
}
......
}
........
download(url, (result) =>
{
download(url, (result) =>
{
........
}
}
}

如果写这些东西最后代码变得难以理解; 难以维护, 所谓的回调地狱就是这样了, 回调函数一个套着一个, 两三层还好, 如果超过四层, 而且实际业务逻辑肯定有其他语句, 这样情况变得更复杂。

那么有没有一个比较优雅的处理上面四个步骤的办法呢?

所以需要改变思路, 关于这些是我们下一次的主要内容了, 下一篇重点……未完待续。