基于Vuejs、vue-router、iview的管理后台

上一篇分享的是使用angularjs及materialdesign的管理后台前端页面的实现。因为感觉input的输入框实在是太丑了,并且用户端的页面我早已开发完毕,就等着后端给接口了,所以就萌生出了使用心中一直念念不忘的Vuejs来实现一版管理后台。

这个使用了Vue-cli来构建vue架构,使用vue-router来搭建路由,使用iview来作为UI框架。

项目构建

  1. 安装nodejs
    nodejs安装及常用快捷键
    建议安装nvm来控制nodejs的版本,上面的链接里有详细的步骤,包括启动node服务常用的PM2等等…
  2. 全局安装webpack、vue-cli脚手架
    npm install -g webpack vue-cli;

  3. 创建工程
    vue init webpack-simple <project name>
    这里直接一路回车就可以了。
    注意:工程名不能是中文

  4. 安装项目依赖
    进入工程,输入npm install就可以了。

  5. 安装路由模块vue-router、网络请求模块vue-resource模块
    npm install --save vue-router vue-resource
    这个会安装到package.jsondependencies中。

  6. 安装UI框架 iView
    npm install --save iview

  7. 使用iView、vue-router、vue-resource

# main.js
import Vue from 'vue';
import VueRouter from 'vue-router';
import VueResource from 'vue-resource';
import iview from 'iview';
import 'iview/dist/styles/iview.css';
import App from './App.vue';

Vue.config.debug = true;
Vue.use(VueRouter);
Vue.use(VueResource);
Vue.use(iview);
  1. 修改webpack.config.js配置文件
    因为使用iView需要引用其css,但是最初的webpack.config.js文件里面并没有配置读取css文件和字体文件或者有的设定的有问题,所以这里需要我们自行修改一下:
{
    test: /\.js$/,
    loader: 'babel-loader',
    exclude: /node_modules/
 },
 {
    test: /\.css$/,
    loader: "style-loader!css-loader"
 },
 {
    test: /\.(eot|woff|woff2|ttf)([\\?]?.*)$/,
    loader: "file-loader"
 },
 {
    test: /\.(png|jpg|gif|svg)$/,
    loader: 'file-loader',
    options: {
      name: '[name].[ext]?[hash]'
    }
 }

继续阅读基于Vuejs、vue-router、iview的管理后台

基于angularjs与materialDesign的管理后台

最近换了个公司,乱七八糟的事儿比较多,更新耽误了些…
之前还看过一段时间的Vuejs,想着新公司如果做项目的话,用Vuejs去做。然而新公司的技术架构pc端更倾向于Angularjs,而且有专门的前端架构,架子什么的都搭的差不多了,所以来到新公司的第一个项目就用Angularjs做的。

通过这个项目,我对eslint、gitignore、proxy也算有了接触。毕竟以前做项目的时候也没关注过这些。这个项目是用gulp跟webpack配合使用的。也是直接用的旧有的架子,没做什么改动。
现在就说一下用Angularjs做的这个项目吧。

目录结构

  • app: 源代码
    • views: 一个页面一个文件夹
    • *.ctrl Controller
    • *.html Controller对应的页面
    • *.scss Controller对应页面的样式表
    • services: 服务,一个页面可能有多个服务,与页面一一对应
    • filters: 过滤器
    • app.js: 项目入口文件
    • index.html: index
  • dest: 编译后代码存放的位置,源码中不存在
  • .eslintrc.json: 语法检查
  • .gitignore: git忽略目录
  • .babelrc: babel编译配置
  • … 其他配置

入口文件 app.js

这个项目使用了angular-resource、angular-material等框架,因为Angularjs是依赖注入的,所以所有依赖的框架、插件甚至服务过滤器等等都需要import进来,并且注入到angular程序中。

Dependencies 项目依赖

import angular from 'angular';
import 'angular-material';
import 'angular-resource';
...

View 项目页面,包括其中的Controller及template等

import { Template, Controller } from './views/page1/page1.ctrl';
...

Service 服务

import IndexMenuResource from './services/index-menu.resource'

主程序,所有注入的内容都会在这里体现。

