友人C - 函数
type: channel
link: https://www.ihewro.com/tag/函数
items: 30分钟写一个简单QQ自动回复机器人
items: C++学习笔记1：类的使用
items: java实现Apriori算法——频繁项集的计算
items: 为js动态创建的元素绑定事件
items: typecho博客实现ajax评论
items: 巧用excel表格计算平均GPA
items: typecho评论模块入门
items: lazyload.js 减轻图片加载负担
items: 怎么学JavaScript？
items: instantclick 中文文档

30分钟写一个简单QQ自动回复机器人
type: item
date: 2019-09-19T23:22:00+08:00
description: 环境要求mac OS/linux（其他操作系统类似）酷Qdocker+CoolQ HTTP API 插件NoneBotdocker如果是windows服务器或者电脑也可以安装酷Q，mac linux/linux服务器只能装酷Qdocker（推荐docker安装）!> 也可以直接使用「CoolQ HTTP API 插件」作者集成的docker镜像包，这样就无需配置「CoolQ HTTP API 插件」了。简单介绍简单介绍一下原理是什么。在酷Q中登录你的QQ账号，「酷Q」接管你的消息，并将QQ的所有消息请求和发送进行封装成一些接口，供“插件”进行进一步接管和调用。酷Q的插件后缀都是.cpk，需要安装在酷Q的内部。「CoolQ HTTP API 插件」作用就是专门针对“http请求以及信息处理”方面的插件，使用的语言当然是与酷Q一致的（易语言好像是）会易语言的开发者还是蛮少的吧...emmm「NoneBot」就像一个翻译官，将「CoolQ HTTP API 插件」的插件全部转变成“Python的方法”。「CoolQ HTTP API 插件」有很多个不同语言的翻译官，方便使用不同语言的开发者直接处理酷Q的信息。这样，我们直接写Python文件，就能直接接收或者发送QQ消息啦！开始开始安装！#1. 安装docker brew install docker #2. 安装酷Q+http插件集成镜像 docker pull richardchien/cqhttp:latest #3. 安装nonebot pip3 install nonebot 我们在docker中先启用酷Qdocker run -ti --rm --name cqhttp-test -v $(pwd)/coolq:/home/user/coolq -p 9001:9000 -p 5701:5700 -e COOLQ_ACCOUNT=123456 -e CQHTTP_POST_URL=http://example.com:8080 -e CQHTTP_SERVE_DATA_FILES=yes richardchien/cqhttp:latest 上面的命令如果需要改，就改9001和5701就可以了，其它的不用修改。其中：9001端口号就是登录酷Q的端口号5001端口号是HTTP API 插件开放的端口，这个不用管。如果需要启用多个酷Q，保证这个端口号和容器名称cqhttp-test不重复即可启动之后，打开127.0.0.1:9001，如果部署到Linux服务器上面就是ip地址:9001打开页面之后，会要求输入密码，密码默认是MAX8char。进入之后就是一个类似QQ登录界面，输入账号密码即可。（第一次登录可能要输入验证码）此时，酷Q其实就是以一个安卓手机的身份登录了你的QQ，并接管了你的所有消息处理。「CoolQ HTTP API 插件」同时也在开放接口供其他插件进行调用。接下来，我们需要使用nonebot 模块，使用Python代码接管QQ消息的接收和发送。在coolq/data/app/io.github.richardchien.coolqhttpapi/config/里面有<你的登录的QQ号>.json 文件，打开，并修改（如果没有则增加）三个变量为对应的值{ "ws_reverse_api_url": "ws://127.0.0.1:9999/ws/api/", "ws_reverse_event_url": "ws://127.0.0.1:9999/ws/event/", "use_ws_reverse": true }!> 如果docker部署电脑上的，把 127.0.0.1 改成host.docker.internal!> 如果docker是部署在Linux服务器上的，把127.0.0.1改成172.17.0.1这个操作就是让「CoolQ HTTP API 插件」把接收信息和发送的信息借给noneboot 模块来接管。所以，开始通过noneboot模块，使用Python开发吧。可以用pycharm ide，当然也可以直接新建一个文件夹，使用命令行启用。我们直接用命令行来启动。cd ~/Document mkdir qqboot_test touch boot.py cd qqboot_test & mkdir plugin 第一条指令cd切换到指定目录，后面的指令，你可以完全一样。打开boot.py，我们复制粘贴下面的代码：import nonebot from os import path if __name__ == '__main__': nonebot.init() nonebot.load_plugins( path.join(path.dirnam…

