2014年1月

不设置z-index时的显示层级

本文的由来,在看 一淘九宫格的面试题 这篇文章的时候,发现 雨夜带刀 的实现方案没有使用z-index实现了层级的更改效果,于是便产生了好奇;问过几个前端,无果;经过一番google之后,得以下文档:

Standard blocks (DIV #5) in the normal flow, without any positioning property, are always rendered before positioned elements, and appear below them, even if they come later in the HTML hierarchy.


Positioned elements without z-index applied or z-index: 0 are on a higher stacking level than non-positioned elements.

大概意思是:
没有指定z-index的时候,定位元素要晚于非定位元素渲染,这样使得定位元素拥有更高的显示层级。

QQ20140128-1.png

参考:

jQuery-pjax的坑

白话解释:利用ajax进行页面的局部刷新,并可以实现浏览器前进后退 的一个库

bower install jquery-pjax -S --allow-root

使用

官方文档上是这样写的:

$(document.body).pjax("a.btn", ".container");

神马?没搞定?

QQ20140119-1.png

额!确实没搞定,于是第一个想到的就是google。无奈转载太多,而且提供的demo没有一个正常工作的(PS:鄙视转载无验证)。

根据上图中提示的代码位置,找到了locationReplace,在根据xhr请求被cancel,定位到代码223行,输出错误为timeout,找至196行,发现插件的默认值中根本就没有timeout选项,于是设置超时10s就解决这个问题了:

$(document.body).pjax("a.btn", ".container", {timeout: 10000});

PS:不知官方文档使用方法为何没有提及,不知我国人写出demo之后有无测试过

理解Laravel Eloquent的cache

Eloquent::remember

// 从数据库中取出前5个用户,并缓存结果。
User::remember(10)->take(5)->get();
// 下面这句会缓存posts么?
User::with(array('posts'))->remember(10)->take(5)->get();

先找一下remember在哪定义的!

remember 方法的定义

# grep -nC1 "Eloquent" app/config/app.php
150-        'DB'              => 'Illuminate\Support\Facades\DB',
151:        'Eloquent'        => 'Illuminate\Database\Eloquent\Model',
152-        'Event'           => 'Illuminate\Support\Facades\Event',
# grep -nC3 "function remember(" vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php
1086-     * @param  string  $key
1087-     * @return \Illuminate\Database\Query\Builder|static
1088-     */
1089:    public function remember($minutes, $key = null)
1090-    {
1091-        list($this->cacheMinutes, $this->cacheKey) = array($minutes, $key);
1092-

这里EloquentModel的一个别名,而Model中并没有定义remember方法,而是用了装饰者设计模式通过__call魔术方法调用了Builder的方法。其实他是在内部实例化Builder的,有点“反向代理”的意思。

Builder在调用remember的时候做了个标记,在get的时候对这个标记作了判断,对查询结果做了缓存的写入和读取。这就不难理解remember方法只会对单个query查询结果进行缓存。

回头看

User::with(array('posts'))->remember(10)->take(5)->get();

使用with只是将1 + 5 * 1次query,优化成了1 + 1次;而不是想象中的一次缓存该条语句产生的所有query的结果。

缓存关联Model

User::with(array('posts' => function ($query)
    {
        return $query->remember(10);
    }))->remember(10)->take(5)->get();

当然,在定义model relation的时候也可以将 remember() 跟在后面,但我不认为这是一个好的方法。

function posts()
{
    return $this->hasMany('Post')->remember(10);
}

vagrant的坑

vagrant project和 虚拟机 关系丢失

额,这个问题不知道怎么产生的,但它确实出现了。解决办法:

VBoxManage list vms
# "vagrant_default_1389674864" {aea24237-3b9e-45b2-8593-59e2b63b34b8}
# 修改id文件
vim .vagrant/machines/default/virtualbox/id
# 或者直接
echo 'aea24237-3b9e-45b2-8593-59e2b63b34b8' > .vagrant/machines/default/virtualbox/id

vagrant 共享目录的权限

#...
config.vm.synced_folder "/Applications/MAMP/htdocs/plus.tool.lu", "/var/www/html"
#...

好吧,在虚拟机里面chmod -R 777 /var/www/html没用,google之后发现,需要在Vagrantfile里面设置。Vagrant Synced Folders Permissions

# ...
config.vm.synced_folder "/Applications/MAMP/htdocs/plus.tool.lu", "/var/www/html",
    id: "vagrant-root",
    owner: "nobody",
    group: "nobody",
    mount_options: ["dmode=775,fmode=664"]
# ...

[scrapy] laracasts爬虫

购买了1个月的laracasts.com的帐号,又怕有的时候没时间看,所以就都抓取下来。

  1. 将标题,描述都保存到mysql数据库

  2. 将视频下载到本地

CREATE TABLE `laracasts_lessons` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `title` varchar(255) NOT NULL DEFAULT '',
  `downlink` varchar(255) NOT NULL DEFAULT '',
  `description` text NOT NULL,
  `path` varchar(255) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

这里说一下流程,代码就不贴出来了,有需要的可以下载附件。请先修改文件内的数据库用户名密码,和laracasts的账户,再执行./laracasts.sh

登录 -> 遍历列表页面 -> 遍历课程页面 -> 获取信息 -> 下载视频 -> 保存到MySQL

laracasts.zip

在项目中使用gulp

安装gulp

npm install gulp -g
npm install gulp gulp-coffee gulp-concat --save-dev

配置

我的js第三方库是使用bower来管理的,.bowerrc

{
    "directory": "public/js/vendor"
}

gulp这样配置,暂时只用了coffee的编译,没有使用js的合并和混淆

var gulp = require('gulp');
var coffee = require('gulp-coffee');
var concat = require('gulp-concat');
var uglify = require('gulp-uglify');
var rename = require('gulp-rename');

gulp.task('coffee', function () {
    gulp.src(['./public/js/**/*.coffee', '!./public/js/vendor/**'])
        .pipe(coffee())
        .pipe(gulp.dest('./public/js/'));
});

gulp.task('scripts', function () {
    gulp.src(['./public/js/**/*.js', '!./public/js/vendor/**'])
        .pipe(concat('all.js'))
        .pipe(gulp.dest('./public/dist'))
        .pipe(rename('all.min.js'))
        .pipe(uglify())
        .pipe(gulp.dest('./public/dist'));
});

gulp.task('default', function() {
    gulp.run('coffee');
    // gulp.run('scripts');
    gulp.watch(['./public/js/**/*.coffee', '!./public/js/vendor/**'], function () {
        gulp.run('coffee');
    });
    if (0) {
        gulp.watch(['./public/js/**/*.js', '!./public/js/vendor/**'], function () {
            gulp.run('scripts');
        });
    }
});

[Laravel4] 增加自定义的function

vendor/laravel/framework/src/Illuminate/Support/helpers.php Laravel4这个自带的function很不错,但是有的时候想扩展自己的方法;问题是该在哪边require进去。

建立一个文件app/Service/helpers.php,所有的自定义方法就写在这个里面了;然后修改composer.json,在autoload里面加上该文件,再执行composer du就可以了

{
    "autoload": {
        // ...
        "files": ["app/Service/helpers.php"]
    }
}

html5 drag事件

html5的drag drop相关事件

drag
dragstart
dragend
dragover
dragenter
dragleave
drop

dragend的坑!

The dragstart event is fired when the user starts dragging an element or text selection.

MDN的文档说的不错,dragstart只有在element或者选中文字拖放开始的时候触发,也就是拖放文件的时候不会触发。

The dragend event is fired when a drag operation is being ended (by releasing a mouse button or hitting the escape key).

尼玛,这没说啊,试过才知道。dragstartdragend文件拖放是不会触发的。