angular.module('app', [
    'ngResource', 'ngRoute', 'ngMaterial' ...
])
.controller('controller', Controller)
.service('IndexMenuResource', IndexMenuResource)
.config(['$routeProvider', function($routeProvider) {
    $routeProvider.when('/', {
        template: Template,
        controller: Controller,
        controllerAs: 'ctrl'
        }) ...
    }]);

在这里,我每一个只写了一个,需要说明一点,使用controllerAs,在其他页面的对应的controller中,就可以不用$scope,转而使用this就可以了。然后需要在controller对应的template中,每一个变量前面都加上controllerAs的内容,也就是上文中的ctrl
这个地方也可以将路由模块抽离出来,但是,看着这个文件也不大,就放在这里吧,维护起来也还算好维护。

登录模块

登录模块是最后加的,原型图中也没有这个,但是感觉作为一个后台管理系统,如果没有这个模块,岂不是所有人知道网址就能随意修改内容了么…于是跟后端同事商量了一下,就把这个做上了。因为时间比较紧,项目经理就直接说,暂不需要权限管理,注册之类的,直接把这个东西在后台写死就好。但是后端同学还是为user单独建了张表,把权限也留出口来,以后如果有需要直接加上就好了。

继续阅读基于angularjs与materialDesign的管理后台

vue匹配模板简单实现

之前在学习新框架的时候,只是简单的跟着教程一步一步的敲demo,从来没有想过这个框架是如何实现的,简单的功能我能不能实现。最近打算开始学习Vue,觉得还是尝试一下能不能自己简单的实现其中的某些功能吧。

感觉模板引擎后端同学用的多一些,像jade、FreeMarker等,这个通常是在客户端发出HTTP请求之后,应用层的控制器(Controller)接收,通过应用层的服务器(service)访问数据库,然后封装到模型层(Model),再跳转到视图层(View),通过模板引擎生成HTML代码,最后返回给客户端浏览器。

但是Vuejs也是有模板的,他的模板引擎是在客户端浏览器的内存中处理生成的。所以我们用模板的时候,显示出来的是要渲染的数据。

Vue官网的第一个demo

<div id="app">
    {{ message }}
</div>
var app = new Vue({
    el: '#app',
    data: {
        message: 'Hello Vue!'
    }
});

看到这个部分,感觉应该可以通过正则来简单的实现一下:
html部分不变。

正则部分:

首先想到的是匹配两边的大括号,/\{\{\}\}/,注意转译;
然后我们需要匹配大括号中间的内容,[\w]+;
这里需要注意一个问题,在匹配的内容前后可能会有空格,所以这里内容部分我们需要修改成\s*[\w]+\s*;
但是如果需要替换的话,使用正则的分组用法$1会比较轻松的解决这个问题;
所以正则的最终版就变成了/(\{\{\s*([\w]+)\s*\}\})/g;

js部分:
function vue(options) {
    var context = document.querySelector(options.el);
    var html = context.innerHTML;
    var regex = /(\{\{\s*([\w]+)\s*\}\})/g;
    while(regex.test(html)) {
        html = html.replace(RegExp.$1, options.data[RegExp.$2]);
    }
    context.innerHTML = html;
}

$1是最先匹配到的{% raw %}{{}}{% endraw %}
包括其内的部分,$2是匹配的要替换的对象。
使用方法跟vue的使用方法一样。
这样第一个demo我们就简单的实现了。当然相比vue有非常多的缺陷,比如不可以通过app.message来修改数据…

继续阅读vue匹配模板简单实现

前端构建工具的简易实现

虽然说之前用过gulp、webpack这种前端构建工具,但是自己也只是单纯的使用,从来没想过这些东西到底是怎样实现的。最近看了一节公开课,觉得很受启发,现在就说一下我的这个前端构建工具是如何实现的。

功能

开发环境

zst dev 实现保存代码自动刷新的功能。

生产环境

zst dist 这个实现的功能较多:
1. 自动生成dist目录
2. 合并压缩js、css添加时间戳输出到dist目录
3. 将favicon.ico文件复制到dist目录
4. 处理index.html文件,删除注释
5. 如果开发的是移动端页面,还会在index.html中插入移动端meta及处理rem的代码

