Snapaper | 一个「伪」刷题网站的诞生

Posted ·1003 Views·4545 Words

咳咳(敲桌板)
https://www.snapaper.com

又开新坑啦,不过这次的坑并没有很深(一定是我进步了)
前段时间心血来潮注册了一个「snapaper.com」域名,听起来很上口,果断剁手...
本来是8月暑假的坑的,但是暑假太好哇加上当时突然有许多新想法就花了蛮多时间去填小半新功能的坑了...

蛮好,开填这个坑的缘由其实是偶然的 Bruce 同学偶然的准备下载生物 Past Papers 来学习来着,GCE Guide (https://www.gceguide.com) 网站只能手动右键下载,慢、乱、烦,好吧,那做个扩展工具吧。诶...还有个域名放哪儿没用诶,诶诶诶,正好用上了..嗯嗯 OK 中秋节就开干。

开发

基于上一次做彩虹六号战绩查询时使用 QueryList 的经验,这次的 Snapaper 也用这个「简介优雅的 Php 采集插件」来完成。

首先,页面的基本逻辑是:

  1. 首页(index.php)
    1. 采集 GCE Guide > Past Papers 页面的标题(分类长期固定,故先使用 html 静态页面)
    2. 截取标题文字(A Levels/IGCSE...)传参到 cate.php 处理分类下学科
  2. 学科(cate.php)[参数:cate]
    1. 采集 GCE Guide > Past Papers > $_GET['cate'] 页面的学科列表学科名(结构为.dir>td>a)
    2. 学科名传参到 paper.php 处理学科下所有的试卷
  3. 试卷(paper.php)[参数:cate & sub]
    1. 采集 GCE Guide > Past Papers > $_GET['cate'] > $_GET['sub'] 页面的试卷列表试卷名&试卷pdf链接(结构为.file>td>a)
    2. js实现扩展功能(页面上每条试卷循环输出时添加当前指针的值为id,与按钮的 onclick 所执行函数的参数)
      1. 全部下载
        1. 从0开始,使用jquery的 click() 函数模拟点击链接
        2. 设置 setInterval 间隔3秒下载一次,指针加一,直至指针到达最后,清除 interval
      2. 列表下载
        1. 设置全局变量 list ,按钮 onclick 函数参数为指针,click 后将指针添加到 list,以「,」分隔
        2. 删除 list 中的某一个值,分隔 list 字符串为数组,删除数组指定值内容,转换回字符串存入 list
        3. 从0开始,使用jquery的 click() 函数模拟点击 list 中对应 id 的 a 标签链接
        4. 设置 setInterval 间隔3秒下载一次,指针加一,直至指针到达 list 最后,清除 interval
      3. php创建下载
        1. 独立 php 文件处理文件下载,readfile()函数,传入 pdf 链接返回下载头与请求

好吧,大概就是这样。涉及到的新知识是 php 创建浏览器下载请求

<?php
 $filename = $_GET['filename'];
 header('content-disposition:attachment;filename='.basename($filename));
 header('content-length:'. filesize($filename));
 readfile($filename);
?>

实现下载功能的 js 代码(注释我其实后来加在生产环境了,所以我还是一如既往的严谨..嗯..严谨)

function download_list(){ //列表下载
 var urls = $('#download_items').val(); //获取列表数据
 if(urls == ''){ //为空则提示
 alert('Can not download empty list');
 }else{
 $('#count_list_notice')[0].style.display = 'none';
 toTop();
 $('#dl')[0].innerHTML = '<button class="uk-button uk-button-danger" style="border-radius: 5px;margin-left: 0.5%;">Processing...</button><button class="uk-button uk-button-default" style="border-radius: 5px;margin-left: 0.5%;" onclick="location.reload();">Refresh</button>'; //修改按钮
 $('#notice')[0].style.display = 'unset'; //显示提示
 var url = urls.split(','); //半角逗号分隔字符串为数组
 var idname = ''; //初始化idname
 var num = 0; //初始化指针值
 var click = function(){
 if(num == (url.length)){ //指针到达列表总数
 window.clearInterval(interval); //清除interval
 }else{
 idname = '#' + url[num]; //补全idname
 downloadFile($(idname).attr('href'));
 num += 1; //累加指针
 }
 }
 window.interval = setInterval(click,3000); //设置interval
 }
}
 function remove_items(id){ //删除列表指定id 值
 var current = $('#download_items').val(); //获取当前列表值
 var current = current.split(','); //分隔列表字符串为数组
 current.splice($.inArray(id,current),1); //获取删除值位置并删除
 var now_count = current.length;
 if(now_count == 0){
 $('#count_list_notice')[0].style.display = 'none';
 }else{
 $('#list_count')[0].innerHTML = now_count;
 }
 var now = current.join(","); //数组转换回字符串
 $('#download_items').val(now); //存入列表值
 var change = '#btn'+id; //补全提示已修改的按钮id
 $(change).attr('onclick', 'add_items('+ id +')'); //修改按钮onclick
 $(change)[0].innerHTML = 'Add to List'; //修改按钮文本
 $(change)[0].className = 'papers-list-td-btn1'; //修改按钮css
 console.log($('#download_items').val()); //方便debug
}
 function add_items(id){ //增加列表值
 var current = $('#download_items').val(); //获取当前列表值
 if(current == ''){ //若当前列表值为空
 var now = id;
 var change = '#btn'+id;
 $('#download_items').val(now); //直接赋值给列表,不增加连接符
 $(change).attr('onclick', 'remove_items('+ id +')');
 $(change)[0].innerHTML = 'Remove from List';
 $(change)[0].className = 'papers-list-td-btn1-change';
 $('#count_list_notice')[0].style.display = 'unset';
 $('#list_count')[0].innerHTML = '1';
 }else{
 var now = current + ',' + id //否则增加连接符
 var change = '#btn'+id;
 $('#download_items').val(now);
 $(change).attr('onclick', 'remove_items('+ id +')');
 $(change)[0].innerHTML = 'Remove from List';
 $(change)[0].className = 'papers-list-td-btn1-change';
 now = current.split(",");
 var now_count = now.length + 1;
 $('#list_count')[0].innerHTML = now_count;
 }
 console.log($('#download_items').val());
}
function down(id){
 var id = '#'+id;
 $(id)[0].click();
}
/* UX 功能 */
function toTop(){
 var gotoTop= function(){
 var currentPosition = document.documentElement.scrollTop || document.body.scrollTop;
 currentPosition -= 50;
 if (currentPosition > 0) {
 window.scrollTo(0, currentPosition);
 }
 else {
 window.scrollTo(0, 0);
 clearInterval(timer);
 timer = null;
 }
 }
 var timer=setInterval(gotoTop,0.3);
}
function toBottom(){
 $('#bottom')[0].scrollIntoView();
}
/* 随浏览器变化而改变 */
function getScrollTop() {  
 return scrollTop = document.body.scrollTop + document.documentElement.scrollTop;
}
window.onscroll = function () {
 if (getScrollTop() <= 400) {
 $('#to_top')[0].style.display = 'none';
 $('#to_bottom')[0].style.display = 'none';
 $('#sticky')[0].style.display = 'none';
 }else {
 $('#to_top')[0].style.display = 'unset';
 $('#to_bottom')[0].style.display = 'unset';
 $('#sticky')[0].style.display = 'unset';
 }
}
/* 结束随浏览器变化而改变 */
/* 结束 UX 功能 */

那,前端设计还是用的 UIKit ,风格是以前记忆中看到过的某个代码托管网站的项目列表大致样式,记不清楚了(其实就只是加了些淡色的border-top,算不上设计...)

这个试卷列表是我想要的效果...
当然还是要日常皮一下的

亮点就不明说了...

好吧,大概这就是 V0.1 版本的 Snapaper 了,以后应该会加功能的,包括社区、用户贡献内容等。蛮方便的对于真正想刷题的同学来说,也算帮个忙啦!

Comments

Leave a comment to join the discussion