土法炮制博客的日历插件
自从网易博客玩球后,改用 Typecho
写日志已经有一段时间。可能我要求比较低,一直满意。
心血来潮想加个日历插件在右侧栏上, 搜了下现有的插件emmm ...只有一个2016年的版本,功能比较简陋就真的只显示个月历而已。
眼看博客程序已经3年没有更新,估计是指望不上别人自己动手改造一个。
看了一下 Typecho的插件开发说明,嫌麻烦。还是按自己熟悉的粗暴手法来强行嫁接吧!
最终效果如图(如果没出错的话应该在页面右边已经看到实物了)
我要实现的功能不多
- 要能显示月历,能前后翻月
- 样式要简洁,不突兀,与界面低调融合在一起
- 要标记有博客的日期,点上去的话要切换到当天
- 如果从下面按月归档的链接点进去的话,日历要跟随切换到当前月份
想了下,我用过的layDate日历插件应该能满足这个需求,也是一个已经3、4年没有更新的项目正好凑一对。
下面开干!
1.编辑外观文件 sidebar.php
进入博客后台 -> 控制台
-> 外观
-> 编辑当前外观
-> 选择 sidebar.php
在对应的位置插入以下代码(对blog程序做最小化改动,选择外部引用脚本),然后点保存文件
<!--//自定义控件:日历-->
<section class="widget">
<h3 class="widget-title">一个土土的日历</h3>
<?php
require(dirname(__FILE__)."/../../../../blogplugins/plugin_typecho_laydate.php");
?>
</section>
大概看起来就是这样
当中的路径根据自己的实际情况调整, 我放到博客路径同级的另一个文件夹 blogplugins
里,。
另外额外说一句,在下文的js中使用了jQuery
语法, 如果博客之前没有用到的话建议这里也引用一下,也可以用 zepto
代替。
准备依赖的日历控件 layDate.js
按照layDate的文档说明放到任意路径即可,我的例子是放到了 /js/layDate.js
路径下。注意有个 theme的文件夹要一起放进去不要遗漏。
插件脚本 plugin_typecho_laydate.php
不啰嗦了,直接上源码。
本例博客主程序路径在 /blog/
,
插件的路径在 /blogplugins/plugin_typecho_laydate.php
日历插件的路径在 /js/laydate.js
<?php
/**
* plugin_typecho_laydate
* @author f77@outlook.com
* @copyright 2020
*/
define("DB_HOST","localhost");
define("DB_PORT","3306");
define("DB_DATABASE","blog");
define("DB_USER","***账号***");
define("DB_PASS","***密码***");
include("../class/fmysql.class.php"); #mysql组件,源码原理略
$uri = $_SERVER['REQUEST_URI'];
$init_date = date("Y-m-d");//默认定位日历在今天
$ts_now = strtotime($init_date);
//分析是否日期,是否需要初始化日期
$parts = explode('/',$uri);
$p_count = count($parts);
if($p_count>=4){ //月份归档有/结尾,所以是
//带日期blog会自动补地址栏最后的/所以还是要转换成offset计算
if($parts[$p_count-4]=='index.php')
$p_offset = $p_count;
elseif($parts[$p_count-5]=='index.php')
$p_offset = $p_count-1;
else
$p_offset = 0;
if($p_offset){
$str_date = $parts[$p_offset-3]."-".$parts[$p_offset-2]."-".($parts[$p_offset-1]?$parts[$p_offset-1]:'01'); //月份总览不带日期,所以定位在1号
if($new_init_ts = strtotime($str_date)){ //返回false如果不是合法日期
$init_date = date("Y-m-d",$new_init_ts);
}
}
}
//取出有日志的所有日期合集,定一个时间范围,避免数组太大
//今日取之前半年
//历史日期取前后各3个月
//因为博客程序用的是数据类型 timestamp int(10) 所以range值入乡随俗
$ts_init = strtotime($init_date);
if($ts_init<$ts_now){ //取前后各3月
$range_s = $ts_init-3600*24*92;
$range_e = $ts_init+3600*24*92;
}else{ //取之前6个月
$range_s = $ts_init-3600*24*183;
$range_e = $ts_init+3600*24;//把今天包括进去
}
$s = new FMYSQL();
$sql = "SELECT FROM_UNIXTIME(`created`, '%Y-%m-%d') AS `blogDate`
FROM `typecho_contents`
WHERE `type` = 'post'
AND `created` BETWEEN {$range_s} AND {$range_e}
GROUP BY FROM_UNIXTIME(`created`, '%Y-%m-%d');";
if(!$dates = $s->getData($sql)) $dates = [];
$str_arr_dates = '';//组装输出的日期
foreach($dates as $ditem){
$str_arr_dates .= "'".$ditem["blogDate"]."',";
}
if($str_arr_dates) $str_arr_dates = substr($str_arr_dates,0,-1); //去掉末尾的,
?>
<div id="cald"></div>
<script src="/js/laydate.js"></script> <!-- laydate.js的路径 -->
<script>
//日志的mapper
var blog_dates = [<?php echo $str_arr_dates;?>];
//mDate 参数 YYYY-MM-DD 格式
function hasBlog(mDate){
var result = false;
$(blog_dates).each(function(n,bDate){
if(bDate==mDate){
console.log("date match!",bDate,mDate);
result = true;
return;
}
});
console.log("date no match",mDate);
return result;
}
//laydate实例
laydate.render({
elem: '#cald' //指定元素
,position: 'static'
,theme: 'grid'
,calendar: true
,showBottom: false
,mark: { //标记有日志的日期,空字符串,只显示角标
<?php
$firstObj = true;
foreach($dates as $d){
if(!$firstObj){
echo ","; //第一行以外其余行补个,在最前面
}else{
$firstObj = false;
}
echo "'".$d["blogDate"]."': ''\n";
}
?>
}
,value: '<?php echo $init_date;?>' //初始日期。默认是当前日期
,done: function(value, date){ //点击日期交互回调
console.log("date click:",date.year, date.month, date.date);
//月份和日期是个位数时,需要手动补个0,保证日期格式的一致,下文同
var mDate = date.year +'-'+ (date.month>=10?date.month:('0'+date.month.toString())) +'-'+ (date.date>=10?date.date:('0'+date.date.toString()));
if(hasBlog(mDate)){ //跳转到当天
//注意根据自己的博客路径调整下面的跳转URL
location.href = "/blog/index.php/"+date.year +'/'+ (date.month>=10?date.month:('0'+date.month.toString())) +'/'+ (date.date>=10?date.date:('0'+date.date.toString()));
}else{}//什么也不做,这一天没有日志
}
});
</script>
小结
其实没什么特别的地方,就在于一条 sql 把日志按日期分组查询出来。
然后用 laydate 渲染一个日历组件,对特定的日期做一定的交互。两句说说完了。
相关文档
- layDate的文档: https://www.layui.com/laydate/
- Typecho的文档: http://docs.typecho.org/doku.php