用到的模块:

express、watch、command、fs、path、uglifyjs、uglifycss、cheerio、open、package、http、socket.io

开发

config

我们需要一个config对象来作为项目的配置

const config = {
    server: {
        ip: "http://localhost",
        port: 3000
    },
    input: "./src",
    output: "./dist",
    info: "INFO  ",
    isPhone: true, //是否是手机
};

server字段设置的是服务的ip跟端口,input字段是输入路径,output字段是输出路径,info字段是打印log的日志头,isPhone字段是是否是移动端。

开发环境

  1. 首先,我们需要创建一个http服务在3000端口,这里我们使用express这个框架来实现。
var app = require('express');
var server = require('http').createServer(app);
server.listen(config.server.port, function (req, res) {
    log('server start at '+config.server.ip+":"+config.server.port);
});
app.get('/', function (req, res) {
    res.send(getHtml(config.isPhone,config.input));
});

function getHtml(isPhone,path) {
    var path = path || './src';
    var devHtml = fs.readFileSync(path +'/index.html', 'utf-8') + fs.readFileSync('./socket.xml');
    if(isPhone) return fs.readFileSync('./isphone.xml') + devHtml;
    else return devHtml;
}

在这段代码中,server.listen是在config.server.port端口开启一个服务器,cb会在服务开启后执行。
app.get()是express的路由,当客户端访问到/时,返回给客户端什么内容。
getHtml方法最终返回的是加上处理自动刷新代码的index.html。
如果要开启服务器后自动打开客户端,可以使用open插件:

var open = require('open'); //自动打开浏览器
server.listen(config.server.port, function (req, res) {
    log('server start at '+config.server.ip+":"+config.server.port);
    open(config.server.ip+":"+config.server.port);
});
  1. 使用socket.io及watch
var io = require('socket.io').listen(server);
io.sockets.on('connection', function (socket) {
    watch.watchTree(config.input, function (f, curr, prev) {
        if (typeof f == "object" && prev === null && curr === null) {
            // Finished walking the tree
        } else { // f was changed
            socket.emit('file-change');
        }
    });
    log('client connected');
});

socket.io是websocket长链接通信的封装,之前在egret游戏中使用了websocket通信,但是没有使用socket.io。
这个就是当socket连接后,执行的操作,也就是使用watch插件进行文件的监控。使用方式都有注释,也可以从github上进行搜索。最后一个else中,socket.emit是自定义的事件名,文件改变。

继续阅读前端构建工具的简易实现

doTjs详细介绍

doT.js是一个小巧快速的JavaScript模板引擎,他可以帮助我们在html端更好的使用json数据,且无需依赖其他插件就可工作。整个插件只有120行,.min.js文件甚至只有4kb。
官网:http://olado.github.io/doT/index.html

安装

npm install dot

1. 用于nodejs

require('dot');

2. 浏览器

<script type="text/javascript" src="./doT.js"></script>

使用

html:
<div id="int"></div>

1. 赋值

格式:
{% raw %}
{{= }}
{% endraw %}

模板:

<script id="intTmpl" type="text/template">
    <p>My name is {{=it.name}}, I'm {{=it.age}}</p>
</script>

调用方式:

var data = {name: 'John', age: 26};
var intTmpl = doT.template(document.getElementById('intTmpl').innerText);
document.getElementById('int').innerHTML = intTmpl(data);

从上面的代码中我们可以看到,有一个it,这个是代指引用的数据,也就是代码中的datait.name就是data.name,所以这个在使用方法上实际跟json对象是一样一样的。
在调用方式上,都是3个步骤:
1. 先声明数据源,也就是代码中的data,这个一般情况下是后端同学传回来的。
2. 找到要将数据填进去的模板。
3. 找到你要渲染的位置。这个位置就是上面html中的int

2. 条件

格式:

{% raw %}
{{? }}
{% endraw %} //if
{% raw %}
{{?? }}
{% endraw %} //else if
{% raw %}
{{??}}
{% endraw %} //else

模板:

<script id="intTmpl" type="text/template">
    {{? it.name}}
    <p>Hello, my name is {{=it.name}}</p>
    {{?? it.age}}
    <p>I'm {{=it.age}}</p>
    {{??}}
    <p>Nobody here!</p>
</script>

调用方式:

var data = {name: 'John', age: '26'};
var intTmpl = doT.template(document.getElementById('intTmpl').innerText);
document.getElementById('int').innerHTML = intTmpl(data);

调用方式都是一样的。

3. 转译html

格式:
{% raw %}
{{! }}
{% endraw %}
模板:

<script id="intTmpl" type="text/template">
    {{!it.uri}} {{!it.html}}
</script>```
调用方式:  

var data = {uri:”http://www.zhangshuang.top”, html:”html元素“};
剩下的跟上面一样。


转译跟赋值的区别: 转译是让html标签不使用html引擎渲染,也就是不会解析html构建DOM树,也不渲染树结构、布局、绘制样式等等,而是直接变成字符串渲染出来。 赋值的话,如果数据中有html标签,就会解析html构建DOM树,渲染树结构,渲染树布局,绘制渲染树。 ##### 4. 数组迭代 格式: {% raw %} {{~ }} {% endraw %} 模板:

{{~it.array:value:index}}

{{=index+1}}:{{=value}}

{{~}}


调用方式:

var data = {array: [“a1”, “a2”, “a3”]};
剩下两个步骤跟上面一样。
“`

其中it.array是找到那个数组value是数组中的每一个值,index是数组的下标,换成a或b或其他都行。

上面这些事比较常用的,甚至,只要会使用json都能很好的使用doT.js,也就是每一个都通过赋值的方式去找。还有一些其他的,如果有想了解的也可以去官网了解一下。

基础真的很重要

还记得之前写过的一篇博客,egret游戏引擎入门(六) 在说到其中的一个参数userID的位数为18位,在传输过来的时候丧失精准度的问题。当时我跟几个小伙伴对这个问题纠结了一晚上,其实这个问题在犀牛书中就有提到过(第6版,p34,3.1数字)。

按照JavaScript中的数字格式,能够表示的整数范围是从 -9007199254740992 ~ 9007199254740992,包含边界值。如果使用了超过此范围的整数,则无发保证低位数字的精准度。

从上面这段文字中我们可以看到,JavaScript语言只能保证数字的长度在16位以内,如果超过16位,则超出的部分会丧失精准度。

从这里可以看出,基础真的好重要呀,所以近期内会重读犀牛书、高程之类的。

es6变量声明的6种方法

ES5只有两种变量声明的方法,分别是varfunction关键字。ES6相比ES5多了letconstimportclass这四个关键字。
最早的ES5使用varfunction这两个关键字声明的变量会触发变量声明提前,这个大家都很熟悉。但是ES6新增的letconst这两个块级作用域的变量声明关键字则不会。

let

在代码块内,使用let关键字声明变量之前,该变量都是不可使用的,也就是在这个代码块内,只要声明的该变量,但是在该变量声明之前调用了,就会报错。这在语法上称为“暂时性死区(参照阮一峰的ES6入门,见下例:)。”

{
    console.log(b); //ReferenceError
    let b = 123;
}

const

使用const关键字声明变量的作用域也是块级作用域,但是constlet还是有着非常明显的区别的:使用let关键字声明的变量,它的值可以改变;使用const关键字声明的变量,它的值可以改变,但是变量所指向的内存中的地址是不可改变的。

{
    const a = {
        p: 123,
        d: 234
    }

    a.f = 345;
}

上述代码是不会出错的。但是如下操作是会报错的:

{
    const a = {
        a: 123
    }

    a = { // TypeError: Assignment to constant variable
        b: 234
    }
}

这个就是改变了常量a在内存中的地址。

import

import 是用于在一个模块中加载另一个含有export的模块。写法如下:

import React from 'react';
或
import React, { Component } from 'react';

前面的这个React实际是自己定义的一个要引入文件的名称,也就相当于声明变量。这个就是引入react模块并命名为React,从react中引入React以及Component。

class

es6引入了class(类)这个概念,使其看起来更加像传统的面向对象的语言例如java或者C++。通过class关键字,可以定义类(声明或定义了一个对象)。