C++学习笔记1：类的使用
type: item
date: 2017-12-15T15:21:00+08:00
description: 系列笔记[基本数据结构]()[类的使用]()[类的继承和派生]()[面向对象特征之一——多态]()[操作符重载]()[const关键字的使用]()1. 类的定义与使用1.1 类的定义最简单的类的申明：class Student{ };在类的定义最后需要加上分号，这是和java不同的地方，否则会有编译错误。1.2 类的使用即创建类的实例——对象。在java中你会使用到new关键字，而在c++中，创建对象与使用普通的数据类型一样简单：Student studentObject;2. 类的成员变量和成员函数2.1 成员变量class Student { char name[20]; //姓名 int id_num; //学号 int age; //年龄 char sex; //性别和java不同，类的成员变量不能在创建的时候初始化值。2.2 成员函数和java不同,c++的成员函数有两种定义方式:1.类内部申明，类外定义（实现）：class student { void set_age(int a); int get_age(); }; //在类外部定义set_age函数 void student::set_age(int a) { age = a; } //在类外部定义get_age函数 int student::get_age() { return age; }在类内部申明函数，在类的外部定义的时候通过作用域操作符 :: 进行实现。申明的时候，只需写出返回类型、函数名称、参数列表、末尾分号即可，不能加上空的大括号。 返回类型 类名::成员函数名(参数列表) { //函数体 }你也可以在类的成员函数申明的前面加上inline关键字使其变成内联函数。内联函数可以优化程序的执行效率。class student { inline void set_age(int a); inline int get_age(); }; //在类外部定义set_age函数 void student::set_age(int a) { age = a; } //在类外部定义get_age函数 int student::get_age() { return age; }2. 类内部边申明边定义（实现）class Student{ void set_age(int a){age = a;} int get_age(){return age;} }这种方式其实和java的成员函数调用方式是相同的。2.3 访问限制和java的语法类似，c++也提供了三种关键字：public：本类和其他类都可以访问到private： 只有本类可以访问到protected：只有本类和派生的类可以访问。但是使用的语法格式有点不同。class book { public: void setprice(double a); double getprice(); private: double price; };通过这种格式，可以将属性为public的变量或函数申明在一起。避免了重复的写权限限制符号。当然，权限相同的成员也可以分开声明，申明的顺序也是无所谓的。2.4 访问成员变量/函数创建的对象就是类的实例，就直接使用.点选择符，这里是和java一样的。创建的如果是对象的指针，需要使用->箭头选择符访问成员。java中没有指针就没有这条规则。#include <iostream> using namespace std; class book { public: void setprice(double a); double getprice(); private: double price; }; void book::setprice(double a) { price = a; } double book::getprice() { return price; } int main() { book Alice; Alice.setprice(29.9); cout<<"The price of Alice is $"<<Alice.getprice()<<endl; book *Harry = new book; Harry->setprice(49.9); cout<<"The price of Harry is $"<<Harry->getprice()<<endl; return 0; }注意：C++类class和结构体struct区别class和struct都可以定义一个类的结构。采用struct关键字，结构体中定义的成员变量或成员函数默认都是public属性的。使用class关键字，类中定义的成员变量或成员函数默认都是private属性的，除此之外，没有其他任何区别。3. …

java实现Apriori算法——频繁项集的计算
type: item
date: 2017-11-20T23:01:00+08:00
description: 前言之前学校开的选修课《数据挖掘》，布置的两道算法题，时间有限完成其中一道：用Apriori算法求特定支持度的频繁项集。算法本身不难，java萌新我却花费了一天的时间，特此记录。算法描述我们目的是求出项数为K的频繁项集即L(K)。Apriori算法的核心步骤是：L(K-1)通过自连接求出项数为K的候选项集合C(K)通过对C(K)进行一系列处理（剪枝 + 支持度判断） 得到L(K)集合在说明下面更多内容之前，先对一部分概念进行说明：事务：如第一张图中，每一行就是一个事务，如 T100 I1,I2,I5。其中T100是事务编号，这个随便命名，只要保证唯一即可。后面的I1 I2 I5是该事务中的项数据集：如图一，整个表就是数据集，就是所有的事务的集合。即D = {T100,T200…}项集：包含若干个项（如I1 、I2这样的项）的集合。可以看出项集和事务似乎有点项。但是项集更随意一点，任意几个项都能组成一个项集。但是事务是人为规定好的。可信度：项集在数据集中出现的重复次数。项集不一定需要在事务中连续出现。如{I1,I2,I5}项集在数据集中出现的次数为2次，分别是第一个和倒数第二个事务。接下来，详细分析算法中的两个步骤：1. 自连接：怎么个连接法呢？以图二中的L2频繁集的集合为例：项集支持度{I1,I2}4{I1,I3}4{I1,I5}2{I2,I3}4{I2,I4}2{I2,I5}2判断两个项集是否可以自连接要看两个项集的K-1项是否完全相同。如果满足条件，连接后的项集 = 第一个项集 + 第二个项集的最后一个元素。比如{I1 I2}与{I1 I3}满足自连接条件，连接后的项集为{I1 I2 I3}。2. 剪枝：剪枝是这个算法的核心，如果不进行这个步骤的话，也能得出正确结果，但是时间就会大大增加了。剪枝的核心是若某个集合存在一个非空子集不是频繁项集，则该集合不是频繁项集。我们通过自连接组成新的K项的候选项集后，需要通过剪枝判断是否满足条件。即找出该候选项集的含有(K-1)项的子集，并分别判断每个子集是否存在于K-1项频繁项集里。只要有一个不存在，那么该K项候选项集也不可能是频繁项集。这里我们只需要找含有K-1项的子集，而不用找所有的子集，因为这个算法是从下不断递归上来的，含有更少项的子集肯定是在频繁子集里的。问题关键是怎么寻找某个K项集的K-1项子集呢？很简单，依次把K项集中的每个元素去掉一个就可以了。完成了这两步骤，就完成了这个算法了核心步骤。3. 对精简后候选集统计每一个项集的支持度4. 根据最小支持度将候选项集转换为K项频繁项集合可以看出，如果不剪枝的话，第三步的工作量是非常大的。剪枝过后，候选集的体积大大减小了。但是获取含有一项的频繁项集因为没有候选项集，就需要特殊处理。这个很简单，就是统计数据集中的每一项的支持度，并和最小支持度进行比较，得到含有一项的频繁项集。代码分析github项目地址：https://github.com/ihewro/Aprioriimport java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.InputStreamReader; import java.util.*; /** * @author hw * 算法名称：数据挖掘：Apriori算法求特性支持度下的所有的频繁集 * 算法原理： * * 0. 获取C1的时候，因为没有L(0)频繁集，所以单独处理一个函数 * 1. 已经频繁集L(k-1)，{}自连接+剪枝}求出精简后的候选集C(k) * 2. 根据精简后的候选集C(k)根据求出频繁集L(k) * * 数据结构： * 1. 使用List<String> 存储整个数据库的数据，string代表每一行的数据 * 2. 使用HashMap<String,Integer> 存储项集以及项集的重复次数，便于查找。是{项集}的集合。 * 3. 每个项集用String类型存储。项集中的每一项使用String.split(" ")方法变成数据，以便取用项集中的每一项 * * 给定的数据格式： * 1. 每个数据以空格隔开 * 2. 每一行代表一个事务T,事务编号就是行号 * * 示例数据： * 1. {11，12，13}是一个频繁项集，是属于HashMap<String,Integer>中的一个元素，数据类型为String. * 2. Set<String> = HashMap.keySet(); 用来存储HashMap的所有key的值，也就是存储所有的项集（不包括项集的重复次数） * * 相关概念： * 1. 支持度百分比 * 2. 支持度 * 3. 事务 * 4. 候选…

为js动态创建的元素绑定事件
type: item
date: 2017-08-01T01:15:00+08:00
description: 问题描述handsome主题评论的时候，如果是子评论，评论内容前面会有一个@某人的锚点链接。由于主题顶部的导航占用了50px的高度，所以点击锚点链接的时候必须向下偏移原来的位置50px，才能正常显示。为此，之前写了一个解决方法：锚点链接跳转后位置上下偏移一定位置方法但是，对于ajax生成的评论，如果不刷新页面的话，点击子评论左边的锚点链接却不会向下偏移。即：以前写的js对动态生成的页面元素不管用！举个很简单的demo，见下面的代码： 这是一个段落。 请点击任意一个 p 元素，它会消失。包括本段落。 在本按钮后面插入一个新的 p 元素 这段代码很简单。有两个功能：点击按钮会插入一个 标签及其内部内容点击p标签会 隐藏 或 显示 当前 p 元素但是这段代码的问题是：点击按钮生成 p 标签，如果点击生成的这个 p 标签，则无法 隐藏 或 显示 当前 p 元素。问题出在哪儿呢？解决方法原因在于，浏览器解析js代码的时候，会寻找当前页面的所有 p 标签，并给每个 p 标签绑定上相关事件（slideToggle()）。但是未来动态生成的 p 标签却无法再次重新绑定相关的事件了！因为js已经被浏览器解析完了 这里可以使用jQuery中的delegate()方法。我们通过bind绑定的点击（click）事件，只适用于当前页面的元素使用delegate绑定的点击事件，却可以适用于当前或未来的元素（比如由脚本创建的新元素）。所以核心代码改成$(document).ready(function(){ $("div").delegate("p","click",function(){ $(this).slideToggle(); }); });delegate的语法是：$(selector).delegate(childSelector,event,data,function)简单来说，即为指定元素（selector）的子元素（childSelector） ，监听某些事件（event），绑定相关函数（function）。该bug会在handsome v3.3.0 版本中得到解决参考文章js动态加载HTML元素时出现的无效的点击事件 - 何甘霖 - 博客园

typecho博客实现ajax评论
type: item
date: 2017-07-26T23:43:00+08:00
description: 前言系列文章：typecho博客实现pjaxinstantclick 中文文档相关文章： Typecho · JS简单实现评论ajaxTypecho全站pjax方案阅读前须知：以下内容对于实现了pjax效果的站点，可能需要自行增加回调函数。以下内容完全适用于实现了instantclick站点标有（*）内容为可选内容，可略去不读如有疑问可以发送邮件或者直接评论，千万不要加我QQ提问代码分析ajax的基础知识这里使用的是jQuery ajax的底层的一个方法：$.ajax()，执行这个方法的时候，会返回一个创建的XMLHttpRequest对象。基本语法：$.ajax({ url: ,//发送请求的地址 type: ,//请求方式，是post还是get请求 data: ,//要发送到服务器的数据 error: function() { //请求失败执行的回调函数 }, success: function(data) { //请求成功执行的回调函数，参数data是请求成功后的页面的纯文本 HTML 代码 } }) 实现步骤监听comment_form评论框的提交事件：$(comment_form).submit(function() { //提交事件 }）(*) 检查评论内容以及作者邮箱内容是否符合规则（预检）：这段代码比较简单易懂，不再赘述，直接看代码就行了。发起ajax请求：就是最基础的$.ajax() 请求：$.ajax({ url: $(this).attr('action'),//提交表form的action属性 type: $(this).attr('method'),//提交表form的method属性 data: $(this).serializeArray(),//要发送到服务器的数据 error: function() { //这里写一下提示信息代码即可 }, success: function(data) { //这部分内容在第四步中会解释 } }) 获取到ajax请求的数据，从这些数据中找到最新评论的内容，并把该内容插入到当前页面中：如何从ajax成功返回的数据中找到最新评论，我有两个思路：从ajax请求成功返回的数据中寻找到最新的评论插入到当前页面中。直接在提交的时候，拿一个变量把用户提交的内容保存起来，然后，直接按照你的评论结构组装成一条评论插入到当前页面中我是第一种方法，所以以下代码分析均只适用与第一种方法。第一个问题：理解ajax请求成功后返回的数据是什么东西？返回的数据是执行提交操作后页面的html代码，换句话说，返回的数据（data）就相当于手动刷新当前页面后的html代码所以，在返回的数据里面，肯定是可以找到最新评论的！第二个问题：如何找到最新评论的内容和应该插入到什么位置？首先你得保证你的评论将较新的的评论显示在前面。其次，我把用户评论简单分成两种：母评论（parent）：直接评论文章的子评论（children）：评论文章中的某条评论我们先来看如何找到最新评论的内容：其实很简单：typecho生成commentID的时候总是越来越大的，所以只要找到数据中最大的那个commentID就是用户刚才评论的最新评论了！代码就是：new_id = $(comment_list, data).html().match(/id=\"?comment-\d+/g).join().match(/\d+/g).sort(function(a, b) { return a - b }).pop(); 但是其实还是存在一个问题的：如果你启用了评论分页功能，由于typecho显示最新评论总是在第一页，所以当用户不在第一页发出了母评论，那么从数据（data）中找到的ID最大的评论并不是最新评论，这个时候，发送ajax请求成功后，就没必要向当前页面插入评论，因为最新评论再第一页。if ($('.page-navigator .prev').length && parent_id == ""){ new_id = ''; }//做一个判断 ... if (new_id)//new_id不为空的时候才会插入 $('#' + parent_id + " .comment-children .comment-list").prepend(data);接下来就是插入的位置问题:其实很简单，如果是母评论，直接插入到comment_list的最前面即可：$(comment_list).prepend(data);如果是子评论，要在监听页面中的回复链接，当鼠标点击回复按钮的时候，通过父元素的父元素（根据个人的评论结构而定），找到回复当前的评论ID(parentID)：$(comment_reply + ' a').click(functi…

巧用excel表格计算平均GPA
type: item
date: 2017-02-22T22:12:00+08:00
description: 建议直接脱到最后食用更佳。今天班群里面通知：申请实验班的同学需要把GPA报给团支书。实验班是小班教学，一个班只有30多人，老师也是很厉害的，不仅如此，氛围肯定是不一样的想当初大一下学期刚开始的时候，就有机会报名实验班，据说面试的是我们授课老师，很好过，一些GPA3.0左右的都进了，当时我GPA3.63，可是当时害怕报不上就没报！以至于，大二上学期《数据结构》蹭了大半个学期的实验班的课（我们老师讲的实在太快），造成了很大的负担。这次有机会了，可是上一学期考的并不理想，不知道这次能否成功，不过不管了！先申请再说。接下来是如何使用excel表格快速计算平均GPA。GPA公式是这样的：每一科的学分*绩点之和/所有科目的学分之和这里需要这个函数：sumproduce，sum指的是求和，product是求积。组合在一起就是乘积之和。先把教务网的成绩直接复制到excel表格中。如上图所示，学分栏G3-G28，绩点栏H3-H28每一科的学分绩点之和 公式就是：SUMPRODUCT(G3:G28,H3:H28)所有科目学分之和公式就是：SUM(G3:G28)最后公式就是：=SUMPRODUCT(G3:G28,H3:H28)/SUM(G3:G28)最后结果是：大一第一学期 3.63大一第二学期 3.64 大一第三学期 2.78大二第一学期 3.24 大二第二学期 3.38大二第三学期 3.55大三第一学期 3.36综合(所有)3.44不要问我为啥大一第三学期GPA这么低，因为那是小学期啊！小学期，是夏天最热的时候，只有两门课，一共10多天，大家基本都无心上课，导致多核程序设计学的一塌糊涂！！！惨痛的教训这么简单一个公式，我居然能写这么多文字！学期学年学分绩点课程名称成绩课程性质22015-201634数据结构与算法（I）91专业必修22015-201643.33大学英语B82公共基础必修22015-201663.67高等数学(Ⅱ)85公共基础必修22015-20162.54离散数学(Ⅰ)92专业必修22015-201613.33金工实习B+实践环节必修22015-201633.67思想道德修养与法律基础86公共基础必修22015-20161.54普通物理实验(Ⅰ)A公共基础必修22015-201643.33普通物理(Ⅰ)84公共基础必修32015-201622.33多核程序设计C+专业选修32015-201613.67程序设计实训A-实践环节必修12015-201644程序设计基础A专业必修12015-201622.67计算机科学导论B-专业必修12015-201643.33大学英语C83公共基础必修12015-20163.54线性代数93公共基础必修12015-201664.33高等数学(Ⅰ)96公共基础必修12015-201622.67中国近现代史纲要76公共基础必修12015-201612.33军事理论72公共基础必修12015-201613军事训练B实践环节必修22016-20173.54.33操作系统原理95专业必修22016-20173.52.67数字逻辑76专业必修22016-20172.53.33数论与组合数学B+专业选修22016-20173.53.67概率论与数理统计88公共基础必修22016-201724计算方法A专业选修22016-201763.67毛泽东思想和中国特色社会主义理论体系概论85公共基础必修22016-201721形势与政策合格公共基础必修32016-201723.33认识实习B+实践环节必修32016-201714操作系统原理课程设计A实践环节必修12016-201714数据结构课程设计A实践环节必修12016-20172.54数据结构与算法（II）94专业必修12016-201743电路与电子技术81专业必修12016-201743.33大学英语A84公共基础必修12016-20172.53.33离散数学(Ⅱ)83专业必修12016-201733马克思主义基本原理78公共基础必修12016-20171.53.67普通物理实验(Ⅱ)A-公共基础必修12016-201742.67普通物理(Ⅱ)75公共基础必修12017-20182.53.67Linux和Unix编程基础87专业选修12017-20182.53.67面向对象程序设计A-专业选修12017-20182.54Java程序设计A专业选修12017-20183.53编译原理80专业必修12017-20184.53计算机组成原理80专业必修12017-20183.53.67数据库原理86专业必修12017-201813.67数据库原理课程设计A-实践环节必修12017-201813计算机组成原理课程设计B实践环节必修12017-201833.67移动互联…

typecho评论模块入门
type: item
date: 2017-01-27T00:27:00+08:00
description: 官方文档对这方面写的比较简洁，不利于主题修改者快速入门typecho，所以总结了一些经验，方便自己也方便主题修改者创建评论模块。先写一个评论区的总的容器，id 为 comments。 ... 评论区域分为两个部分：评论输出列表模块 和 评论输入表单模块。评论输出列表模块有两种方法：使用官方自带的函数输出，方便简单，只需要加点CSS控制就行自定义评论列表模块,更灵活满足我们需求官方自带的函数输出评论代码如下：<?php $this->comments()->to($comments); ?> <?php if ($comments->have()): ?> <?php $this->commentsNum(_t('暂无评论'), _t('仅有一条评论'), _t('已有 %d 条评论')); ?> <?php $comments->listComments(); ?> <?php $comments->pageNav('« 前一页', '后一页 »'); ?> <?php endif; ?>代码很好理解。不再赘述。说明一下 ：官方文档—快速入门—调用评论页 给出的代码示例是错误 的！代码示例只能实现简单输出评论，不能对每条评论回复，是个半残品 。但是里面的函数是可以在自定义评论模块中来使用的。我们这里输出评论模块使用的使用官方自带的函数 $comments->listComments(); 。输出的HTML结构也是写死的。所以，接下来是如何自定义评论输出列表模块。自定义评论输出列表模块官方文档—自定义评论列表区域 这里面给出了很混乱的代码讲解，实质上是写了一个 threadedComments 函数来替代系统自带的 threadedCommentsCallback函数（在/var/widget/comments/archive.php内置）。这个函数是php与html互写的形式。可以看出这个函数分为了两个部分：php动态控制输出结构html语句直接固定输出结构<?php function threadedComments($comments, $options) { ... //动态控制结构 ?> ... //html 固定结构 } <?php } ?> 动态控制结构 $commentClass = ''; if ($comments->authorId) { if ($comments->authorId == $comments->ownerId) { $commentClass .= ' comment-by-author'; //如果是文章作者的评论添加 .comment-by-author 样式 } else { $commentClass .= ' comment-by-user'; //如果是评论作者的添加 .comment-by-user 样式 } } $commentLevelClass = $comments->_levels > 0 ? ' comment-child' : ' comment-parent'; //评论层数大于0为子级，否则是父级如果是文章作者的评论添加 .comment-by-author 样式如果是评论作者的添加 .comment-by-user 样式通过判断 $comments->_levels 来确定当前评论的是子级评论还是父级评论这部分一般不需要更改的，即使修改也是增加语句。HTML固定输出结构<li id="li-<?php $comments->theId(); ?>" class="comment-body<?php if ($comments->levels > 0) { echo ' comment-child'; $comments->levelsAlt(' comment-level-odd', ' comment-level-even'); } else { echo ' comment-parent'; } $comments->alt(' comment-odd', ' comment-even'); echo $commentClass; ?>"> <div id="<?php $comments->theId(); ?>"> <?php $comments->gravatar('40', ''); ?> <?php $comments->author(); ?> <a href="<?php $comments->permalink(); ?>"><?php $comments->date('Y-m-d H:i'); ?> <?php $comments->reply(); ?> <?php $comments->content(); ?> <?php i…

lazyload.js 减轻图片加载负担
type: item
date: 2017-01-23T13:05:00+08:00
description: lazyload.js 减轻图片加载负担图片延迟加载大家可能有听说过，其实qqdie的博客早就使用了这个jquery插件，这款插件只有4K！但是有一个缺点是文章中的图片并没有使用延迟加载，问题在于这款jquery 插件 对于图片 的结构的要求必须是这样的： 解释一下这个结构：src里面存放占位图，data-orignal 存放的才是真实的图片地址。当滚动到图片位置的时候，这个插件才会把真实的地址赋给src ，这样图片就会加载出来。是一种延迟加载的策略。这个结构对于已经固定死结构的图片（比如评论区的头像或者其他的一些结构固定的图片）比较容易，自己改一下就很简单，但是对于文章中的图片 如何自动生成这种结构，却让人头痛，总不能让用户手动在后台编辑器添加图片吧，这是不人性化的~ 一开始是想通过js获取到所有图片，然后把图片的data-orignal 属性赋值为src的值，再把 src 属性全部赋值为img/grey.gif。代码其实很简单，是这样的：//对文中图片惰性加载 var imgs = $(".wrapper-lg img"); for (var i = 0; i < imgs.length; i ++) { var srcvalue = $(imgs[i]).attr("src"); $(imgs[i]).attr("data-original",srcvalue); $(imgs[i]).attr("src","<?php $this->options->themeUrl("img/grey.gif") ?>"); }效果非常尴尬，本来图片先出来，然后界面闪一下，图片变成占位图。？？？这样就本末倒置，起不到任何作用！如果不能对文章图片延迟加载，这个插件其实没有多大作用的！就在我要放弃的时候，发现了这篇文章[LazyLoad+ob_start()，完美解决图片延迟加载 [jQuery 插件]](http://www.rainleaves.com/html/1248.html) ,作者提供了新的方法：通过php的ob_start()函数在页面加载区的时候就更换图片属性 。关于ob_start();函数原理原博文有介绍，不再赘述，这里介绍使用方法：在footer.php 中<?php //图片延缓加载相关处理，替换src为data-original，并添加占位符 $echo = ob_get_contents(); //获取缓冲区内容 ob_clean(); //清楚缓冲区内容，不输出到页面 $placeholder = "img/grey.gif"; //占位符图片 $preg = "/ /i"; //匹配图片正则 $replaced = ' '; print preg_replace($preg, $replaced, $echo); //重新写入的缓冲区 ob_end_flush(); //将缓冲区输入到页面，并关闭缓存区 ?>代码也非常容易理解，就是设置页面中所有的图片(事实上并不是所有的)的src 和data-original 的值。最后使用$("img").lazyload();就可以实现延迟加载的效果了。那么问题来了！我不想所有的图片都延迟加载，怎么办？其实上面的正则匹配中隐藏了一个黑名单机制！图片的html结构为 即图片标签的结束标签/前面如果没有空格 ，则不会被正则表达式匹配成功，也就不会延迟加载。好了，这样一来，解决了所有我遇到的问题了！最后需要了解的是延迟加载的常见设置项：加载特效：图片会以淡入的方式显示（更多特效参阅官方文档）$("img").lazyload({ effect : "fadeIn" });触发加载方式：可以选择点击图片才显示内容$("img").lazyload({ event : "click" });当然，还有一些更有趣的设置项可以参阅官方文档。插件地址：tuupola/jquery_lazyload对了，如果你对图片的黑名单机制有什么更好的想法，欢迎一起讨论。

怎么学JavaScript？
type: item
date: 2017-01-17T23:49:00+08:00
description: 怎么学JavaScript？JavaScript 我也学了一段时间，可是每次写起代码来总是入门级别，很是苦恼。这篇文章中说把整本书给敲下来未尝不是一个好办法，我很有体会，有时候看不进代码，敲下来的过程中就在慢慢的吸收代码的精髓，觉得很受益处，遂转载之。转载原文：统一回复《怎么学JavaScript？》鉴于时不时，有同学私信问我(老姚，下同)怎么学前端的问题。这里统一回复一下，如下次再遇到问我此问题同学，就直接把本文链接地址发给你了。首先说句题外话。关于有人管我叫大神的事情。个人感觉这跟你买东西时，人家管你叫帅哥一样，你答应与否都无妨。正题开始，前端怎么学，应该因人而异，别人的方法未必适合自己。就说说我的学习方法吧。我把大部分时间放在学习js上了。因为这个js的学习曲线，先平后陡。项目实践和练习啥的，我不说了，主要说下工作之外的时间利用问题。我是怎么学的呢，看书，分析源码。个人这几天统计了一下，前端书籍目前看了50多本吧（点击我）。大部分都是js的。市面上的书基本，差不多都看过。第一个问题是，看书有啥好处？好处应该是不言而明的，书看多了，基础会逐渐夯实起来。看多了，自己的判断力，自然就上来了。看别人的文章，就能很快判断出，对方每块儿讲得对不对，哪块儿又是自己不清楚的，模棱两可的。当然也为看源码，分析源码提供了基础。10本书读2遍的好处，应该大于一本书读20遍。10本书的交集，那就是基础知识的核心，而并集那就是所有的知识。好书当然要多读，反复读。但是只读一本是不行的。因为每本书的侧重点都不一样。从不同的侧面，去理解一个知识点，是很有意义的。所以特别佩服印度人，他跟你讲英文，你一个词语没听懂，他会蹦出n个同一意思的单词，你听懂一个，就ok了。看书也是这样的，某一块讲得不透彻，不用担心，其他书籍可以帮助你来了解。第二个问题是，书籍推荐。个人觉得不错的，没事可以翻翻的。书籍如下：《javascript面向对象编程指南》，风格轻松易懂，比较适合初学者，原型那块儿讲得透彻，12种继承方式呢。《js权威指南》、《js高级程序设计》，这两本书经典是经典，但是太厚，适合把其中任意一章都当成一本书来读。洋洋洒洒，很难一口气看完。比较适合当做参考书。《你不知道的javascript》狙击js核心细节，闭包、原型、this讲得都还清楚。目前《中册》也出了，还在看。《js设计模式与开发实践》js设计模式也是要学的，此书把js的设计模式讲得非常清晰，一点不晦涩，看起来没多少难度。《正则指引》，分析源码时，如果正则表达式不懂，没法进行下去的。此书相对来说讲得比较清晰。《基于MVC的JavaScript Web富应用开发》，看完后，基本能写出自己的mvc框架了。是本好书。《javascript函数式编程》，js是一门函数式语言，此书是函数式编程一个入门，函数是一等公民那是非常重要的。《js忍者秘籍》，jq作者写的，没有传说中的那么难读，话说就算你看完并理解所有知识点，也不会达到世界高手级别的。因为你还没有做到随心所欲。《javascript框架设计》，如果初看此书，会觉得此书有罗列代码之嫌。在我看来，此书讲究的是框架的全局观。以上书籍是我认为是成就高手之路上必须看的，也需要反复看。css相关的书籍，说实话我看得比较少，总共有六七本吧。有两本必须推荐一下：《css权威指南》，css基础知识点那是讲得非常清楚的。什么层叠优先级、line-height啥的。不是随便一本书都敢叫“权威指南”的。《css揭秘》此书我也是不断的看，此书才不屑于全面讲css3各属性呢。css规范文档能讲的，它只会讲你最不在意的。此书解决的47问题，解决思路和解决方案同等重要，很有启发性。以上各书你都可以不买，至少买本此书吧。第三个问题，怎么看。想必很多同学，都想看书，但是很难看下去。文字部分相对来说还能看看，一遇到代码，头皮就发麻了。此问题一开始时我也遇到的。说一个学习理论。比如说学英语，有个开水理论。词汇量必须达到6000才行，如果没达到，英文水平不会上去的，这跟烧开水一样，没事烧烧，放着凉凉，从来没烧到100度，那么此水是永远不能喝的。一旦煮沸过，就可以随时喝了。20本书你看不下去，说明什么呢？任何一本书，你都没看完过。熟悉的，永远只是前三章。别笑，我原先也是这样的。那么现在的问题是，怎么把一本书看完呢？很简单，敲。《基于MVC的JavaScript Web富应用开发》这本书我看时，就是这样，终于有一天，我下定决心要把此书从头到尾敲一遍。文字加代码都敲，然后就一章一章得看完了。代码敲一遍后，你会发现，没之前看起来的那么难。如果你属于一看书就犯困那种同学。强烈建议你把《javascript面向对象编程指南》此书从头到尾敲一遍。坚持看完一本书后，信心就上来了。先保证看完一本再说。看完3本后…

instantclick 中文文档
type: item
date: 2017-01-16T20:36:00+08:00
description: 同步更新官网文档：v3.1 2017/8/17instantclick 中文文档简介instantclick.js 是一种ajax无刷新和预加载页面的技术，对于普通博客程序，有着明显的加速作用。(instantclick.js ≈ pjax + 预加载页面)而且，使用方法也十分的简单。在github截止目前，已经由4447个star了，非常可观。但是官方文档纯英文，可能阅读上有点障碍，所以，在此，翻译一下大部分的官方文档内容，方便新手快速使用。大部分采用直译方式，需要注意的地方 用小括号注释起来。（尽管如此，instantclick.js 仍然有一些bug亟待解决，如果你可以忽略缺点吧，我们一起开始吧！）目录初级阶段开始使用instantclick 工作原理预加载页面黑名单规则事件和脚本的重新加载进阶阶段跟踪页面内容的变化自定义加载条初级阶段开始使用下载instantclick.js最新的发布版本是2014/12/25发布的V3.1.0 （虽然github一直有更新，但是并没有发布新的版本~）压缩版本2.7kb开发版本21kb其他的下载方式github上面的最新开发版本通过bower（一种前端开发工具） : bower install instantclick初始化instantclick把 instantclick.js 和 初始化代码 放在你的页面的结束之前( 标签结束之前)... 现在instantclick 已经成功在你的网页上面生效。阅读下面的文章以便更熟练的使用instantclick。instantclick 工作原理：将会让你建立正确的模型以便更好的理解instantclick的机制预加载页面：将会向你展示不同的预加载页面的方法黑名单规则：因为有些链接你不想预加载事件和脚本的重新加载：将会帮助你使instantclick更好的配合你的网页中的JavaScript。instantclick不总是“即插即用”（不是通过两行代码就可以在你的网页上运行），你可能需要自定义一些设置来适应你的网站，这也是为什么阅读上述文章是强制性的。instantclick 工作原理InstantClick与传统的web应用区别不大，但是很有必要去了解这些不同的地方！instantclick使浏览器不再刷新整个页面（即无刷新页面效果）首先：你需要理解的核心内容是：instantclick在技术上使你的网站成为单页应用程序；浏览器不再刷新整个页面，而是通过instantclick技术来更改页面内容，这意味着：你不能依赖DOMContentLoaded和jQuery.ready()这两个函数来触发相关事件（这两个事件在刷新整个页面的时候才会触发，但是你可以使用[InstantClick’s events]()来替代)依赖上面两个函数的第三方脚本（比如js代码）需要调整（参阅[事件和脚本的重新加载]()）在加载页面的时候，浏览器不会在显示原本加载进度条了，instantclick有它自己的加载进度条。其次：你需要明白instantclick只会改变 和title，所以你的脚本只会被加载一次（带来的好处是速度的明显提升）。下面还有一些内容你需要了解：通过instantclick加载的每个页面的 标签里面的样式和脚本应该是相同的（因为instantclick只会加载一次 标签里的内容）如果 标签里面的某些内容依赖于网页的内容（比如在页面加载时运行的脚本或css动画），它需要调整以便正常运行。InstantClick是渐进式增强功能：如果访问者的浏览器不支持InstantClick，您的网站链接将照常工作，只是不会提升速度了。预加载页面InstantClick 关于预加载方式有多种选择。你可以根据你的服务器配置来选择合适的方式。但是不管怎样，当每个页面改变时，不会重新加载脚本和样式表，这样会使你的页面加载速度提升一倍！（与Turbolinks、pjax等等技术是类似的）默认: 在鼠标悬停预加载(on mouseover)当用户鼠标悬停在链接上开始预加载页面。如果用户网络链接不错的话，你的页面会很快的打开。初始化方法就是[开始使用]()设置的方式。不会给服务器带来额外负担：在鼠标点击的瞬间预加载(mousedown)当用户按下你的链接按钮的瞬间，页面开始预加载。这为你的服务器带来了接近零的开销，但仍然能够带来一个很“神奇”的速度提升！使用方法：将'mousedown'作为参数传递给InstantClick.initInstantClick.init('mousedown');折中的方式：鼠标悬停延迟一定时间才会预加载如果用户在您选择的延迟过后仍悬停在链接上，则该网页将开始预加载。推荐的延迟时间为：100ms和50ms。超过100ms效果比mousedo…