class Person() {

}

类里面还有构造方法(constructor),这个就不在这里描述了。

HTTP请求的GET与POST

最近跟公司后端的小伙伴们沟通才知道,原来后端在面试的时候,也经常会遇到GET、POST这样的问题。
HTTP请求GET方法和POST方法有什么区别?
感觉把区别都说了出来,但是当问题在深入一点的时候,发现自己只是知道了结果,但是不知道原理。看来以后还要在知识的深度上狠下功夫。不都说了,下面就深入了解一下GET方法和POST方法的区别吧。

HTTP的请求类型

GET方法与POST方法都是HTTP的请求类型,另外还有两种平常用的不多的PUT(更新)、DELETE(删除)类型。

区别一:

GET方法是从指定的资源请求数据,POST方法是向指定的资源提交要处理的数据。

区别二:

GET方法请求有长度限制,POST方法请求没有长度限制。
这个理解起来比较简单,因为在发送数据时,GET方法是在url的末尾拼接数据,而url的长度是有限的,最长2048个字符,这个限制要根据不同的浏览器厂商而定。而POST方法是在HTTP的消息主体(request body)中发送的,所以没有限制。

区别三:

GET方法因为请求的数据是拼接在url中的,所以存书签的时候能够储存。而POST方法则不行。

区别四:

GET方法不如POST方法安全。
GET方法发送的数据是拼接在url上的,所以发送的信息都是可见的,并且参数会保留在浏览器的历史中,可以被缓存,所以不安全。而POST方法请求的参数不会被保存在浏览器历史或者web服务器日志中。

区别五:

GET方法点击后退或者刷新按钮时不会有操作。而POST方法的数据会重新提交。

区别六:

编码类型不一样:
GET方法使用的编码类型是:application/x-www-form-urlencoded;POST方法使用的编码类型是:application/x-www-form-urlencodedmultipart/form-data,为二进制数据使用多重编码。

区别七:

数据类型不一样:
GET方法只允许ASCII字符。POST方法没有限制,也允许二进制数据。

区别八:

GET方法是幂等的,POST方法是非幂等的。
再引入幂等的概念

在编程中.一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。幂等函数,或幂等方法,是指可以使用相同参数重复执行,并能获得相同结果的函数。这些函数不会影响系统状态,也不用担心重复执行会对系统造成改变。例如,“setTrue()”函数就是一个幂等函数,无论多次执行,其结果都是一样的.更复杂的操作幂等保证是利用唯一交易号(流水号)实现.

区别九:

GET方法无副作用,POST方法有副作用。
副作用是指,在发送完一个请求后,网站上的资源状态没有发生修改。比如注册新用户,发生了改变,就是有副作用。而请求用户数据,数据没有发生改变,就是没有副作用。

参考

  1. HTTP head请求
  2. post和get请求的区别

js作用域

作用域

引:Engine/Scope Conversation

Engine/Scope Conversation
from You Don’t Know JS: Scope & Closures
这一章节,生动详细的向我们描述了js解析引擎是如何运行的,这对理解我们的作用域非常有帮助,有兴趣的可以瞅一眼。下面通过几个简单的题来巩固一下。

1.下面代码alert显示的内容是什么?
function a() {
    var foo = 1;
    b();
}

function b() {
    alert(foo);
}

function c() {
    var foo = 1;
    d();
    function d() {
        alert(foo);
    }
}

a();
c();

这道题主要考察的是js中变量的作用域的问题。运行a(),得到的结果是foo is not defined,且程序停止,不会再执行c(),如果把a()注释掉的话,会alert(1)
function a(){}中声明的变量foo是局部变量,无法被外界访问,所以function b(){}会报错。

function d(){}中的foo虽然也是局部变量,但是foo的作用域恰好包括了function d(){},所以这个foo可以找到。

2.下面代码console显示的内容是什么?
var scope="global";  
function t(){  
    console.log(scope);  
    var scope = "local";
    console.log(scope);  
}  
t();

有些童鞋想当然的认为,因为代码还没有执行到var scope = "local",所以第一个显示的内容是global,第二个是local
然而事实却不是这样的,第一个显示的内容是undefined。如果按照js解析引擎去解读这段代码,应该可以这样去理解:

var scope; //只是知道有这个变量,还没有进行赋值
function t() {} //函数声明提前
t(); //执行这个方法
function t() { //开始观察方法的内部
    var scope; //这个是局部变量,变量声明提前
    console.log(scope); //没有赋值,所以为undefined
    scope = "local"; //对局部变量进行赋值
    console.log(scope; //显示为 local
}
3.es5跟es6的作用域区别

在es5中,是没有块级作用域这个概念的,只有函数作用域,下面的这个例子就可以说明:

var name="global";  
if(true){  
    var name="local";  
    console.log(name)  
}  
console.log(name);

这里的两个console显示的内容都是local,因为如果有块级作用域的话,第二个console出来的内容应该是global,但是name这个变量被if中的name给覆盖了。
es6中,多了let这个声明变量的关键字,使用let声明变量的作用域是块级作用域。还是上面es5中的代码,我们将if中的var变为let看一下:

var name="global";  
if(true){  
    let name="local";  
    console.log(name)  
}  
console.log(name);  

这时,console出来的内容就是

local
global

这就证实了,使用let声明变量的作用域是块级作用域。

4.为下面html中每一个li添加点击事件,点击alert出自己为ul中的第几个。
<ul>
    <li>内容</li>
    <li>内容</li>
    <li>内容</li>
    <li>内容</li>
    <li>内容</li>
</ul>

下面代码中是否有问题?如果有应该如何改善?

var liList = document.getElementsByTagName('li');
for(var i = 0, li; li = liList[i]; i++) {
    li.addEventListener('click', function() {
        alert(i);
    }, false);
}

这道题有两个问题,第一个是for循环的写法上存在问题,没有说明i的最大值是多少;第二个问题是根据js中变量的作用域链来看,i在这个匿名函数中没有声明,所以会去外面找,但是这个i因为没有最大值,一直++,所以也不会知道i是多少。
应该使用如下方法去写:
方法一:

var liList = document.getElementsByTagName('li');
for(var i = 0, len = liList.length; i < len; i++) {
    (function (i) {
        liList[i].addEventListener('click', function () {
            alert(i);
        });
    })(i);
}

这种方法使用闭包的方式,将i传入。不会出现每次调用因为匿名函数中找不到i,去外部找,i已经加到最大值的情况。
方法二:

for(let i = 0, len = liList.length; i < len; i++) {
    liList[i].addEventListener('click', function () {
        alert(i);
    })
}

使用es6的块级作用域解决。

浏览器兼容问题【转】

1. ie6.0横向margin加倍

产生因素:块属性、float、有横向margin。
解决方法:display:inline;

2. ie6.0下默认有行高

解决方法:overflow:hidden;或font-size:0;或line-height:xx px;

3. 在各个浏览器下img有空隙(原因是:回车。)


解决方法:让图片浮动。

4. 一个父标签与几个子标签嵌套,父标签不浮动,子标签float,子标签不撑开父的高度。

解决方法:a 在子标签最后清浮动
{
<div style="height:0;clear:both;">
&nbsp;
</div>
}

b 父标签添加{overflow:hidden;}
c 给父标签设置高度

5. Ie6下,不识别最大宽、高度和最小宽高度,意即min-width/height和 Max-width/height在ie6中没效果,

解决方法:
(1):

.abc{border:1px blue solid;width:200px;height:200px;}
html>body .abc{width:auto;height:auto;min-width:200px;min-height:200px;}

(2):

.abc{width:200px;height:200px;_width:200px;_height:200px;}

(因为ie6有一个特征,当定义一个高度时,如果内容超过高度,元素会自动调整高度。)

6. Ie6里面:如li设宽、高,并且li里面的标签浮动,那么li之间会有间距

解决方法:li不设宽、高或者li内的标签不浮动

7. li之间有间距

解决方法:li 设置vertical-align:middle;
8 3像素问题:ie6下,当浮动元素与流动元素并列显示时,他们之间会存在三像素问题。
解决方法:用hack技术, 例如:所有浏览器通用 height:100px;
ie6专用_height:100px;
ie7专用*+height:100px;
ie6/ie7共用*height:100px;

9. 当定义行内元素为包含框时,且包含框包含的绝对定位元素以百分比为单位进行定位时,会出现混乱。

解决方法:在行内元素里加入`{zoom:1;}`

10. 当多个浮动元素中间夹杂着HTML注释语句时,如果浮动元素宽度为100%,则在下一行多显示一个上一行最后一个字符。

解决办法:给浮动元素添加display:inline;

11. opacity 定义元素的不透明度

filter:alpha(opacity=80);/*ie支持该属性*/
opacity:0.8;/*支持css3的浏览器*/

12. 两个块元素,竖向的margin值不增加,会重叠,其间距为最大margin值。

13. 优先级:

被!important 注明的css属性具有最高优先级(.abc{color:red !important;})。但在ie6中!important具有一个bug:在同一组css属性中,!important不起作用。

14. 火狐不识别background-position-y 或background-position-x;

15. ie6 不支持 fixed

/*对于非IE6可以这样写*/
#top{  
    position:fixed;  
    bottom:0;  
    right:20px;  
}  

/*但是IE6是不支持fixed定位的,需要另外重写*/
#top{  
    position:fixed;  
    _position:absolute;  
    top:0;  
    right:20px;  
    _bottom:auto;  
    _top:expression(eval(document.documentElement.scrollTop));
}  

/*使用hack使IE6实现该效果,但这个东东会闪烁,需要以下代码*/
*html{  
    background-image:url(about:blank);  
    background-attachment:fixed;  
}  

/*使固定在顶部*/
#top{  
    _position:absolute;  
    _bottom:auto;  
    _top:expression(eval(document.documentElement.scrollTop));  
}  

/*固定在底部*/
#top{  
    _position:absolute;  
    _bottom:auto;  
    _top:expression(eval(document.documentElement.scrollTop+document.documentElement.clientHeight-this.offsetHeight-(parseInt(this.currentStyle.marginTop)||0)-(parseInt(this.currentStyle.marginBottom)||0)));  
}  
/*垂直居中*/
#top{
    position:fixed;
    top:50%;
    margin-top:-50px;
    _position:absolute;
    _top:expression(eval(document.documentElement.scrollTop+document.documentElement.clientHeight/2));
}

16. 解决 ie6 最大、最小宽高 hack方法

/* 最小宽度 */
.min_width{
    min-width:300px;
    _width:expression(parseInt(this.clientWidth) < 300 ? "300px" : this.clientWidth);
}

/* 最大宽度 */
.max_width{
   max-width:600px;
   _width:expression(parseInt(this.clientWidth) > 600 ? "600px" : this.clientWidth);
}

/* 最小高度 */
.min_height{
   min-height:200px;
   _height:expression(parseInt(this.clientHeight) < 200 ? "200px" : this.clientHeight);
}

/* 最大高度 */
.max_height{
   max-height:400px;
   _height:expression(parseInt(this.clientHeight) > 400 ? "400px" : this.clientHeight);
}

17. z-index不起作用的 bug

1)ie6下 首先讲讲第一种z-index无论设置多高都不起作用情况。这种情况发生的条件有三个:1、父标签position属性为relative;2、问题标签含有浮动(float)属性。
2)所有浏览器:它只认第一个爸爸
层级的高低不仅要看自己,还要看自己的老爸这个后台是否够硬。用术语具体描述为:
父标签position属性为relative或absolute时,子标签的absolute属性是相对于父标签而言的。而在IE6下,层级的表现有时候不是看子标签的z-index多高,而要看它们的父标签的z-index谁高谁低。

18. ie各个版本hack

/*类内部hack:*/
    .header {_width:100px;}            /* IE6专用*/
    .header {*+width:100px;}        /* IE7专用*/
    .header {*width:100px;}            /* IE6、IE7共用*/
    .header {width:100px\0;}        /* IE8、IE9共用*/
    .header {width:100px\9;}        /* IE6、IE7、IE8、IE9共用*/
    .header {width:330px\9\0;}    /* IE9专用*/

/*选择器Hack:*/
    *html .header{}        /*IE6*/
    *+html .header{}    /*IE7*/