Author Archive 柏小白

By柏小白

vue 常用方法

vue 获取元素高度
<div ref="elememt" >
</div>

//获取高度值
var height= this.$refs.text.offsetHeight; //100
//获取元素样式值,element 为元素ref="element"
var heightCss = window.getComputedStyle(this.$refs.element).height; // 100px
// var heightCss =this.$refs.element.offsetHeight;  //100 不带px
//获取元素内联样式值
var heightStyle =this.$refs.element.style.height; // 100px
By柏小白

教你怎么实现缩短网址功能

本文将简单介绍,如何去完成一个缩短网址的功能。

Node.js + MySQL + Redis版本的源码地址:github

Demo地址:www.ecool.fun/shortLink

文章阅读大概需要8分钟。

什么是短链接

短链接,通俗来说,就是将长的URL网址,通过程序计算等方式,转换为简短的网址字符串。

大家经常可以从微博或者各类营销短信中,看到短链接,形式一般类似于 t.cn/xxxxxx,点击后,就能跳转到对应的页面。

早期短链接广泛应用于图片上传网站,通过缩短网址URL链接字数,达到减少代码字符串的目的。更便于使用者引用网址,写入代码中,节省字符数空间。常见于网店图片分类的使用,因有字符限制,运用短链接,达到外链图片的目的,自微博盛行以来,在微博字数有限的特色下,短链接也盛行于微博网站,以节省字数,给博主发布更多文字的空间。

将长链接转成短链接,一般是为了方便记忆或者传播。

需要完成的功能

从上面的介绍中,我们得出,缩短网址需要完成以下两个功能点:

  • 将长网址缩短成短链接
  • 点击生成短链接,能正常跳转到原来的长网址页面

全流程设计

其实上述功能点的原理很简单,简单描述一下:

  • 用户输入长网址,服务端接收后进行处理,并根据长网址的内容,生成一个短码,并将映射关系进行存储。然后根据短码拼接出短链接,返回给用户;
  • 用户点击短链接,服务器端根据短链接中的短码,查找到对应的长网址,并302跳转到对应的页面。

知识点:为什么要使用302跳转,而不是301跳转呢?

301是永久重定向,302是临时重定向。短地址一经生成就不会变化,所以用301是符合http语义的。但是如果用了301, Google,百度等搜索引擎,搜索的时候会直接展示真实地址,那我们就无法统计到短地址被点击的次数了,也无法收集用户的Cookie, User Agent 等信息,这些信息可以用来做很多有意思的大数据分析,也是短网址服务商的主要盈利来源。

引自知乎-武林的回答,原文链接

整个流程的设计如下图所示:

短网址全流程

可以看到,我用到了MySQLRedis来存储长网址和短码之间的映射关系。

MySQL想必大家都能理解,但是为什么要用 Redis 呢,直接用数据库不就好了吗?

这个主要是考虑到生成短链接,在投放之后的访问量会比较大,使用 Redis 缓存后,能有效降低数据库的压力。

生成短码的方法

通过上面的全流程设计,会发现主要的问题就是如何通过长网址,去生成对应的短码。

短码一般是由 [a - z, A - Z, 0 - 9] 这62 个字母或数字组成,短码的长度也可以自定义,但一般不超过8位。比较常用的都是6位,6位的短码已经能有568亿种的组合:(26+26+10)^6 = 56800235584,已满足绝大多数的使用场景。

目前比较流行的生成短码方法有:自增id摘要算法普通随机数

  • 自增id

该方法是一种无碰撞的方法,原理是,每新增一个短码,就在上次添加的短码id基础上加1,然后将这个10进制的id值,转化成一个62进制的字符串。

一般利用数据表中的自增id来完成:每次先查询数据表中的自增id最大值max,那么需要插入的长网址对应自增id值就是 max+1,将max+1转成62进制即可得到短码。

但是短码 id 是从一位长度开始递增,短码的长度不固定,不过可以用 id 从指定的数字开始递增的方式来处理,确保所有的短码长度都一致。同时,生成的短码是有序的,可能会有安全的问题,可以将生成的短码id,结合长网址等其他关键字,进行md5运算生成最后的短码。

10进制转成62进制的具体实现:

function string10to62(number) {
    const chars = '0123456789abcdefghigklmnopqrstuvwxyzABCDEFGHIGKLMNOPQRSTUVWXYZ';
    const charsArr = chars.split('');
    const radix = chars.length;
    let qutient = +number;
    let arr = [];
    do{
        let mod = qutient % radix;
        qutient = (qutient - mod) / radix;
        arr.unshift(charsArr[mod]);
    }while(qutient);
    return arr.join('');
}
复制代码
  • 摘要算法

摘要算法又称哈希算法,它表示输入任意长度的数据,输出固定长度的数据。相同的输入数据始终得到相同的输出,不同的输入数据尽量得到不同的输出。

算法思路:

1、将长网址通过 md5 运算,生成 32 字符的 hex string,分为 4 段,每段 8 个字符;

2、对这四段循环处理,取 8 个字节,将其看成 16 进制串,并与 0x3fffffff(30位1) 与操作,即超过 30 位的忽略处理;

3、这 30 位分成 6 段,每 5 位的数字作为字母表的索引取得特定字符,依次进行获得 6 位字符串。

4、总的 md5 串可以获得 4 个 6 位串,取里面的任意一个就可作为这个长网址的短链接 url 地址。

虽然几率很小,但是该方法依然存在碰撞的可能性,解决冲突会比较麻烦。不过该方法生成的短码位数,是固定的,也不存在连续生成的短码有序的情况。

  • 普通随机数

该方法是从62个字符串中随机取出一个6位短码的组合,然后去数据库中查询该短码是否已存在。如果已存在,就继续循环该方法重新获取短码,否则就直接返回。

该方法是最简单的一种实现,不过由于Math.round()方法生成的随机数属于伪随机数,碰撞的可能性也不小。在数据比较多的情况下,可能会循环很多次,才能生成一个不冲突的短码。

具体实现:

// 获取唯一的Link
async getShortLink() {
    const shortLink = this.generateShortLink();

    // 查询数据库中是否存在该链接,如果存在,就直接返回
    const searchResult = await this.searchByLinkInMySQL(shortLink);

    if (searchResult && searchResult.length > 0) {
    // 如果shortLink已经存在,就遍历重新生成
        return this.getShortLink();
    }
    return shortLink;

}

// 生成随机的Link
generateShortLink() {
    let str = '';
    const arr = [
        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
        'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
    ];

    for (let i = 0; i < 6; i++) {
        const pos = Math.round(Math.random() * (arr.length - 1));
        str += arr[pos];
    }
    return str;
}
复制代码

综上,比较推荐使用第一种方法来实现短码的生成。

广告时间

最后,欢迎大家star我们的人人贷大前端团队博客,所有的文章还会同步更新到知乎专栏掘金账号,我们每周都会分享几篇高质量的大前端技术文章。

作者:人人贷大前端技术中心
链接:https://juejin.im/post/5d2d33885188253a2e1b8626
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

By柏小白

JS正则大全

2019年JS正则大全(常用)

来源: any86.github.io/any-rule/

24小时制时间(HH:mm:ss)

/^((?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d$)/

12小时制时间(hh:mm:ss)

/^(1[0-2]|0?[1-9]):[0-5]\d:[0-5]\d$/

base64格式

/^\s*data:([a-z]+\/[a-z0-9-+.]+(;[a-z-]+=[a-z0-9-]+)?)?(;base64)?,([a-z0-9!$&',()*+;=\-._~:@\/?%\s]*?)\s*$/i

数字/货币金额(支持负数、千分位分隔符)

/(^[-]?[1-9]\d{0,2}($|(,\d{3})*($|(\.\d{1,2}$))))|((^[0](\.\d{1,2})?)|(^[-][0]\.\d{1,2}))$/

数字/货币金额 (只支持正数、不支持校验千分位分隔符)

/(^[1-9]([0-9]+)?(\.[0-9]{1,2})?$)|(^(0){1}$)|(^[0-9]\.[0-9]([0-9])?$)/

银行卡号(16或19位)

/^([1-9]{1})(\d{15}|\d{18})$/

中文姓名

/^([\u4e00-\u9fa5·]{2,10})$/

新能源车牌号

/[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领 A-Z]{1}[A-HJ-NP-Z]{1}(([0-9]{5}[DF])|([DF][A-HJ-NP-Z0-9][0-9]{4}))$/

非新能源车牌号

/^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领 A-Z]{1}[A-HJ-NP-Z]{1}[A-Z0-9]{4}[A-Z0-9挂学警港澳]{1}$/

车牌号(新能源+非新能源)

/^([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领 A-Z]{1}[A-HJ-NP-Z]{1}(([0-9]{5}[DF])|([DF]([A-HJ-NP-Z0-9])[0-9]{4})))|([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领 A-Z]{1}[A-Z]{1}[A-HJ-NP-Z0-9]{4}[A-HJ-NP-Z0-9 挂学警港澳]{1})$/

URL链接(网址)

/^((https?|ftp|file):\/\/)?([\da-z.-]+)\.([a-z.]{2,6})(\/\w\.-]*)*\/?/

手机号(严谨), 根据工信部2019年最新公布的手机号段

/^1((3[\d])|(4[5,6,7,9])|(5[0-3,5-9])|(6[5-7])|(7[0-8])|(8[\d])|(9[1,8,9]))\d{8}$/

手机号(宽松), 只要是13,14,15,16,17,18,19开头即可

/^1[3-9]\d{9}$/

手机号(最宽松), 只要是1开头即可, 如果你的手机号是用来接收短信, 优先建议选择这一条

/^1\d{10}$/

日期, 如: 2000-01-01或2000-1-1

/^\d{4}(-)([0-1][0-2]|\d)\1([0-2]\d|\d|30|31)$/

email地址

/^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/

国内座机电话,如: 0341-86091234

/\d{3}-\d{8}|\d{4}-\d{7}/

一代身份证号(15位数字)

/^\d{8}(0\d|11|12)([0-2]\d|30|31)\d{3}$/

二代身份证号(18位数字),最后一位是校验位,可能为数字或字符X

/^\d{6}(18|19|20)\d{2}(0\d|11|12)([0-2]\d|30|31)\d{3}(\d|X|x)$/

身份证号, 支持1/2代(15位/18位数字)

/(^\d{8}(0\d|11|12)([0-2]\d|30|31)\d{3}$)|(^\d{6}(18|19|20)\d{2}(0\d|11|12)([0-2]\d|30|31)\d{3}(\d|X|x)$)/

帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线组合

/^[a-zA-Z][a-zA-Z0-9_]{4,15}$/

纯中文/汉字

/^[\u4E00-\u9FA5]+$/

是否小数

/^\d+\.\d+$/

电话(座机)

/^0\d{2,3}-\d{7,8}$/

纯数字

/^\d{1,}$/

是否html标签

/<(.*)>.*<\/\1>|<(.*) \/>/

是否qq号格式正确

/^[1-9][0-9]{4,10}$/

是否由数字和字母组成

/^[A-Za-z0-9]+$/

纯英文字母

/^[a-zA-Z]+$/

纯小写英文字母组成

/^[a-z]+$/

纯大写英文字母

/^[A-Z]+$/

密码强度正则,最少6位,包括至少1个大写字母,1个小写字母,1个数字,1个特殊字符

/^.*(?=.{6,})(?=.*\d)(?=.*[A-Z])(?=.*[a-z])(?=.*[!@#$%^&*? ]).*$/

用户名正则,4到16位(字母,数字,下划线,减号)

/^[a-zA-Z0-9_-]{4,16}$/

ipv4地址正则

/^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/

16进制颜色

/^#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/

微信号,6至20位,以字母开头,字母,数字,减号,下划线

/^[a-zA-Z][-_a-zA-Z0-9]{5,19}$/

中国邮政编码

/^(0[1-7]|1[0-356]|2[0-7]|3[0-6]|4[0-7]|5[1-7]|6[1-7]|7[0-5]|8[013-6])\d{4}$/

只包含中文和数字

/^(([\u4E00-\u9FA5])|(\d))+$/

非字母

/[^A-Za-z]$/
By柏小白

vue中8种组件通信方式

vue中8种组件通信方式, 值得收藏!

之前写了一篇关于vue面试总结的文章, 有不少网友提出组件之间通信方式还有很多, 这篇文章便是专门总结组件之间通信的

vue是数据驱动视图更新的框架, 所以对于vue来说组件间的数据通信非常重要,那么组件之间如何进行数据通信的呢? 首先我们需要知道在vue中组件之间存在什么样的关系, 才更容易理解他们的通信方式, 就好像过年回家,坐着一屋子的陌生人,相互之间怎么称呼,这时就需要先知道自己和他们之间是什么样的关系。 vue组件中关系说明:

1563158686(1)

如上图所示, A与B、A与C、B与D、C与E组件之间是父子关系; B与C之间是兄弟关系;A与D、A与E之间是隔代关系; D与E是堂兄关系(非直系亲属) 针对以上关系我们归类为:

  • 父子组件之间通信
  • 非父子组件之间通信(兄弟组件、隔代关系组件等)

本文会介绍组件间通信的8种方式如下图目录所示:并介绍在不同的场景下如何选择有效方式实现的组件间通信方式,希望可以帮助小伙伴们更好理解组件间的通信。

1563158701(1)

一、props / $emit

父组件通过props的方式向子组件传递数据,而通过$emit 子组件可以向父组件通信。

1. 父组件向子组件传值

下面通过一个例子说明父组件如何向子组件传递数据:在子组件article.vue中如何获取父组件section.vue中的数据articles:['红楼梦', '西游记','三国演义']

// section父组件
<template>
  <div class="section">
    <com-article :articles="articleList"></com-article>
  </div>
</template>

<script>
import comArticle from './test/article.vue'
export default {
  name: 'HelloWorld',
  components: { comArticle },
  data() {
    return {
      articleList: ['红楼梦', '西游记', '三国演义']
    }
  }
}
</script>

复制代码
// 子组件 article.vue
<template>
  <div>
    <span v-for="(item, index) in articles" :key="index">{{item}}</span>
  </div>
</template>

<script>
export default {
  props: ['articles']
}
</script>
复制代码

总结: prop 只可以从上一级组件传递到下一级组件(父子组件),即所谓的单向数据流。而且 prop 只读,不可被修改,所有修改都会失效并警告。

2. 子组件向父组件传值

对于$emit 我自己的理解是这样的: $emit绑定一个自定义事件, 当这个语句被执行时, 就会将参数arg传递给父组件,父组件通过v-on监听并接收参数。 通过一个例子,说明子组件如何向父组件传递数据。 在上个例子的基础上, 点击页面渲染出来的ariticleitem, 父组件中显示在数组中的下标

// 父组件中
<template>
  <div class="section">
    <com-article :articles="articleList" @onEmitIndex="onEmitIndex"></com-article>
    <p>{{currentIndex}}</p>
  </div>
</template>

<script>
import comArticle from './test/article.vue'
export default {
  name: 'HelloWorld',
  components: { comArticle },
  data() {
    return {
      currentIndex: -1,
      articleList: ['红楼梦', '西游记', '三国演义']
    }
  },
  methods: {
    onEmitIndex(idx) {
      this.currentIndex = idx
    }
  }
}
</script>
复制代码
<template>
  <div>
    <div v-for="(item, index) in articles" :key="index" @click="emitIndex(index)">{{item}}</div>
  </div>
</template>

<script>
export default {
  props: ['articles'],
  methods: {
    emitIndex(index) {
      this.$emit('onEmitIndex', index)
    }
  }
}
</script>
复制代码

二、 $children / $parent

1563158473(1)

上面这张图片是vue官方的解释,通过$parent$children就可以访问组件的实例,拿到实例代表什么?代表可以访问此组件的所有方法和data。接下来就是怎么实现拿到指定组件的实例。

使用方法

// 父组件中
<template>
  <div class="hello_world">
    <div>{{msg}}</div>
    <com-a></com-a>
    <button @click="changeA">点击改变子组件值</button>
  </div>
</template>

<script>
import ComA from './test/comA.vue'
export default {
  name: 'HelloWorld',
  components: { ComA },
  data() {
    return {
      msg: 'Welcome'
    }
  },

  methods: {
    changeA() {
      // 获取到子组件A
      this.$children[0].messageA = 'this is new value'
    }
  }
}
</script>
复制代码
// 子组件中
<template>
  <div class="com_a">
    <span>{{messageA}}</span>
    <p>获取父组件的值为:  {{parentVal}}</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      messageA: 'this is old'
    }
  },
  computed:{
    parentVal(){
      return this.$parent.msg;
    }
  }
}
</script>
复制代码

要注意边界情况,如在#app上拿$parent得到的是new Vue()的实例,在这实例上再拿$parent得到的是undefined,而在最底层的子组件拿$children是个空数组。也要注意得到$parent$children的值不一样,$children 的值是数组,而$parent是个对象

总结

上面两种方式用于父子组件之间的通信, 而使用props进行父子组件通信更加普遍; 二者皆不能用于非父子组件之间的通信。

三、provideinject

概念:

provideinject 是vue2.2.0新增的api, 简单来说就是父组件中通过provide来提供变量, 然后再子组件中通过inject来注入变量。

注意: 这里不论子组件嵌套有多深, 只要调用了inject 那么就可以注入provide中的数据,而不局限于只能从当前父组件的props属性中回去数据

举例验证

接下来就用一个例子来验证上面的描述: 假设有三个组件: A.vue、B.vue、C.vue 其中 C是B的子组件,B是A的子组件

// A.vue

<template>
  <div>
	<comB></comB>
  </div>
</template>

<script>
  import comB from '../components/test/comB.vue'
  export default {
    name: "A",
    provide: {
      for: "demo"
    },
    components:{
      comB
    }
  }
</script>
复制代码
// B.vue

<template>
  <div>
    {{demo}}
    <comC></comC>
  </div>
</template>

<script>
  import comC from '../components/test/comC.vue'
  export default {
    name: "B",
    inject: ['for'],
    data() {
      return {
        demo: this.for
      }
    },
    components: {
      comC
    }
  }
</script>
复制代码
// C.vue
<template>
  <div>
    {{demo}}
  </div>
</template>

<script>
  export default {
    name: "C",
    inject: ['for'],
    data() {
      return {
        demo: this.for
      }
    }
  }
</script>
复制代码

四、ref / refs

ref:如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例,可以通过实例直接调用组件的方法或访问数据, 我们看一个ref 来访问组件的例子:

// 子组件 A.vue

export default {
  data () {
    return {
      name: 'Vue.js'
    }
  },
  methods: {
    sayHello () {
      console.log('hello')
    }
  }
}
复制代码
// 父组件 app.vue

<template>
  <component-a ref="comA"></component-a>
</template>
<script>
  export default {
    mounted () {
      const comA = this.$refs.comA;
      console.log(comA.name);  // Vue.js
      comA.sayHello();  // hello
    }
  }
</script>
复制代码

五、eventBus

eventBus 又称为事件总线,在vue中可以使用它来作为沟通桥梁的概念, 就像是所有组件共用相同的事件中心,可以向该中心注册发送事件或接收事件, 所以组件都可以通知其他组件。

eventBus也有不方便之处, 当项目较大,就容易造成难以维护的灾难

在Vue的项目中怎么使用eventBus来实现组件之间的数据通信呢?具体通过下面几个步骤

1. 初始化

首先需要创建一个事件总线并将其导出, 以便其他模块可以使用或者监听它.

// event-bus.js

import Vue from 'vue'
export const EventBus = new Vue()
复制代码

2. 发送事件

假设你有两个组件: additionNum 和 showNum, 这两个组件可以是兄弟组件也可以是父子组件;这里我们以兄弟组件为例:

<template>
  <div>
    <show-num-com></show-num-com>
    <addition-num-com></addition-num-com>
  </div>
</template>

<script>
import showNumCom from './showNum.vue'
import additionNumCom from './additionNum.vue'
export default {
  components: { showNumCom, additionNumCom }
}
</script>

复制代码
// addtionNum.vue 中发送事件

<template>
  <div>
    <button @click="additionHandle">+加法器</button>    
  </div>
</template>

<script>
import {EventBus} from './event-bus.js'
console.log(EventBus)
export default {
  data(){
    return{
      num:1
    }
  },

  methods:{
    additionHandle(){
      EventBus.$emit('addition', {
        num:this.num++
      })
    }
  }
}
</script>
复制代码

3. 接收事件

// showNum.vue 中接收事件

<template>
  <div>计算和: {{count}}</div>
</template>

<script>
import { EventBus } from './event-bus.js'
export default {
  data() {
    return {
      count: 0
    }
  },

  mounted() {
    EventBus.$on('addition', param => {
      this.count = this.count + param.num;
    })
  }
}
</script>
复制代码

这样就实现了在组件addtionNum.vue中点击相加按钮, 在showNum.vue中利用传递来的 num 展示求和的结果.

4. 移除事件监听者

如果想移除事件的监听, 可以像下面这样操作:

import { eventBus } from 'event-bus.js'
EventBus.$off('addition', {})
复制代码

六、Vuex

1. Vuex介绍

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化. Vuex 解决了多个视图依赖于同一状态来自不同视图的行为需要变更同一状态的问题,将开发者的精力聚焦于数据的更新而不是数据在组件之间的传递上

2. Vuex各个模块

  1. state:用于数据的存储,是store中的唯一数据源
  2. getters:如vue中的计算属性一样,基于state数据的二次包装,常用于数据的筛选和多个数据的相关性计算
  3. mutations:类似函数,改变state数据的唯一途径,且不能用于处理异步事件
  4. actions:类似于mutation,用于提交mutation来改变状态,而不直接变更状态,可以包含任意异步操作
  5. modules:类似于命名空间,用于项目中将各个模块的状态分开定义和操作,便于维护

3. Vuex实例应用

// 父组件

<template>
  <div id="app">
    <ChildA/>
    <ChildB/>
  </div>
</template>

<script>
  import ChildA from './components/ChildA' // 导入A组件
  import ChildB from './components/ChildB' // 导入B组件

  export default {
    name: 'App',
    components: {ChildA, ChildB} // 注册A、B组件
  }
</script>
复制代码
// 子组件childA

<template>
  <div id="childA">
    <h1>我是A组件</h1>
    <button @click="transform">点我让B组件接收到数据</button>
    <p>因为你点了B,所以我的信息发生了变化:{{BMessage}}</p>
  </div>
</template>

<script>
  export default {
    data() {
      return {
        AMessage: 'Hello,B组件,我是A组件'
      }
    },
    computed: {
      BMessage() {
        // 这里存储从store里获取的B组件的数据
        return this.$store.state.BMsg
      }
    },
    methods: {
      transform() {
        // 触发receiveAMsg,将A组件的数据存放到store里去
        this.$store.commit('receiveAMsg', {
          AMsg: this.AMessage
        })
      }
    }
  }
</script>
复制代码
// 子组件 childB

<template>
  <div id="childB">
    <h1>我是B组件</h1>
    <button @click="transform">点我让A组件接收到数据</button>
    <p>因为你点了A,所以我的信息发生了变化:{{AMessage}}</p>
  </div>
</template>

<script>
  export default {
    data() {
      return {
        BMessage: 'Hello,A组件,我是B组件'
      }
    },
    computed: {
      AMessage() {
        // 这里存储从store里获取的A组件的数据
        return this.$store.state.AMsg
      }
    },
    methods: {
      transform() {
        // 触发receiveBMsg,将B组件的数据存放到store里去
        this.$store.commit('receiveBMsg', {
          BMsg: this.BMessage
        })
      }
    }
  }
</script>
复制代码

vuex的store,js

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const state = {
  // 初始化A和B组件的数据,等待获取
  AMsg: '',
  BMsg: ''
}

const mutations = {
  receiveAMsg(state, payload) {
    // 将A组件的数据存放于state
    state.AMsg = payload.AMsg
  },
  receiveBMsg(state, payload) {
    // 将B组件的数据存放于state
    state.BMsg = payload.BMsg
  }
}

export default new Vuex.Store({
  state,
  mutations
})
复制代码

七、localStorage / sessionStorage

这种通信比较简单,缺点是数据和状态比较混乱,不太容易维护。 通过window.localStorage.getItem(key)获取数据 通过window.localStorage.setItem(key,value)存储数据

注意用JSON.parse() / JSON.stringify() 做数据格式转换 localStorage / sessionStorage可以结合vuex, 实现数据的持久保存,同时使用vuex解决数据和状态混乱问题.

八 $attrs与 $listeners

现在我们来讨论一种情况, 我们一开始给出的组件关系图中A组件与D组件是隔代关系, 那它们之前进行通信有哪些方式呢?

  1. 使用props绑定来进行一级一级的信息传递, 如果D组件中状态改变需要传递数据给A, 使用事件系统一级级往上传递
  2. 使用eventBus,这种情况下还是比较适合使用, 但是碰到多人合作开发时, 代码维护性较低, 可读性也低
  3. 使用Vuex来进行数据管理, 但是如果仅仅是传递数据, 而不做中间处理,使用Vuex处理感觉有点大材小用了.

vue2.4中,为了解决该需求,引入了$attrs 和$listeners , 新增了inheritAttrs 选项。 在版本2.4以前,默认情况下父作用域的不被认作props的属性百年孤独,将会“回退”且作为普通的HTML特性应用在子组件的根元素上。接下来看一个跨级通信的例子:

// app.vue
// index.vue

<template>
  <div>
    <child-com1
      :name="name"
      :age="18"
      :gender="女"
      :height="158"
      title="程序员成长指北"
    ></child-com1>
  </div>
</template>
<script>
const childCom1 = () => import("./childCom1.vue");
export default {
  components: { childCom1 },
  data() {
    return {
      name: "zhang",
      age: "18",
      gender: "女",
      height: "158"
    };
  }
};
</script>
复制代码
// childCom1.vue

<template class="border">
  <div>
    <p>name: {{ name}}</p>
    <p>childCom1的$attrs: {{ $attrs }}</p>
    <child-com2 v-bind="$attrs"></child-com2>
  </div>
</template>
<script>
const childCom2 = () => import("./childCom2.vue");
export default {
  components: {
    childCom2
  },
  inheritAttrs: false, // 可以关闭自动挂载到组件根元素上的没有在props声明的属性
  props: {
    name: String // name作为props属性绑定
  },
  created() {
    console.log(this.$attrs);
     // { "age": "18", "gender": "女", "height": "158", "title": "程序员成长指北" }
  }
};
</script>
复制代码
// childCom2.vue

<template>
  <div class="border">
    <p>age: {{ age}}</p>
    <p>childCom2: {{ $attrs }}</p>
  </div>
</template>
<script>

export default {
  inheritAttrs: false,
  props: {
    age: String
  },
  created() {
    console.log(this.$attrs); 
    // { "name": "zhang", "gender": "女", "height": "158", "title": "程序员成长指北" }
  }
};
</script>
复制代码

总结

常见使用场景可以分为三类:

  • 父子组件通信: props$parent / $childrenprovide / inject ; ref ; $attrs / $listeners
  • 兄弟组件通信: eventBus ; vuex
  • 跨级通信: eventBus;Vuex;provide / inject 、$attrs / $listeners

今天就分享这么多,如果对分享的内容感兴趣,可以关注公众号「程序员成长指北」,或者加入技术交流群,大家一起讨论。

加入我们一起学习吧!

转:https://juejin.im/post/5d267dcdf265da1b957081a3?utm_source=gold_browser_extension

By柏小白

webstorm插件

File -> settings -> Plugins 即可调出设置中的插件选项。

或者直接快捷键 ctrl + alt + s也可调出设置菜单。

具体的插件安装方法不再赘述,不会的同学建议先看一下明河的:《webstorm入门指南》

接下来主要收录了一些常用的插件,方便查阅:

ideaVim

此插件可以让 webstorm 编辑器支持 vim。

.ignore

可以支持 .gitignore 的语法规则,并提供了一些自动将文件加入 .gitignore 中的功能。

eslint

语法检查的插件

AceJump

用于光标的快速定位与跳转,默认的快捷键是ctrl + ;,按快捷键之后,再按下自己想要将光标跳转到的目标的字母,这时会出现很多A,B,C,D,E…… 的序号,按下相应的字母即可跳转到相应的地方。(区分大小写)

1560500769-6514-ace-jump

点多次的话,好像对应不同的用法,待我再研究研究。。。。

Key Promoter

鼠标完成某项操作时,会提示相应的快捷键。

1560500772-5360-key-promoter

Markdown

支持 markdown 语法

AngularJS

支持 angularjs 的语法提示

activate-power-mode

atom 上的神器啊,抱着试一试的心态一搜,webstorm 上居然也有了,安装之后可以在 window -> activate-power-mode 中关闭震动以及开启彩色模式。

Material Theme UI

主题类的插件,可以改改界面颜色呀,文件图标啥的,至少比默认的稍微强那么点。。。。

1560500773-4107-material

CodeGlance

这也是强烈推荐的,用过 sublime 的同学会知道右侧有一个当前文件中代码的缩略图,这个插件可以让 webstorm 也具有此功能。

1560500771-1182-code-glance

 

Translation

  • 多翻译引擎
    • Google翻译
    • 有道翻译
    • 百度翻译
  • 多语言互译
  • 语音朗读
  • 自动选词
  • 自动单词拆分
  • 53e79ae43a865a4b83b62372089a3585
By柏小白

nginx配置ssl证书实现https访问

一.已签发的证书,下载 签发SSL证书自行google

二.

下载的文件有两个:

1,214292799730473.pem  或者 214292799730473.crt

2,214292799730473.key

三.

配置ca证书

1,nginx的安装目录为:/etc/nginx/。进入目录,增加cert/文件夹,把刚刚下载的两个文件上传到cert/文件夹中。

2,在/etc/nginx/vhost/下,增加web.xn--w0sz4as21fs7k.com.com文件。内容如下:

说明:下面的配置是对443端口和80端口进行监听,443端口要启用ssl。监听443端口的server配置可以仿照上面ca认证页面的nginx配置示例进行配置。

root节点笔者创建了一个web.xn--w0sz4as21fs7k.com/的文件夹,专门存放来自这个域名的请求以示区分。

server {
listen 443;
server_name web.xn--w0sz4as21fs7k.com; // 你的域名
ssl on;
root /var/www/web.xn--w0sz4as21fs7k.com; // 前台文件存放文件夹,可改成别的
index index.html index.htm;// 上面配置的文件夹里面的index.html
ssl_certificate cert/98989898989.pem;// 改成你的证书的名字
ssl_certificate_key cert/98989898989.key;// 你的证书的名字
ssl_session_timeout 5m;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
location / {
index index.html index.htm;
}
}
server {
listen 80;

# 你的域名
server_name web.xn--w0sz4as21fs7k.com;

# 把http的域名请求转成https
rewrite ^(.*)$ https://$host$1 permanent;
}

By柏小白

webstorm关闭eslint检测

vue项目已经设置关闭eslint,但是代码还是很多标红线的地方,原因是webstorm这个ide默认启用了eslint,可以在设置中关闭

1558082214(1)

By柏小白

Invalid Host header 服务器域名访问出现的问题

项目是通过局域网访问来演示的,这个项目是采用Vue.js前后端分离的方式来做的,然而发现只能在本地访问,不能通过域名nginx反向代理访问。

通过服务器域名访问时是显示Invalid Host header,这是由于新版的webpack-dev-server出于安全考虑,默认检查hostname,如果hostname不是配置内的,将中断访问。可以在build目录中的webpack.base.config.js中添加如下webpack-dev-server配置:devServer: { disableHostCheck: true, }

By柏小白

frps在win10下通过winsw启动自动运行

使用方法:
1、下载最新版的 Windows Service Wrapper 程序[winsw],比如我下载的名称是 “winsw-1.9-bin.exe”, 百度相关下载地址:https://www.cr173.com/soft/101797.html

然后,把它命名成你想要的名字(比如: “winsw.exe”,当然,你也可以不改名)

2、将重命名后的 winsw.exe 复制到 frp_0.13.0_windows_386 的安装目录(我这里是 “C:\Frps\frp_0.13.0_windows_386″)

3、在同一个目录下创建一个Windows Service Wrapper的XML配置文件,名称必须与第一步重命名时使用的名称一致(比如我这里是 “winsw.xml”, 如果,你没有重命名,则应该是 “winsw-1.9-bin.xml”)

文件内容如下:

<service>
<id>frp</id>
<name>frp</name>
<description>用frps外网穿透</description>
<executable>frpc</executable>
<arguments>-c frpc.ini</arguments>
<logmode>reset</logmode>
</service>

4、命令行下执行以下命令,以便将其安装成Windows服务。

C:\Frps\frp_0.13.0_windows_386> winsw.exe install

OK,至此,完工,确认一下:我的电脑 右键 -> 管理 -> 服务 -> 是否有了个 frp 服务呢?

8

补充:

Windows Servcie Wrapper的命令格式如下:

# 安装服务

CMD:\> winsw.exe install

# 卸载服务

CMD:\> winsw.exe uninstall

By柏小白

webstorm通过sftp修改本地文件 直接上传到服务器上

在开发中需要修改本地环境文件 保持ctrl+s保存 直接上传到服务器上 下面是具体步骤

Tools–Deployment–Configuration 这时候Upload to等都是灰色的

1

打开之后设置

添加个服务 左侧绿色加号 添加 这时候会选择类型 SFTP 用的centos,windows就是ftp。填写服务名称 我写的home,然后确定下面的 ,填写具体的地址

  • SFTP host : 服务器IP地址域名
  • Port : 端口号
  • Root Path : 找到服务器上的需要的文件夹
  • User name:用户名 一般都是root
  • Password :密码 这里后面打勾 保持密码 Save password
  • 填写正确后测试下Test SFTP connection 成功后就可以使用
  • Web server root URL : 访问的地址 这里根据服务器的IP来访问 Open 下看是否正确打开

2

测试连接是否成功:Test Connection

3

配置ctl+s保存上传文件

Tools–Deployment–Options

5

如下选项需要更改

  • Upload changed files automatically to the default server 这里选择 On explicit save action (Ctrl + S)
  • Upload external changes 这里勾选
  • Override default permissions on files 权限777 或者775
  • Override default permissions on folders 权限775

4

如下图的配置 确定后就可以看到,打开相应的服务器文件

6

直接修改文件ctrl+s保存到服务器上

7

By柏小白

webstorm 通过ssh连接服务器

必要条件
服务器一台 ( 虚拟机也可以 ); 一般 linux 安装完成,配置好网络等相关参数之后,可以通过 ssh 工具来连接,连接之后就可以在本地电脑对远程服务器进行操作了. 今天无意间发现, webstorm 也自带了 ssh 连接工具;具体使用如下 :

1 在 Tools下拉菜单中,有个start ssh session.,如下图所示:

2

2 点击 Start SSH session , 跳出如下对话框 :

3

3 点击 Edit credentials … ,跳出如下对话框 :

1

4 配置相关参数, Host 是目标服务器的IP ,这里本人使用的是Centos 7 系统的虚拟机 ; Linux的 Port 默认是 22 ,用户名和密码就是你要连接的服务器的用户名和密码,配置好好之后点击 OK 按钮,即可连接 , 连接成功后,会自动打开Terminal 工具,显示如下

4

5 远程ssh连接的terminal乱码

5

By柏小白

有哪些鲜为人知,但是很有意思的网站?

扩展阅读

工具类

图片/视频工具

IT/AI/工具类

音乐/影视类

二次元/动漫类

文艺类

网盘/搜索类

文学/百科类

实用/行政类

趣味/无聊类

声音/太空类

怀旧类

游戏/测试类

网站之最

特别推荐

原文地址:

 

By柏小白

Linux中设置服务自启动的三种方式

有时候我们需要Linux系统在开机的时候自动加载某些脚本或系统服务

主要用三种方式进行这一操作:

ln -s                       在/etc/rc.d/rc*.d目录中建立/etc/init.d/服务的软链接(*代表0~6七个运行级别之一)

chkonfig                命令行运行级别设置

ntsysv                   伪图形运行级别设置

 

注意:1.这三种方式主要用于以redhat为基础的发行版

2.如果还不知道运行级别是什么,那么最好先看看相关资料再实验

 

第一种方式:ln -s 建立启动软连接

在Linux中有7种运行级别(可在/etc/inittab文件设置),每种运行级别分别对应着/etc/rc.d/rc[0~6].d这7个目录

Tips:/etc/rc[0~6].d其实是/etc/rc.d/rc[0~6].d的软连接,主要是为了保持和Unix的兼容性才做此策

 

这7个目录中,每个目录分别存放着对应运行级别加载时需要关闭或启动的服务

由详细信息可以知道,其实每个脚本文件都对应着/etc/init.d/目录下具体的服务

K开头的脚本文件代表运行级别加载时需要关闭的,S开头的代表需要执行

因此,当我们需要开机启动自己的脚本时,只需要将可执行脚本丢在/etc/init.d目录下,然后在/etc/rc.d/rc*.d中建立软链接即可

[root@localhost ~]# ln -s /etc/init.d/sshd /etc/rc.d/rc3.d/S100ssh

此处sshd是具体服务的脚本文件,S100ssh是其软链接,S开头代表加载时自启动

如果需要在多个运行级别下设置自启动,则需建立多个软链接

这种方式比较繁琐,适用于自定义的服务脚本

如果系统中已经存在某些服务(比如安装apache时就会有httpd服务项),可以使用下面的两种方式

 

第二种方式:chkconfig

如果需要自启动某些服务,只需使用chkconfig 服务名 on即可,若想关闭,将on改为off

在默认情况下,chkconfig会自启动2345这四个级别,如果想自定义可以加上–level选项

上面我们先将sshd服务的所有启动级别关闭,然后使用–level选项启动自定义级别

Tips:–list选项可查看指定服务的启动状态,chkconfig不带任何选项则查看所有服务状态

 

第三种方式:ntsysv 伪图形

ntsysvchkconfig其实是一样的,只不过加上了图形而已

启动ntsysv有两种方式,一是直接在命令行中输入ntsysv,二是使用setup命令,然后选择系统服务

默认情况下,当前运行级别为多少,在ntsysv中设置的启动服务的级别便是多少

比如,我当前的运行级别是3,那么我在伪图形界面中选择启动服务后,它的运行级别也会是3

如果想自定义运行级别可使用ntsysv –level方式

 

以上三种操作需要保证服务脚本文件可执行,并且要有root权限

其中,第一种方式多用于自定义脚本,第二、三种多用于系统已存在的服务

比如ftp、samba、ssh、httpd等等

并且,要做相关设置需要弄清楚运行级别的问题

 

Tips:如果想手动启动某服务,传统的方式是 /etc/init.d 服务名 start

实际上还可以这样,service 服务名 start

转自:https://www.cnblogs.com/nerxious/archive/2013/01/18/2866548.html

By柏小白

jenkins配置记录(1)–添加用户权限

 

这样我直接用QQ截图直接粘贴就可以把简书的外链图片全部替换成本地图片链接了。

前一阵子在线上部署了一套jenkins环境,作为线上代码发布平台使用。
部署记录:http://web.xn--w0sz4as21fs7k.com/?p=1895

下面重点记录下jenkins安装后的一些配置:

(1)添加用户权限

jenkins初次登陆后,要先注册一个用户作为管理员:

依次点击“系统管理”->“Configure Global Security”

1548228117-5908-6-20161101155031049-98639631

 

如下:
选择“启用安全”模式,
“安全域”->“Jenkins专用用户数据库”->不选择“允许用户注册”(如果此处选择了”允许用户注册“,那么任何人都可以注册,只是注册后没有任何的操作权限,登陆后会提示“Access Denied,没有Overall/Read权限”,还是需要在管理员账号下授权后才能操作)。先注册一个管理员账号,然后在管理员下创建普通账号,再授予这些账号相应的操作权限。
“授权策略”->“项目矩阵授权策略”,添加账号。

1548228114-9862-20161101155821643-1395315569

 

 

首先添加一个admin账号作为管理员,先”应用“,注意这个时候千万别点击“保存”。由于admin用户还没有注册,所以这里添加到权限策略内会显示红色,等后面将这个admin用户注册后就会变成正常的绿色。

1548228116-5046-20161101160747565-2035208245

如上,点击“应用”后,再点击回到“jenkins”首页,会提示进行注册,则使用上面添加的管理员账号admin进行注册

1548228113-2373-20161101161617236-510924690

 

注册成功后,就可以用管理员admin账号登陆了

1548228118-2462-20161101161240080-369601404

 

在管理员账号下就可以创建普通用户

依次点击“系统管理”->“管理用户”

1548228119-9716-20161101161442315-1791228697

 

1548228121-9704-20161101161518721-415777939

1548228122-1515-20161101161729580-1298369009

 

然后在“系统管理”->“Configure Global Security”的->“授权策略”->“项目矩阵授权策略”里授予wangshibo用户相应的权限。
由于wangshibo用户已经注册好了,所以这里添加进去后是绿色的

1548228124-1199-20161101162206315-1425033646

其他用户的添加步骤跟上面一样操作即可。

一般而言,除了运维人员(管理员)具有所有项目操作的权限外,一般只给开发人员(通常是项目组的负责人)Beta环境下的项目操作权限。如下,只给caogaokui和yuxiaogang这两个用户设置构建项目的权限。

 

“系统管理”->“管理用户”->“创建用户”

1548228125-4966-20161103011609580-190636434

“系统管理”->“Configure Global Security”->“授权策略”->“项目矩阵授权策略”

1548228126-7193-20161103012153799-1436603609

 

 

然后再相应的项目构建配置里,“启用项目安全”,将相应的用户添加进去,赋予操作权限,说明他们对该项目由构建的权限。如下:

1548228127-6465-20161103011954471-850219423

1548226500-9090-20161103011954471-850219423

 

By柏小白

Jenkins安装及入门配置

一、安装Jenkins

Jenkins是开源的,使用Java编写的持续集成的工具,在Centos上可以通过yum命令行直接安装。记录下安装的过程,方便以后查找。需要先安装Java,如果已经Java可以跳过该步骤。

安装Java

看到当前系统Java版本的命令:

java -version

如果显示Java版本号,说明已经正确安装,如果显示没有该命令,需要安装Java:
sudo yum install java

该命令如果检测到Java不存在可以直接安装Java,如果已存在则可以升级Java。

最新版本Jenkins安装**

首先要先添加Jenkins源:

sudo wget -O /etc/yum.repos.d/jenkins.repo http://jenkins-ci.org/redhat/jenkins.repo

sudo rpm --import http://pkg.jenkins-ci.org/redhat/jenkins-ci.org.key

添加完成之后直接使用yum命令安装Jenkins:

yum install jenkins

历史版本安装

通过yum直接安装的是最新版本的Jenkins,必须使用JDK1.8,,由于我们使用的是jdk1.7,所以需要安装历史版本的jenkins。以下是安装步骤。

一、下载历史版本

https://jenkins.io/网站,点击下载进入下载页面

1548227927-8497-2223516-d8a8a896f5499066
image

选择对应操作系统

1548227928-8663-2223516-e4e498d842434397
image

选择版本,由于2.54以上的版本需要JDK1.8,所以我们选择选择低版本,这里选择使用2.46.3的版本

1548227931-5418-2223516-5c68677cb31029ef
image

将下载下来的rpm文件上传到服务器

1548227934-9764-2223516-e055089c2e917312
image

首先先添加Jenkins源:

sudo wget -O /etc/yum.repos.d/jenkins.repo http://jenkins-ci.org/redhat/jenkins.repo

sudo rpm --import http://pkg.jenkins-ci.org/redhat/jenkins-ci.org.key

使用rpm命令安装jenkins

1548227932-4578-2223516-16b272eead3aae31
image

启动Jenkins

使用命令启动Jenkins:

sudo service jenkins start

Starting Jenkins [ OK ]

在浏览器中输入:http://<服务器ip>:8080/ 就可以进入Jenkins界面直接使用了 。

停止Jenkins服务的命令为:

sudo service jenkins stop

相关配置

Jenkins安装目录:

/var/lib/jenkins/

Jenkins配置文件地址:

/etc/sysconfig/jenkins

这就是Jenkins的配置文件,可以在这里查看Jenkins默认的配置。

cat jenkins

这里介绍下三个比较重要的配置:

  • JENKINS_HOME
  • JENKINS_USER
  • JENKINS_PORT

JENKINS_HOME是Jenkins的主目录,Jenkins工作的目录都放在这里,Jenkins储存文件的地址,Jenkins的插件,生成的文件都在这个目录下。

<pre class="md-fences md-end-block" lang="shell" contenteditable="false" cid="n105" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: Consolas, &quot;Liberation Mono&quot;, Courier, monospace; font-size: 0.9em; white-space: pre; display: block; break-inside: avoid; text-align: left; background: var(--code-block-bg-color); background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(221, 221, 221); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;">## Path:    Development/Jenkins
## Description: Jenkins Continuous Integration Server
## Type:    string
## Default:   "/var/lib/jenkins"
## ServiceRestart: jenkins
#
# Directory where Jenkins store its configuration and working
# files (checkouts, build reports, artifacts, ...).
#
JENKINS_HOME="/var/lib/jenkins"</pre>

JENKINS_USER是Jenkins的用户,拥有$JENKINS_HOME和/var/log/jenkins的权限。

<pre class="md-fences md-end-block" lang="shell" contenteditable="false" cid="n108" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: Consolas, &quot;Liberation Mono&quot;, Courier, monospace; font-size: 0.9em; white-space: pre; display: block; break-inside: avoid; text-align: left; background: var(--code-block-bg-color); background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(221, 221, 221); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;">## Type:    string
## Default:   "jenkins"
## ServiceRestart: jenkins
#
# Unix user account that runs the Jenkins daemon
# Be careful when you change this, as you need to update
# permissions of $JENKINS_HOME and /var/log/jenkins.
#
JENKINS_USER="jenkins"</pre>

JENKINS_PORT是Jenkins的端口,默认端口是8080,我们这里修改为8000。

<pre class="md-fences md-end-block" lang="shell" contenteditable="false" cid="n111" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: Consolas, &quot;Liberation Mono&quot;, Courier, monospace; font-size: 0.9em; white-space: pre; display: block; break-inside: avoid; text-align: left; background: var(--code-block-bg-color); background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(221, 221, 221); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;">## Type:    integer(0:65535)
## Default:   8080
## ServiceRestart: jenkins
#
# Port Jenkins is listening on.
# Set to -1 to disable
#
JENKINS_PORT="8000"</pre>

主要问题

一、没有那个文件或目录

1548227935-5894-2223516-a5955ae08a2a75fb
image

这是由于找不到jdk目录报的错,只要修改/etc/init.d/jenkins配置文件,配置下jdk目录就好了。

1548227937-8885-2223516-b03bf8102d7619b6
image

保存,重新启动,启动成功

1548227938-4914-2223516-6dc3cab073eb5792
image

二、Jenkins的访问

验证jenkins是否运行正常,通过访问http://localhost:8000

这里有一个临时密码需要输入,在/home/tomcat/.jenkins/secrets/initialAdminPassword里面

1548227939-5880-2223516-6411c1e94adceae7
image

输入密码进入:

1548227941-1161-2223516-33c7ded732879540
image

这里选择把建议的插件全装上去

1548227942-3286-2223516-a03b47b94c74d5a6
image

–设置用户名和密码

1548227943-8985-2223516-84300bb4d31c1088
image

保存,进入主界面

1548227945-5214-2223516-10d4e95114675bb5
image

三、主要配置

系统配置

点击系统管理-系统设置配置邮件通知,通过Test测试,能收到邮件表明配置成功

1548227946-3405-2223516-c62e65781d022202
image

点击系统管理-管理插件,安装SSH插件

1548227948-8138-2223516-527b98d617bc4c88
image

这样,在配置邮件的下面就会有Publish over ssh选项

1548227949-3719-2223516-713f24e65b1910ca
image

配置远程ssh主机地址,通过Test返回success表示配置成功

1548227952-5047-2223516-51bfb993fe4c709a
image

点击保存

全局工具配置

系统管理-全局工具配置,配置JDK,Git,Maven等信息。

1548227954-7097-2223516-b0136eba51d2beec
image

四、新建项目

安装Git plugin插件,注意,由于我们使用的是旧版的jerkin,所以直接安装Git plugin插件是失败的,所以我们需要自己手动下载安装。

插件手动安装步骤

1、下载插件

首先,在可选插件上面过滤输入git,就可以搜索到Git plugin插件,点击此插件

1548227956-4589-2223516-cd7d49d118b052fa
image

进入后查看ID,知道ID为git。

1548227958-3467-2223516-cd21acfaa3bad49f
image

浏览插件网站http://updates.jenkins-ci.org/download/plugins/,找到对应插件git,点击进去。

1548227960-3429-2223516-aa13567c5a636dab
image

注意不要选择最新版本,我们这里选择历史版本,即3.5.0下载

1548227962-7282-2223516-4f882cce085be92a
image

下载到本地。

1548227964-8430-2223516-bee71e0a169d7edc
image

2、安装

还是系统管理-插件管理,选择高级,有上传插件选项,点击文件并上传。

1548227965-7604-2223516-57a523b11f50c926
image

上传之后,会开始安装,这里安装失败,点击查看原因,是缺少另外一个插件,这里需要先安装对应插件,按照上面的步骤。

1548227968-1497-2223516-7321b851ab95b5eb
image

插件安装过程中,如果需要重启jenkins的,可以直接在页面上出入restart重启

1548227970-7246-2223516-ea553e81048f2cc3
image

安装完成之后,在已安装插件中就可以找到对应插件

1548227971-3194-2223516-58050c7a3ac82d9b
image

项目创建

点击新建

1548227973-8848-2223516-58d43228387fb646
image

书写项目名称,选择风格

1548227974-6657-2223516-5a5b59732617a686
image

店家ok之后进入配置界面,在源码管理中选择git,输入项目url,设置分支。如果有账号密码,点击add添加

1548227976-5611-2223516-e8ca5e26b5f5340a
image

添加git的账号密码

1548227978-7010-2223516-f0ad49fd2fbf2ac1
image

构建,选择之前配置的maven,并配置要执行的操作,保存。

1548227980-5316-2223516-f9f0df87f5cec44f
image

点开立即构建,即开始构建项目

1548227982-6524-2223516-8187fa2df9edf5b8
image

构建成功后显示为蓝色,如果有问题显示为红色或黄色。点击任何一次可以进入。

1548227984-8122-2223516-a8bf894695bfa3bf
image

点击Console Output可以查看对应的控制台输出

By柏小白

frp-linux下配置运行

群晖NAS+frp发挥更大作用
Posted by SunnyRx on October 21, 2016
原文地址:http://www.sunnyrx.com/2016/10/21/simple-to-use-frp/

该文章于2018年7月7日将frp版本从0.13.0更新到0.20.0,下文针对frp 0.20.0配置。

NAS没有公网IP是一件很不方便的事情,尤其是在国内的网络环境,学校和小区内的用户通常都没有公网IP。为了解决这个问题,则需要内网穿透,而内网穿透的方法有很多种,例如使用花生壳ngrok等,该文章要介绍的是使用frp让群晖实现内网穿透。

实际上frp有官方的中文文档,上面的内容已经非常详尽,对相关操作比较熟悉的人可以直接阅读官方的中文文档。

什么是frp

frp 是一个高性能的反向代理应用,可以帮助您轻松地进行内网穿透,对外网提供服务,支持 tcp, http, https 等协议类型,并且 web 服务支持根据域名进行路由转发。

准备

在使用frp之前,需要一台有公网IP的服务器(下文称外网主机),一台需要实现内网穿透的机器(下文称内网主机),SSH工具,以及一个域名(如果只是建立SSH反向代理则不需要域名)。

该文章中笔者所使用的服务器是朋友推荐的Vultr服务器,虽然服务器是在国外,但胜在带宽够,有需要的朋友可以注册一个。而需要实现内网穿透的机器则是笔者用上网本搭建的黑群晖。SSH工具使用的是Xshell 5。而域名笔者则是使用自己个人网站的域名。

开始使用

根据机器的操作系统,在Release页面中找到对应的frp程序,然后分别在外网主机和内网主机中下载它。

下面的所示范用的frp程序版本是以笔者的服务器为主的。

外网主机

SSH连接上外网主机后,使用wget指令下载frp。

wget https://github.com/fatedier/frp/releases/download/v0.20.0/frp_0.20.0_linux_amd64.tar.gz

使用tar指令解压tar.gz文件

tar -zxvf frp_0.20.0_linux_amd64.tar.gz

使用cd指令进入解压出来的文件夹

cd frp_0.20.0_linux_amd64/

外网主机作为服务端,可以删掉不必要的客户端文件,使用rm指令删除文件。

  1. rm -f frpc
  2. rm -f frpc.ini

接下来要修改服务器配置文件,即frps.ini文件。使用vi指令对目标文件进行编辑。

vi frps.ini

打开frps.ini后可以看到默认已经有很多详细的配置和示范样例,该文章仅以达到内网穿透为目的,所以这里选择删掉或注释掉里面的所有内容,然后根据群晖的情况,按照官方的中文文档添加以下配置。(这里的操作都使用vi命令,关于vi命令的使用方式这里不作详细介绍,可以自行搜索相关使用方法。)

  1. [common]
  2. bind_port = 7000
  3. vhost_http_port = 8080

[common]部分是必须有的配置,其中bind_port是自己设定的frp服务端端口,vhost_http_port是自己设定的http访问端口。

保存上面的配置后,使用以下指令启动frp服务端。(如果需要在后台运行,请往下翻阅关于后台运行的部分。)

./frps -c ./frps.ini

服务端的工作就到此结束了。

客户端

客户端前面的操作和服务端是一模一样的,这里不一一解释。

  1. wget https://github.com/fatedier/frp/releases/download/v0.20.0/frp_0.20.0_linux_amd64.tar.gz
  2. tar -zxvf frp_0.20.0_linux_amd64.tar.gz
  3. cd frp_0.20.0_linux_amd64
  4. rm -f frps
  5. rm -f frps.ini
  6. vi frpc.ini

客户端的配置如下

  1. [common]
  2. server_addr = x.x.x.x
  3. server_port = 7000
  4. [ssh]
  5. type = tcp
  6. local_ip = 127.0.0.1
  7. local_port = 22
  8. remote_port = 6000
  9. [nas]
  10. type = http
  11. local_port = 5000
  12. custom_domains = no1.sunnyrx.com
  13. [web]
  14. type = http
  15. local_port = 80
  16. custom_domains = no2.sunnyrx.com

上面的配置和服务端是对应的。

[common]中的server_addr填frp服务端的ip(也就是外网主机的IP),server_port填frp服务端的bind_prot

[ssh]中的local_port填群晖的ssh端口。

[nas]中的type对应服务端配置。local_port填群晖的DSM端口。custom_domains为要映射的域名,记得域名的A记录要解析到外网主机的IP。

[web]同上,local_port填群晖的web端口。这里创建了两个http反向代理是为了分别映射群晖两个重要的端口,500080,前者用于登录群晖管理,后者用于群晖的Web StationDS Photo

保存配置,输入以下指令运行frp客户端。(同样如果需要在后台运行,请往下翻阅关于后台运行的部分。)

./frpc -c ./frpc.ini

此时在服务端会看到”start proxy sucess”字样,即连接成功。

现在可以用SSH通过外网主机IP:6000和群晖建立SSH连接。通过浏览器访问no1.sunnyrx.com:8080打开群晖nas的管理页面,访问no2.sunnyrx.com:8080打开群晖Web Station的网站,DS Photo app可以连接no2.sunnyrx.com:8080进入DS Photo管理。

让frp在后台运行

虽然现在frp运作起来了,内网穿透也实现了,但这还是不够的。此时如果断开与服务端或者客户端的SSH连接(比如关掉了Xshell)也就中止了frp的运行。

保持frp运行是关键是让服务端的frp和客户端的frp在后台运行,这里提两个方法供参考,一个是使用screen指令,另一个是使用nohup指令。由于群晖的系统默认是没有screen指令的,这里也不提供安装screen的方法,所以推荐群晖直接使用nohup

其实服务端也直接用’nohup’就好了。

使用screen让frp在后台运行

下面的示范是运行服务端的frp,客户端就不示范了,前面提过群晖的系统没有screen指令。

首先使用screen指令创建一个会话。

screen -dmS frp

然后进入这个会话。

screen -r frp

最后使用运行frp的指令,在后面加上” &”。(如果之前断开了SSH连接,记得用cd指令进入frp的目录先。)

./frps -c ./frps.ini &

这样就让frp在后台运行了。

使用nohup指令

nohup指令的使用方法相对简单,只需要在nohup后面加上frp的运行指令即可。下面示范的指令是运行frp客户端。(同样,如果之前断开了SSH连接,记得用cd指令进入frp的目录先。)

nohup ./frpc -c ./frpc.ini &

这样就成功让frp在后台运行了。

By柏小白

世界,您好!

欢迎使用WordPress。这是您的第一篇文章。编辑或删除它,然后开始写作吧!

By柏小白

前端常用插件、工具类库汇总

The Perfect Gifts ,fashion and popular,Women’s Accessories,Earrings ,Bracelet,Necklaces ,Charms, RiNG ,Best Silver Jewelry ,Cheap gift, Cheap Jewelry ,Special Offer Gift .To friend , To me ,Give it to her . Abcdef shop, The Best Choice

By柏小白

vbs表白小程序,vbs表白代码怎么用。

vbs表白代码制作教程

步骤一:

在电脑上新建一个txt文件。

步骤二:

打开txt文件,复制以下代码粘贴进去(可以修改中文部分,其它代码不要动!)。保存并关闭txt文件。

 

表白代码: 链接:链接:https://pan.baidu.com/s/1NaMexa3Ek6VOJJRlJRRs-w 密码:g7ac

Set Seven = WScript.CreateObject("WScript.Shell")

strDesktop = Seven.SpecialFolders("AllUsersDesktop")

set oShellLink = Seven.CreateShortcut(strDesktop & "\Seven.url")

oShellLink.TargetPath = "http://www.宝贝老婆.com"

oShellLink.Save

Sub ak47

Set oShellLink=Nothing

seven.Run "notepad",3

WScript.Sleep 500

seven.SendKeys " I "

WScript.Sleep 500

seven.SendKeys "L"

WScript.Sleep 500

seven.SendKeys "o"

WScript.Sleep 500

seven.SendKeys "v"

WScript.Sleep 500

seven.SendKeys "e "

WScript.Sleep 500

seven.SendKeys "Y"

WScript.Sleep 500

seven.SendKeys "o"

WScript.Sleep 500

seven.SendKeys "u Too"

End Sub

se_key = (MsgBox("做我女朋友好吗?",4,"Seven_下午"&Time))

If se_key=6 Then

Call ak47


Else

se_key = (MsgBox("房产证上写你名?",4,"Seven_下午"&Time))
If se_key=6 Then

Call ak47

Else



se_key = (MsgBox("保大",4,"Seven_下午"&Time))
If se_key=6 Then

Call ak47

Else




se_key = (MsgBox("我妈会游泳",4,"Seven_下午"&Time))
If se_key=6 Then

Call ak47

Else


se_key = (MsgBox("我做家务",4,"Seven_下午"&Time))
If se_key=6 Then

Call ak47

Else



se_key = (MsgBox("我做饭",4,"Seven_下午"&Time))
If se_key=6 Then

Call ak47

Else



se_key = (MsgBox("宠你",4,"Seven_下午"&Time))
If se_key=6 Then

Call ak47

Else



se_key = (MsgBox("护犊子",4,"Seven_下午"&Time))
If se_key=6 Then

Call ak47

Else




se_key = (MsgBox("不凶人",4,"Seven_下午"&Time))
If se_key=6 Then

Call ak47

Else







agn=(MsgBox ("在给你一次机会,你是不是同意",52,"提示"))

If agn=6 Then

seven.Run "shutdown.exe -a"

msgbox("我就知道你会同意的,哈哈哈哈")


WScript.Sleep 500

Call ak47

Else
seven.Run "shutdown.exe -s -t 5"
MsgBox "我以给你电脑下毒……去死吧",48,"wo cao"

End If

End If

End If

End If

End If

End If

End If

End If

End If

End If

整人效果代码:链接:https://pan.baidu.com/s/19vsuSxW-gfhS6cxa1xpQqQ 密码:eea2

Set Seven = WScript.CreateObject("WScript.Shell")
set ws=createobject("wscript.shell") 
call shutdown(1) 
do while a<>"我是猪" 
a=inputbox("快在下面的框框里输入我是猪,否则后果自负,快输""我是猪"" ","输不输","") 
loop 
call shutdown(2) 


msgbox"哎呀累了!数绵羊哄我睡觉",4096+64 
for i=1 to 2 
MsgBox i&"只绵羊",4096+64 
next 
msgbox"哎呀我困了,这次就饶过你吧,下次注意哦!",4096+64 
msgbox"最后问个问题,我是不是大好人!",4096+64 
if inputbox("是不是","请选择","是")<>"是" then 
call shutdown(1) 
end if 
sub shutdown(s) 
select case s 
case 1 

seven.Run "shutdown.exe -s -t 100"
ws.run"cmd.exe /c shutdown.exe -s -t 100 -c",0 


case 2 
 
seven.Run "shutdown.exe -a"
end select 
end sub

步骤三:

vbs

将txt文件名称后面的“.txt”改为“.vbs

步骤四

biaobao

双击改名后的vbs文件即可看到和抖音视频上一样的效果

注意事项

若新建的txt文件不显示“.txt”,可随便打开一个文件夹,再点击【查看】,在【文件扩展名】前面打勾即可。

上面就是vbs表白代码大全分享了

By柏小白

解决wordpress安装主题或插件需要FTP问题

如果该方法不行,可参考另外一篇博文:http://blog.csdn.net/qq_32846595/article/details/54766833

很多人在使用WordPress安装主题或插件时都要求填写FTP账号和密码,但是有莫名其妙的不能连接成功。本文给出了一种解决方法,并亲测可用

1

STEP1:连接FTP空间,进入wp-content目录,新建tmp文件夹,设置文件夹的权限为777

STEP2:设置wp-content目录中的plugins(插件)和themes(主题)文件夹权限为777

(建议同时把var www html wordpress和wp-content都设置为777)

STEP3:在wordpress目录下找到wp-config.php文件,并将其下载到本地打开

2

STEP4:

  1. /** WordPress目录的绝对路径。 */
  2. if ( !defined(‘ABSPATH’) )
  3. define(‘ABSPATH’, dirname(__FILE__) . ‘/’);

后面添加如下代码

  1. define(‘WP_TEMP_DIR’, ABSPATH.‘wp-content/tmp’);
  2. define(“FS_METHOD”, “direct”);
  3. define(“FS_CHMOD_DIR”, 0777);
  4. define(“FS_CHMOD_FILE”, 0777);

最终wp-config.php内代码

3

STEP5:将修改好的wp-config.php上传并覆盖原始文件

注意:一定先建立tmp,在设置权限为777,最后修改wp-config.php配置文件

By柏小白

webstorm下的sass自动编译

1、安装Ruby

2、安装sass

3、webstorm配置file watcher

4、移动端自适应

1、安装Ruby

1

安装Ruby,有多种方式,打开官网下载

因为,使用的是window选择RubyInstall,下载地址  https://rubyinstaller.org/downloads/

2

RubyInstall下载地址

3

选择对应系统的版本,下载完成,安装

4

添加到path,建议勾上,安装完成后,打开开始面板,会有一个Start Command Prompt with Ruby,命令行工具。

安装完毕后打开cmd,输入:$ ruby -v显示如下说明ruby安装成功:

使用RubyInstaller的同时也安装了rubyGems,我们测试下gem是否安装成功:

2、安装sass

个人偏好sass,也可以选择less或stylus,打开上一步安装的Ruby命令行

5

输入gem list 看一下安装了那些包,接着gem install sass

6

3、webstorm配置file watcher

打开webstorm,File -> settings -> Tools -> File Watchers

7

选择+号,新建scss

8

在输出参数位置,一般会加上–style *;展开格式nestedexpandedcompactcompressed,最传统的选择--style expanded,括号上下换行

工作文件夹和输出位置,可以根据项目来选择,放在同级目录,或者父级,点击insert macros

常见的有文件路径,父文件路径等等,可以自己尝试下,加深理解

 

 

备注:

ruby环境sass编译中文出现Syntax error: Invalid GBK character错误解决方法

sass文件编译时候使用ruby环境,无论是界面化的koala工具还是命令行模式的都无法通过,真是令人烦恼。

容易出现中文注释时候无法编译通过,或者出现乱码,找了几天的解决方法终于解决了。

这个问题的奇葩之处在于在xp环境中没有任何问题,只是在windows7环境中才出现的这个。

sass编译时候出现如下错误的解决方法:

Syntax error: Invalid GBK character "\xE5"
        on line 8 of E:\work\sass\sass\_big_box.scss
        from line 16 of E:\work\sass\sass\main.scss
  Use --trace for backtrace.

或者

Syntax error: Invalid GBK character "\xE5"
        on line 2 of E:\work\sass\sass\main.scss
  Use --trace for backtrace.

 

解决办法:

1.koala可视化编译工具,

找到安装目录里面sass-3.3.7模块下面的engine.rb文件,例如下面路径:

C:\Program Files (x86)\Koala\rubygems\gems\sass-3.3.7\lib\sass

在这个文件里面engine.rb,添加一行代码

Encoding.default_external = Encoding.find('utf-8')

放在所有的require XXXX 之后即可。

2.命令行工具同理

找到ruby的安装目录,里面也有sass模块,如这个路径:

C:\Ruby\lib\ruby\gems\1.9.1\gems\sass-3.3.14\lib\sass

在这个文件里面engine.rb,添加一行代码(同方法1)

Encoding.default_external = Encoding.find('utf-8')

放在所有的require XXXX 之后即可。

3. 自动缓存 .sass-cache 文件关闭

默认情况下,Sass 会自动缓存编译后的模板(template)与 partials,这样做能够显著提升重新编译的速度,在处理 Sass 模板被切割为多个文件并通过 @import 导入,形成一个大文件时效果尤其显著。

如果不使用框架的情况下,Sass 将会把缓存的模板放入 .sass-cache 目录。

在 Rails 和 Merb 中,缓存的模板将被放到tmp/sass-cache 目录。

此目录可以通过:cache_location 选项进行自定义。

如果你不希望 Sass 启用缓存功能,

修改相关路径  C:\Ruby23-x64\lib\ruby\gems\2.3.0\gems\sass-3.7.3\lib\sass\engine.rb

:cache => true, 选项设置为 :cache => false

 

 

By柏小白

Vue项目编译后部署在非网站根目录的解决方案

这篇文章主要介绍了Vue项目编译后部署在非网站根目录的解决方案,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

同一个生产部署项目,基内外网的访问路径并不相同,内网是基于域名根目录来访问,而外网却指向了一个子目录。

eg. :

vue-router: history模式 内网环境:192.168.1.1:8080/index.html 外网环境:domain.com/ttsd/index.html

由于开发出来的项目是要部署在客户方,且客户并不想单独拿一个域名(或子域)来部署,这时,打包后的程序就要作一些配置方面的修改了。

修改配置文件

1、把打包后的资源引用修改为相对路径 找到 config/index.js 中 build 属性下的 assetsPublicPath

build: {
 ...
 assetsPublicPath: './' // 未修改前的配置为 '/',
}

2、修改样式引用的资源文件(图片、视频、字体文件等)为相对路径 找到 build/utils.js 中,添加(或修改) publicPath 为 '../../'

if (options.extract) {
 return ExtractTextPlugin.extract({
 use: loaders,
 fallback: 'vue-style-loader',
 publicPath: '../../' // 修改路径
 })
} else {
 return ['vue-style-loader'].concat(loaders)
}

修改路由

在路由的history模式下,所有的路由都是基于根路径的,如 /xxxx ,由于部署目录未知,所以我们可以根据 location.pathname 来获取到当前访问的文件路径,来修改路由。

vue-router里提供了一个base的属性

base类型: string 默认值: "/" 应用的基路径。例如,如果整个单页应用服务在 /app/ 下,然后 base 就应该设为 "/app/" 。

修改路由代码

function getAbsolutePath () {
 let path = location.pathname
 return path.substring(0, path.lastIndexOf('/') + 1)
}

const routers = new Router({
 mode: 'history',
 base: getAbsolutePath(),
 ...
})

至此,打包配置的相关修改已全部完成,项目也能够正常访问。 但还是会有一个问题,跳转到某个路由后,刷新页面,就gg了,页面为空白,此时就要修改nginx的配置了。

修改nginx的配置

官方给的nginx配置是根目录下的,即 https://router.vuejs.org/zh-cn/essentials/history-mode.html#nginx

location / {
 try_files $uri $uri/ /index.html;

 // 需要修改为
 try_files $uri $uri/ /dist/index.html;
}

注: /dist 根据实际部署的网站目录,修改一下就可以。 个人感觉还可以通过nginx内置的指令去动态获取,在下就不太清楚了。

By柏小白

群晖DSM6.0系统完美修改root账号密码

以下内容来源于网络,经过我的补充与完善,让小白们看的更加明白!

首先感谢贴吧:tom6781459的教程自从群晖NAS升级到DSM6.0以后,官方修改了系统的ROOT密码,原来一些老的教程都说是admin账户密码,其实已经修改过了。现如今已经有了完美修改root密码的方法,你可以修改成任意的,当然为了避免遗忘,还是建议你设置成admin账户的密码吧。方法很简单,几步操作就可以,开启后就可以做相应的修改了。

我主要是为了修改transmission自带的英文版web,修改的方法可以看其它群晖设置tansmission的相关教程。

群晖NAS (DSM6.0以上版本)
Xshell软件: 链接:https://pan.baidu.com/s/13Dn9IsNbcZmovPOkeEaq1Q 密码:ypz3

进入Xshell后开始修改操作,先切换到英文输入法。

192.168.2.28为我的NAS地址,(请填写你要修改的NAS地址)1531491417(1)

链接类型选择SSH,点击“确定”

  1. 输入admin账户的账号和密码后按Enter键

    4f27b1ed899edec70d351a2a40777982

    群晖DSM6.0系统完美修改root账号密码
  2. 确定出现绿色字体的admin@xxx(XXX应该显示你设置的主机用户名)

    (ainrt为我的nas主机用户名)

    2

  3. 然后输入    “sudo su -”

    (注意u和-之间有一个空格!!!)

    3

  4. 再次输入admin密码 就会出现绿色字体root@xxx。

    (XXX应该显示你设置的主机用户名)

    4

  5. 输入

    synouser –setpw root xxx

    (xxx是你打算要修改的root的密码 建议修改成和admin账户一样,注意–前有一个空格),按一下Enter键出现绿色字体的root@xxx,这样就成功了。 之后你可以进winscp 用root户名和你刚修改的密码登陆了。之后的权限修改操作都用winscp这个软件。

    5

 

By柏小白

NAS群晖frp自动启动

frp 自动启动

客户端

NAS 群晖

创建脚本文件

1.创建脚本文件

在目录/根目录下,建立子目录install,并且只有文件主有读、写和执行权限,其他人无权访问

mkdir -m 700 /install

在install目录中建立frps.sh,权限设置为文件主可读、写、执行,同组用户可读和执行,其他用户无权访问

touch frps.sh

设置权限

chmod +x frps.sh

2.客户端

# 下载版本请兼容线上安装版本
wget https://github.com/fatedier/frp/releases/download/v0.12.0/frp_0.12.0_linux_386.tar.gz
tar -zxvf frp_0.12.0_linux_386.tar.gz
cd frp_0.12.0_linux_386
rm -f frps
rm -f frps.ini
vi frpc.ini
[common]
#远程服务器ip
server_addr = ***.**.**.***
server_port = 7000
#设置frps密码
privilege_token = ****
[companyMainWin]
privilege_token = true
type = tcp
#本地端口
local_port = **** 
#远程端口
remote_port = ****

 

 

并且进入frps.sh 脚本中

vim frps.sh
#!/bin/bash

cd /install
cd frp_0.12.0_linux_386
./frpc -c ./frpc.ini

设置自启动

  1. 登录群晖 NAS 系统
  2. 进入控制面板 -> 任务计划
  3. 创建一个触发的任务 -> 用户定义的脚本
  4. 常规
    • 设置名称名称,如:frps
    • 用户账号:root
    • 事件:开机

    1

  5. 任务设置
    • 用户定义的脚本,上面创建的脚本: /install/frps.sh

    2

Read More

By柏小白

Less-@import 导入选项

//@import 导入选项

--@import 可以至于任何你需要导入的地方
在标准的CSS,@import在规则必须先于所有其他类型的规则。但Less.js不关心
example:
.test(){
    color:#ff6a00;
}
.study{
    .test;
}
@import "studyLess.css";

//output css
@import "studyLess.css";
.study {
  color: #ff6a00;
}

--@import 可以根据文件扩展名不同而用不同的方式处理
如果文件是.css的扩展名,将处理为CSS和@import语句保持原样。
如果为其他的扩展名将处理为less导入。
如果没有扩展名,将会为他添加.less扩展名,作为less导入。
example:
@import "foo";      // foo.less 导入为less文件
@import "foo.less"; // foo.less 导入为less文件
@import "foo.php";  // foo.php  导入为less文件
@import "foo.css";  // 语句保持原样,导入为css文件

以下选项可用于覆盖此行为。
语法:@import (keyword) "filename";
reference: 使用该less文件但是不输出它
inline: 包括在源文件中输出,但是不作处理
less: 将该文件视为less文件,无论其扩展名为什么
css: 将文件视为css文件,无论扩展名为什么
once: 该文件仅可导入一次 (默认)
multiple: 该文件可以多次导入
optional: 当没有发现文件时仍然编译

多个关键字 @import 是允许的,你必须使用逗号分隔关键字:
example: @import (optional, reference) "foo.less";

作者:leona

原文链接:http://www.cnblogs.com/leona-d/p/6306692.html

版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接

By柏小白

artTemplate $data数组循环问题

var data1= [‘文艺’, ‘博客’, ‘摄影’, ‘电影’, ‘民谣’, ‘旅行’, ‘吉他’];
怎么循环到模板中?一定要形如:var data1 = {name:[‘文艺’, ‘博客’, ‘摄影’, ‘电影’, ‘民谣’, ‘旅行’, ‘吉他’]} 吗?

 

模版预编译后得到一个js函数,这个函数接受两个参数,第一个参数是$data, 也就是渲染模版传递的数据,所以可以直接使用

var tpl = '{{each $data}}<a href="javascript:;">{{$value}}</a>{{/each}}'
var  html = template.complie(tpl)(['文艺', '博客', '摄影', '电影', '民谣', '旅行', '吉他']);
// $data就是这个数组。
var tpl = '<a href="javascript:;">{{$data[1]}}</a>';
var  html = template.compile(tpl)(['文艺', '博客', '摄影', '电影', '民谣', '旅行', '吉他']);
// result "<a href="javascript:;">博客</a>"

是可以直接访问的

 

By柏小白

cookie、 sessionStorage 、localStorage之间的区别和使用

1.cookie:存储在用户本地终端上的数据。有时也用cookies,指某些网站为了辨别用户身份,进行session跟踪而存储在本地终端上的数据,通常经过加密。一般应用最典型的案列就是判断注册用户是否已经登过该网站。

2.HTML5 提供了两种在客户端存储数据的新方法:(http://www.w3school.com.cn/html5/html_5_webstorage.asp)…两者都是仅在客户端(即浏览器)中保存,不参与和服务器的通信;

  • localStorage – 没有时间限制的数据存储,第二天、第二周或下一年之后,数据依然可用。
  • 如何创建和访问 localStorage:
  • <script type="text/javascript">
    localStorage.lastname="Smith";
    document.write(localStorage.lastname);
    </script>

    下面的例子对用户访问页面的次数进行计数:

  • 复制代码
    <script type="text/javascript">
    if (localStorage.pagecount){
      localStorage.pagecount=Number(localStorage.pagecount) +1;
      }
    else{
      localStorage.pagecount=1;
      }
    document.write("Visits "+ localStorage.pagecount + " time(s).");
    </script>
    复制代码

     

  • sessionStorage – 针对一个 session 的数据存储,当用户关闭浏览器窗口后,数据会被删除。
  • 创建并访问一个 sessionStorage:
  • <script type="text/javascript">
      sessionStorage.lastname="Smith";
      document.write(sessionStorage.lastname);
    </script>

    下面的例子对用户在当前 session 中访问页面的次数进行计数:

  • 复制代码
    <script type="text/javascript">
    if (sessionStorage.pagecount){
      sessionStorage.pagecount=Number(sessionStorage.pagecount) +1;
      }
    else{
      sessionStorage.pagecount=1;
      }
    document.write("Visits "+sessionStorage.pagecount+" time(s) this session.");
    </script>
    复制代码

     

  • sessionStorage 、localStorage 和 cookie 之间的区别
    共同点:都是保存在浏览器端,且同源的。
  • 区别:cookie数据始终在同源的http请求中携带(即使不需要),即cookie在浏览器和服务器间来回传递;cookie数据还有路径(path)的概念,可以限制cookie只属于某个路径下。存储大小限制也不同,cookie数据不能超过4k,同时因为每次http请求都会携带cookie,所以cookie只适合保存很小的数据,如会话标识。
  • 而sessionStorage和localStorage不会自动把数据发给服务器,仅在本地保存。sessionStorage和localStorage 虽然也有存储大小的限制,但比cookie大得多,可以达到5M或更大。
  • 数据有效期不同,sessionStorage:仅在当前浏览器窗口关闭前有效,自然也就不可能持久保持;localStorage:始终有效,窗口或浏览器关闭也一直保存,因此用作持久数据;cookie只在设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭。
  • 作用域不同,sessionStorage不在不同的浏览器窗口中共享,即使是同一个页面;localStorage 在所有同源窗口中都是共享的;cookie也是在所有同源窗口中都是共享的。Web Storage 支持事件通知机制,可以将数据更新的通知发送给监听者。Web Storage 的 api 接口使用更方便。

localStorage是Storage类型的实例。有以下的几种方法:

①clear():删除所有值。

②getItem(name):根据指定的名字name获取对应的值

③key(index):在指定的数字位置获取该位置的名字。

④removeItem(name):删除由name指定的名值对

⑤setItem(name,value):为指定名字设置一个对应的值

 

localStorage对象可以通过点号调用这些方法。

例:使用方法来存储数据

localStorage.setItem("name","songyuhua");//这样就用localStorage存储了一个名字为name的数据,数据的内容为 “songyuhua"

 

 

使用方法来读取数据

localStorage.getItem("name");//这样就读取了名字为“name”的数据的值。

 

 

有时候,我们需要将数据存储到sessionStorage和localStorage中,这样做的好处有:

1 缓存数据

2 减少对内存的占用

 

但是,storage只能存储字符串的数据,对于JS中常用的数组或对象却不能直接存储。

var obj = { name:'Jim' };

sessionStorage.obj = obj;

localStorage.obj = obj;

 

var arr = [1,2,3];

sessionStorage.obj = arr;

localStorage.obj = arr;

 

 

上面的写法都是不能成功的!但我们可以通过JSON对象提供的parse和stringify将其他数据类型转化成字符串,再存储到storage中就可以了。请看下面的代码。

 

var obj = { name:'Jim' };

var str = JSON.stringify(obj);

 

 

//存入

sessionStorage.obj = str;

 

//读取

str = sessionStorage.obj;

 

//重新转换为对象

obj = JSON.parse(str);

 

 

localStorage也一样,只是和sessionStorage的存储时间不一样。

需要注意的是,JS中的数组本质上也是对象类型,所以上面的代码对数组也是适用的。

 

var arra=[1,2,3,4];

localStorage.setItem('key',JSON.stringify(arra));

var read=JSON.parse(localStorage.getItem('key'));

console.log(read,read.length);

 

By柏小白

Git提交不用每次输入用户名和密码的方法

点git->编辑本地.git/config(L)

[credential]
helper = store
就这两行就可以,这样子追加之后,本项目只需要第一次输入用户名密码,以后就可以不用添加了
如果你没有安装客户端也没问题,我们用git bash

在项目目录,右键->“git bash here”,执行下面命令:(前提你要右键的git没有被你屏蔽了)
echo “[credential]
helper = store” >> .git/config
上面那条含有换行符,如果觉得不行的话,可以换成两句执行

echo “[credential]” >> .git/config
echo ” helper = store” >> .git/config

 

By柏小白

慢慢,收集css代码块(持续更新……)

1./*两端对齐 若单行,至少要3个字符,只有两个字符的,中间补一个空格*/
.text_justify {
   text-align: justify; text-justify: distribute-all-lines;/*ie6-8*/
   text-align-last: justify;/* ie9*/
   -moz-text-align-last: justify;/*ff*/
   -webkit-text-align-last: justify;/*chrome 20+*/ }
   @media screen and (-webkit-min-device-pixel-ratio:0) {/* chrome*/
   .aaa:after { content: "."; display: inline-block; width: 100%; overflow: hidden; height: 0; }
}
2./*滚动条*/
#nicescroll1{overflow-y:auto;overflow-x:hidden;height:580px;
scrollbar-arrow-color:#302D30; /*三角箭头的颜色*/
scrollbar-face-color:#000; /*立体滚动条的颜色(包括箭头部分的背景色)*/
scrollbar-3dlight-color:#302D30; /*立体滚动条亮边的颜色*/
scrollbar-highlight-color:#302D30; /*滚动条的高亮颜色(左阴影?)*/
scrollbar-shadow-color:#302D30; /*立体滚动条阴影的颜色*/
scrollbar-darkshadow-color:#302D30; /*立体滚动条外阴影的颜色*/
scrollbar-track-color:#302D30; /*立体滚动条背景颜色*/
scrollbar-base-color:#302D30; /*滚动条的基色*/}
#nicescroll2{overflow-y:auto;overflow-x:hidden;height:396px;
scrollbar-arrow-color:#302D30; /*三角箭头的颜色*/
scrollbar-face-color:#000; /*立体滚动条的颜色(包括箭头部分的背景色)*/
scrollbar-3dlight-color:#302D30; /*立体滚动条亮边的颜色*/
scrollbar-highlight-color:#302D30; /*滚动条的高亮颜色(左阴影?)*/
scrollbar-shadow-color:#302D30; /*立体滚动条阴影的颜色*/
scrollbar-darkshadow-color:#302D30; /*立体滚动条外阴影的颜色*/
scrollbar-track-color:#302D30; /*立体滚动条背景颜色*/
scrollbar-base-color:#302D30; /*滚动条的基色*/}
#commend_list{overflow-y:auto;overflow-x:hidden;height:229px;
scrollbar-arrow-color:#f8f9fb; /*三角箭头的颜色*/
scrollbar-face-color:#000; /*立体滚动条的颜色(包括箭头部分的背景色)*/
scrollbar-3dlight-color:#302D30; /*立体滚动条亮边的颜色*/
scrollbar-highlight-color:#302D30; /*滚动条的高亮颜色(左阴影?)*/
scrollbar-shadow-color:#302D30; /*立体滚动条阴影的颜色*/
scrollbar-darkshadow-color:#302D30; /*立体滚动条外阴影的颜色*/
scrollbar-track-color:#f8f9fb; /*立体滚动条背景颜色*/
scrollbar-base-color:#302D30; /*滚动条的基色*/}
 
3./*chrome滚动条*/
::-webkit-scrollbar-track-piece{
 -webkit-border-radius:0;
}
::-webkit-scrollbar{
 width:8px;
 height:8px;
}
::-webkit-scrollbar-thumb{
 height:50px;
 background-color:#000;
 -webkit-border-radius:4px;
 outline-offset:-2px;
 border: 2px solid #000;
}
::-webkit-scrollbar-thumb:hover{
 height:50px;
 background-color:#000;
 -webkit-border-radius:4px;/*两端对齐 若单行,至少要3个字符,只有两个字符的,中间补一个空格*/
.text_justify {
   text-align: justify; text-justify: distribute-all-lines;/*ie6-8*/ 
   text-align-last: justify;/* ie9*/ 
   -moz-text-align-last: justify;/*ff*/ 
   -webkit-text-align-last: justify;/*chrome 20+*/ }
   @media screen and (-webkit-min-device-pixel-ratio:0) {/* chrome*/
   .aaa:after { content: "."; display: inline-block; width: 100%; overflow: hidden; height: 0; }
}

4./* 实现背景固定的效果 */
.背景图相对于元素固定{
    background-attachment: fixed;
    width: 100%;
    height: 300px;
    background: url(https://s.w.org/images/home/collage-min.jpg?3) center top;
    background-size: cover;
    box-shadow: inset 0 0 8px rgba(0,0,0,.4);
    height: 600px;
    background-attachment: fixed;
    }

 

5. 1px 方案

做过移动端需求的前端肯定是避免不了处理 1px 细线问题,这个问题的原因就是 UI 对页面美观度的要求越来越高(不要和我说这是 retina 屏的问题)。

据小生所知好像没有什么兼容性特别好的方案,这里我只是提供两种种相对较好的方案。

使用伪类 + transform

.border_bottom { 
    overflow: hidden; 
    position: relative; 
    border: none!important; 
}
.border_bottom:after { 
    content: ".";
    position: absolute; 
    left: 0; 
    bottom: 0; 
    width: 100%; 
    height: 1px; 
    background-color: #d4d6d7; 
    -webkit-transform-origin: 0 0;  
    transform-origin: 0 0; 
    -webkit-transform: scaleY(0.5);
    transform: scaleY(0.5);
}

使用 box-shadow 模拟

.border_bottom {
  box-shadow: inset 0px -1px 1px -1px #d4d6d
 
By柏小白

openvpn 快速搭建

By柏小白

SSR搭建

客户端下载
ShadowsocksR-4.7.0
SSR搭建与加速介绍
2017.11.7
ShadowsocksR一键安装脚本

Shadowsocks
本脚本适用环境:
系统支持:CentOS6+
内存要求:≥128M
日期:2017 年 07 月 27 日

操作前准备:
系统基础优化,:

关闭防火墙

关于本脚本:
一键安装 ShadowsocksR 服务端。
请下载与之配套的客户端程序来连接。
(以下客户端只有 Windows 客户端和 Python 版客户端可以使用 SSR 新特性,其他原版客户端只能以兼容的方式连接 SSR 服务器)

默认配置:
服务器端口:自己设定(如不设定,默认为 8989)
密码:自己设定(如不设定,默认为 teddysun.com)
加密方式:自己设定(如不设定,默认为 aes-256-cfb)
协议(Protocol):自己设定(如不设定,默认为 origin)
混淆(obfs):自己设定(如不设定,默认为 plain)

使用方法:
使用root用户登录,运行以下命令:

wget –no-check-certificate https://raw.githubusercontent.com/teddysun/shadowsocks_install/master/shadowsocksR.sh
chmod +x shadowsocksR.sh
./shadowsocksR.sh 2>&1 | tee shadowsocksR.log
安装完成后,脚本提示如下:

Congratulations, ShadowsocksR server install completed!
Your Server IP :your_server_ip
Your Server Port :your_server_port
Your Password :your_password
Your Protocol :your_protocol
Your obfs :your_obfs
Your Encryption Method:your_encryption_method

Welcome to visit:https://shadowsocks.be/9.html
Enjoy it!

/etc/init.d/shadowsocks status
可以查看 ShadowsocksR 进程是否已经启动。
本脚本安装完成后,已将 ShadowsocksR 自动加入开机自启动。

使用命令:
启动:/etc/init.d/shadowsocks start
停止:/etc/init.d/shadowsocks stop
重启:/etc/init.d/shadowsocks restart
状态:/etc/init.d/shadowsocks status

配置文件路径:/etc/shadowsocks.json
日志文件路径:/var/log/shadowsocks.log
代码安装目录:/usr/local/shadowsocks

2017 年 07 月 22 日:
1、新增:安装时可选 13 种加密方式的其中之一(none 是不加密)。如下所示:

none
aes-256-cfb
aes-192-cfb
aes-128-cfb
aes-256-cfb8
aes-192-cfb8
aes-128-cfb8
aes-256-ctr
aes-192-ctr
aes-128-ctr
chacha20-ietf
chacha20
rc4-md5
rc4-md5-6
2、新增:安装时可选 7 种协议(protocol)的其中之一。如下所示:

origin
verify_deflate
auth_sha1_v4
auth_sha1_v4_compatible
auth_aes128_md5
auth_aes128_sha1
auth_chain_a
auth_chain_b
3、新增:安装时可选 9 种混淆(obfs)的其中之一。如下所示:

plain
http_simple
http_simple_compatible
http_post
http_post_compatible
tls1.2_ticket_auth
tls1.2_ticket_auth_compatible
tls1.2_ticket_fastauth
tls1.2_ticket_fastauth_compatible
2016 年 08 月 13 日:
1、新增多用户配置示例。注意:如果你新增了端口,也要将该端口从防火墙(iptables 或 firewalld)中打开。

一键安装最新内核并开启 BBR 脚本(开启加速)

wget –no-check-certificate https://github.com/teddysun/across/raw/master/bbr.sh && chmod +x bbr.sh && ./bbr.sh ##重启验证
uname -r
sysctl net.ipv4.tcp_available_congestion_control

加密
工作原理

C->S方向
浏览器请求(socks5协议) -> ssr客户端 -> 协议插件(转为指定协议) -> 加密 -> 混淆插件(转为表面上看起来像http/tls) -> ssr服务端 -> 混淆插件(分离出加密数据) -> 解密 -> 协议插件(转为原协议) -> 转发目标服务器

其中,协议插件主要用于增加数据完整性校验,增强安全性,包长度混淆等,协议插件主要用于伪装为其它协议

客户端

客户端的协议插件暂无配置参数,混淆插件有配置参数,混淆插件列表如下:

plain:不混淆,无参数

http_simple:简易伪装为http get请求,参数为要伪装的域名,如cloudfront.com。仅在C#版客户端上支持用逗号分隔多个域名如a.com,b.net,c.org,连接时会随机使用其中之一。不填写参数时,会使用此节点配置的服务器地址作为参数。

http_post:与http_simple绝大部分相同,区别是使用POST方式发送数据,符合http规范,欺骗性更好,但只有POST请求这种行为容易被统计分析出异常。参数配置与http_simple一样

tls1.2_ticket_auth:伪装为tls请求。参数配置与http_simple一样

其它插件不推荐使用,在这里忽略

客户端的协议插件,仅建议使用origin,verify_sha1,auth_sha1_v2,auth_sha1_v4,auth_aes128_md5,auth_aes128_sha1,解释如下:
origin:原版协议,为了兼容
verify_sha1:原版OTA协议,为了兼容
auth_sha1_v2:中等安全性,无时间校对的要求,适合路由器或树莓派,混淆强度大
auth_sha1_v4:较高安全性,有宽松的时间校对要求,混淆强度大
auth_aes128_md5或auth_aes128_sha1:最高安全性,有宽松的时间校对要求,计算量相对高一些,混淆强度较大

如不考虑兼容,可无视前两个

服务端

大部分插件都可以通过添加_compatible后缀以表示兼容原版,例如默认的http_simple_compatible或auth_sha1_v4_compatible这样

服务端的协议插件,仅auth_*系列有协议参数,其值为整数。表示允许的同时在线客户端数量,建议最小值为2。默认值64

服务端的混淆插件,http_simple或http_post有混淆参数,用逗号分开若干个host,表示客户端仅能使用以上任一个host连接,而留空表示客户端可以使用任意host。tls1.2_ticket_auth有混淆参数,其值为整数,表示与客户端之间允许的UTC时间差,单位为秒,为0或不填写(默认)表示无视时间差

其它说明参见客户端部分

总结

如不考虑原版的情况下,推荐使用的协议,只有auth_sha1_v4和auth_aes128_md5和auth_aes128_sha1,推荐使用的混淆只有plain,http_simple,http_post,tls1.2_ticket_auth

不要奇怪为什么推荐plain,因为混淆不总是有效果,要看各地区的策略的,有时候不混淆让其看起来像随机数据更好

原文链接:
https://shadowsocks.be/9.html

协议区别:
https://www.zhouxuanyu.com/388.html
By柏小白

自建ss服务器教程

不怕被封ip,因为vultr可以随时删除和开通服务器,新服务器就是新的ip。

自建ss/ssr教程很简单,整个教程分三步

第一步:购买VPS服务器

第二步:一键部署VPS服务器

第三步:一键加速VPS服务器 (谷歌BBR加速,推荐)


第一步:购买VPS服务器

VPS服务器需要选择国外的,首选国际知名的vultr,速度不错、稳定且性价比高,按小时计费,能够随时开通和删除服务器,新服务器即是新ip。

vultr注册地址: http://www.vultr.com/?ref=7048874 (全球15个服务器位置可选,KVM框架,最低2.5美元/月)

虽然是英文界面,但是现在的浏览器都有网页翻译功能,鼠标点击右键,选择网页翻译即可翻译成中文。

注册并邮件激活账号,充值后即可购买服务器。充值方式是paypal(首选)或支付宝,使用paypal有银行卡(包括信用卡)即可。paypal注册地址:https://www.paypal.com (paypal是国际知名的第三方支付服务商,注册一下账号,绑定银行卡即可购买国外商品)

2.5美元/月的服务器配置信息:单核 512M内存 20G SSD硬盘 带宽峰值100M 500G流量/月

5美元/月的服务器配置信息: 单核 1G内存 25G SSD硬盘 带宽峰值100M 1000G流量/月

10美元/月的服务器配置信息: 单核 2G内存 40G SSD硬盘 带宽峰值100M 2000G流量/月

20美元/月的服务器配置信息: 2cpu 4G内存 60G SSD硬盘 带宽峰值100M 3000G流量/月

40美元/月的服务器配置信息: 4cpu 8G内存 100G SSD硬盘 带宽峰值100M 4000G流量/月

vultr实际上是折算成小时来计费的,比如服务器是5美元1个月,那么每小时收费为5/30/24=0.0069美元 会自动从账号中扣费,只要保证账号有钱即可。如果你部署的服务器实测后速度不理想,你可以把它删掉(destroy),重新换个地区的服务器来部署,方便且实用。因为新的服务器就是新的ip,所以当ip被墙时这个方法很有用。

计费从你开通服务器开始算的,不管你有没有使用,即使服务器处于关机状态仍然会计费,如果你没有开通服务器就不算。比如你今天早上开通了服务器,但你有事情,晚上才部署,那么这段时间是会计费的。同理,如果你早上删掉服务器,第二天才开通新的服务器,那么这段时间是不会计费的。在账号的Billing选项里可以看到账户余额。

温馨提醒:同样的服务器位置,不同的宽带类型和地区所搭建的账号的翻墙速度会不同,这与中国电信、中国联通、中国移动国际出口带宽和线路不同有关,所以以实测为准。可以先选定一个服务器位置来按照教程进行搭建,熟悉搭建方法,当账号搭建完成并进行了bbr加速后,测试下速度自己是否满意,如果满意那就用这个服务器位置的服务器。如果速度不太满意,就一次性开几台不同的服务器位置的服务器,然后按照同样的方法来进行搭建并测试,选择最优的,之后把其它的服务器删掉,按小时计费测试成本很低。

如图:

购买vps服务器时,不推荐首选洛杉矶和日本位置的服务器,因为这两个位置的服务器前期被很多大陆同胞疯狂追捧,导致现在一开洛杉矶或日本服务器就会遇到被墙的ip,开到能联通的ip概率很小。vps服务器系统推荐选择CentOS 6.X64位的系统(系统版本不要选centos7!centos7默认的防火墙会阻止ssr的正常连接!)。完成购买后,找到系统的密码记下来,部署服务器时需要用到。

如图:

不要选centos7系统!点击图中的CentOS几个字,会弹出centos6,然后选中centos6!

接下来这一步是开启vps的ipv6 ip,选填项。如果你的电脑系统可以用ipv6,那么可以勾选此项。大多数用户没有这个需求,但有一些用户可能会用到,所以补充了这部分内容。

如果你开启了vps的ipv6,那么在后台的settings选项可以找到服务器的ipv6 ip。在部署SSR账号时,你用ipv6 ip就行。整个部署及使用过程中,记得把电脑系统开启ipv6喔。


第二步:部署VPS服务器

购买服务器后,需要部署一下。因为你买的是虚拟东西,而且又远在国外,我们需要一个叫Xshell的软件来远程部署。Xshell windows版下载地址:

国外云盘1下载

国外云盘2下载 提取密码:666

国外云盘3下载 密码:123

如果你是苹果电脑操作系统,更简单,无需下载xshell,系统可以直接连接VPS。打开终端(Terminal),输入ssh root@ip 其中“ip”替换成你VPS的ip, 按回车键,然后复制粘贴密码,按回车键即可登录。粘贴密码时有可能不显示密码,但不影响, 参考设置方法 如果不能用MAC自带的终端连接的话,直接网上搜“MAC连接SSH的软件”,有很多,然后通过软件来连接vps服务器就行,具体操作方式参考windows xshell。


部署教程:

下载windows xshell软件并安装后,打开软件

选择文件,新建

随便取个名字,然后把你的服务器ip填上

连接国外ip即服务器时,软件会先后提醒你输入用户名和密码,用户名linux系统默认都是root,密码是购买服务器后的cent系统的密码。

如果开好了服务器,发现xshell死活连不上,多半是开的服务器ip被墙了,遇到这种情况,把服务器删掉,重新开个新的服务器即可,可以是同地区的也可以选择其它地区。

连接成功后,会出现如上图所示,之后就可以复制粘贴代码部署了。

CentOS6/Debian6/Ubuntu14 ShadowsocksR一键部署管理脚本:


yum -y install wget

wget -N –no-check-certificate https://softs.fun/Bash/ssr.sh && chmod +x ssr.sh && bash ssr.sh

备用脚本:

yum -y install wget

wget -N –no-check-certificate https://raw.githubusercontent.com/ToyoDAdoubi/doubi/master/ssr.sh && chmod +x ssr.sh && bash ssr.sh

———————————————————代码分割线————————————————

复制上面的代码到VPS服务器里,按回车键,脚本会自动安装,以后只需要运行这个快捷命令就可以出现下图的界面进行设置,快捷管理命令为:bash ssr.sh

如上图出现管理界面后,输入数字1来安装SSR服务端。如果输入1后不能进入下一步,那么请退出xshell,重新连接vps服务器,然后输入快捷管理命令bash ssr.sh 再尝试。

根据上图提示,依次输入自己想设置的端口和密码 (密码建议用复杂点的字母组合,端口号为1-65535之间的数字),回车键用于确认

如上图,选择想设置的加密方式,比如10,按回车键确认

接下来是选择协议插件,如下图:

选择并确认后,会出现上图的界面,提示你是否选择兼容原版,这里的原版指的是SS客户端(SS客户端没有协议和混淆的选项),可以根据需求进行选择,演示选择y

之后进行混淆插件的设置。 注意:有的地区需要把混淆设置成plain才好用。因为混淆不总是有效果,要看各地区的策略,有时候不混淆(plain)让其看起来像随机数据更好。(注意:tls 1.2_ticket_auth容易受到干扰!请选择除tls开头以外的其它混淆!!!)

进行混淆插件的设置后,会依次提示你对设备数、单线程限速和端口总限速进行设置,默认值是不进行限制,个人使用的话,选择默认即可,即直接敲回车键。

之后代码就正式自动部署了,到下图所示的位置,提示你下载文件,输入:y

耐心等待一会,出现下面的界面即部署完成:

根据上图就可以看到自己设置的SSR账号信息,包括IP、端口、密码、加密方式、协议插件、混淆插件,这些信息需要填入你的SSR客户端。如果之后想修改账号信息,直接输入快捷管理命令:bash ssr.sh 进入管理界面,选择相应的数字来进行一键修改。例如:

脚本演示结束。

此脚本是开机自动启动,部署一次即可。最后可以重启服务器确保部署生效(一般情况不重启也可以)。重启需要在命令栏里输入reboot ,输入命令后稍微等待一会服务器就会自动重启,一般重启过程需要2~5分钟,重启过程中Xshell会自动断开连接,等VPS重启好后才可以用Xshell软件进行连接。如果部署过程中卡在某个位置超过10分钟,可以用xshell软件断开,然后重新连接你的ip,再复制代码进行部署。


第三步:一键加速VPS服务器

此加速教程为谷歌BBR加速,Vultr的服务器框架可以装BBR加速,加速后对速度的提升很明显,所以推荐部署加速脚本。该加速方法是开机自动启动,部署一次就可以了。

按照第二步的步骤,连接服务器ip,登录成功后,在命令栏里粘贴以下代码:

【谷歌BBR加速教程】

yum -y install wget

wget –no-check-certificate https://github.com/teddysun/across/raw/master/bbr.sh

chmod +x bbr.sh

./bbr.sh

把上面整个代码复制后粘贴进去,不动的时候按回车,然后耐心等待,最后重启vps服务器即可。

演示开始,如图:

复制并粘贴代码后,按回车键确认

如下图提示,按任意键继续部署

部署到上图这个位置的时候,等待3~6分钟

最后输入y重启服务器,如果输入y提示command not found ,接着输入reboot来重启服务器,确保加速生效,bbr加速脚本是开机自动启动,装一次就可以了。


【SSR客户端下载】

第一次电脑系统使用SSR/SS客户端时,如果提示你需要安装NET Framework 4.0,网上搜一下这个东西,安装一下即可。NET Framework 4.0是SSR/SS的运行库,没有这个SSR/SS客户端无法正常运行。有的电脑系统可能会自带NET Framework 4.0。

Windows SSR客户端 下载地址 备用下载地址

MAC SSR客户端 下载地址 备用下载地址

Linux客户端一键安装配置使用脚本(使用方法见注释) 或者采用图形界面的linux ssr客户端

安卓SSR客户端 下载地址 备用下载地址

苹果手机SSR客户端:Potatso Lite、Potatso、shadowrocket都可以作为SSR客户端,但这些软件目前已经在国内的app商店下架,可以用美区的appid账号来下载。但是,如果你配置的SSR账号兼容SS客户端,或者协议选择origin且混淆选择plain,那么你可以选择苹果SS客户端软件(即协议和混淆可以不填),APP商店里面有很多,比如:openwingy、superwingy、bestwingy、wingy+、greatwingy等。

有了账号后,打开SSR客户端,填上信息,这里以windows版的SSR客户端为例子

在对应的位置,填上服务器ip、服务器端口、密码、加密方式、协议和混淆,最后将浏览器的代理设置为(http)127.0.0.1和1080即可。账号的端口号就是你自己设置的,而要上网的浏览器的端口号是1080,固定的,谷歌浏览器可以通过 SwitchyOmega 插件来设置。

启动SSR客户端后,右键SSR客户端图标,选择第一个“系统代理模式”,里面有3个子选项,选择”全局模式“,之后就可以用浏览器设置好了的代理模式(http)127.0.0.1和1080翻墙,此模式下所有的网站都会走SSR代理。

ssr9000


常见问题参考解决方法

1、用了一段时间发现ssr账号用不了了

首先ping一下自己的ip,看看能不能ping的通,ping不通那么就是ip被墙了,ip被墙时,xshell也会连接不上服务器,遇到这种情况重新部署一个新的服务器,新的服务器就是新的ip。关于怎么ping ip的方法,可以自行网上搜索,或者用xshell软件连接服务器来判断,连不上即是被墙了。vultr开通和删除服务器非常方便,新服务器即新ip,大多数vps服务商都没有这样的服务,一般的vps服务商可能会提供免费更换1次ip的服务。

2、刚搭建好的ssr账号,ip能ping通,但是还是用不了

首选排除杀毒软件的干扰,尤其是国产杀毒软件,比如360安全卫生、360杀毒软件、腾讯管家、金山卫生等。这些东西很容易干扰翻墙上网,如果你的电脑安装了这样的东西,建议至少翻墙时别用,最好卸载。其次,检查下SSR信息是否填写正确。浏览器的代理方式是否是ssr代理,即(HTTP)127.0.0.1 和1080。如果以上条件都排除,还是用不了,那么可以更换端口、加密方式、协议、混淆,或者更换服务器位置。另外,如果你的vps服务器配置的是SSR账号,即有协议和混淆且没有兼容原版(SS版),那么你必须使用SSSR客户端来使用账号,因为SS客户端没有填写协议和混淆的选项。

3、有的地区需要把混淆参数设置成plain才好用。因为混淆不总是有效果,要看各地区的策略,有时候不混淆(plain)让其看起来像随机数据更好。

4、电脑能用但手机用不了

如果你的手机用的是SS客户端,SS客户端没有填协议和混淆的地方,如果你部署的协议和混淆的时候没有选择兼容原版(SS版),因此手机是用不了的。这个时候你把协议弄成兼容原版、混淆也设置成兼容原版即可。或者直接将协议设置成origin,混淆设置成plain。

5、vps的服务器操作系统不要用的太高,太高可能会因为系统的防火墙问题导致搭建的SSR账号连不上,如果你用的centos系统,建议用centos6,不要用centos7。如果你前面不小心装了centos7系统,那么只能重装系统或者重新部署新的vps服务器。

6、vultr服务商提供的vps服务器是单向流量计算,有的vps服务商是双向流量计算,单向流量计算对于用户来说更实惠。因为我们是在vps服务器上部署SSR服务端后,再用SSR客户端翻墙,所以SSR服务端就相当于中转,比如我们看一个视频,必然会产生流量,假如消耗流量80M,那么VPS服务器会产生上传80M和下载80M流量,vultr服务商只计算单向的80M流量。如果是双向计算流量,那么会计算为160M流量。

7、如果你想把搭建的账号给多人使用,不用额外设置端口,因为一个账号就可以多人使用。一般10美元的服务器可以同时支持100人在线使用。

如果想实现支持每个用户(端口)不同的加密方式/协议/混淆等,并且管理流量使用,可以参考多用户配置脚本:wget -N –no-check-certificate https://softs.fun/Bash/ssrmu.sh && chmod +x ssrmu.sh && bash ssrmu.sh 备用脚本:wget -N –no-check-certificate https://raw.githubusercontent.com/ToyoDAdoubi/doubi/master/ssrmu.sh && chmod +x ssrmu.sh && bash ssrmu.sh 安装后管理命令为:bash ssrmu.sh

注意:这个多用户配置脚本和教程内容的脚本无法共存!要想用这个脚本,把之前的脚本卸载,输入管理命令bash ssr.sh ,选择3,卸载ShadowsocksR即可卸载原脚本。

8、vultr服务器每月有流量限制,超过限制后服务器不会被停止运行,但是超出的流量会被额外收费。北美和西欧地区的服务器超出流量后,多出的部分收费为0.01美元/G。新加坡和日本东京(日本)为0.025美元/G,悉尼(澳大利亚)为0.05美元/G。把vultr服务器删掉,开通新的服务器,流量会从0开始重新计算。

9、vultr怎样才能申请退款呢?

vultr和其他的国外商家一样,都是使用工单的形式与客服联系,如果需要退款,直接在后台点击support,选择open ticket新开一个工单,选择billing question财务问题,简单的在文本框输入你的退款理由。比如:Please refund all the balance in my account。工单提交以后一般很快就可以给你确认退款,若干个工作日后就会退回你的支付方式。(全额退款结束后,账号可能会被删除)

如果英语水平不好,但是想和客服进行交流,可以用百度在线翻译,自动中文转英文和英文转中文。

10、路由器也可以配置ssr,关键的是路由器刷固件,华硕路由器刷梅林改版固件最简单,下载固件直接刷,梅林改版固件自带软件中心,然后再软件中心点离线安装就可以了(原版梅林不带软件中心 下载)。路由器刷merlin_8wan_firmware(八万)的固件就行KoolShare固件下载 其他的路由器也可以刷梅林。有问题或者对路由器配置ssr感兴趣的,可以在这些网站上自学:koolshare 华硕路由爱好者社区 NAP6

By柏小白

SHTML 教程

什么是 SHTML

使用SSI(Server Side Include)的html文件扩展名,SSI(Server Side Include),通常称为“服务器端嵌入”或者叫“服务器端包含”,是一种类似于ASP的基于服务器的网页制作技术。

SSI工作原理:

将内容发送到浏览器之前,可以使用“服务器端包含 (SSI)”指令将文本、图形或应用程序信息包含到网页中。例如,可以使用 SSI 包含时间/日期戳、版权声明或供客户填写并返回的表单。对于在多个文件中重复出现的文本或图形,使用包含文件是一种简便的方法。将内容存入一个包含文件中即可,而不必将内容输入所有文件。通过一个非常简单的语句即可调用包含文件,此语句指示 Web 服务器将内容插入适当网页。而且,使用包含文件时,对内容的所有更改只需在一个地方就能完成。

因为包含 SSI 指令的文件要求特殊处理,所以必须为所有 SSI 文件赋予 SSI 文件扩展名。默认扩展名是 .stm、.shtm 和 .shtml。

Web 服务器在处理网页的同时处理 SSI 指令。当 Web 服务器遇到 SSI 指令时,直接将包含文件的内容插入 HTML 网页。如果“包含文件”中包含 SSI 指令,则同时插入此文件。除了用于包含文件的基本指令之外,还可以使用 SSI 指令插入文件的相关信息(如文件的大小)或者运行应用程序或 shell 命令。

网站维护常常碰到的一个问题是,网站的结构已经固定,却为了更新一点内容而不得不重做一大批网页。SSI提供了一种简单、有效的方法来解决这一问题,它将一个网站的基本结构放在几个简单的HTML文件中(模板),以后我们要做的只是将文本传到服务器,让程序按照模板自动生成网页,从而使管理大型网站变得容易。

所以,利用SHTML格式的页面目的和 ASP 差不多,但是因为是 API 所以运转速度更快,效率更高,比ASP快,比HTML慢,但由于可以使用服务器端包含,因此使页面更新容易(特别是批量更新banner,版权等),想象一下吧,你有一段 HTML,要在中间穿插一些特殊的服务端脚本,比如插入其他 HTML 段落,你选择 ASP 来完成这个任务,但是如果任务更繁重,需要更多的时间,比如 5 s,这个时候你不用 ASP 而用  SHTML,或许处理时间就只用 4s 了。

SSI有什么用?

之所以要扯到 SSI,是因爲 Shtml – Server-Parsed HTML 的首字母缩略词。包含有嵌入式服务器方包含命令的 HTML 文本。在被传送给浏览器之前,服务器会对 SHTML 文档进行完全地读取、分析以及修改。shtml和asp 有一些相似,以shtml命名的文件里,使用了ssi的一些指令,就像asp中的指令,你可以在SHTML文件中写入SSI指令,当客户端访问这些shtml文件时,服务器端会把这些SHTML文件进行读取和解释,把SHTML文件中包含的SSI指令解释出来比如:你可以在SHTML文件中用SSI指令引用其他的html文件(#include ),服务器传送给客户端的文件,是已经解释的SHTML不会有SSI指令。它实现了HTML所没有的功能,就是可以实现了动态的SHTML,可以说是HTML的一种进化吧。像新浪的新闻系统就是这样的,新闻内容是固定的但它上面的广告和菜单等就是用#include引用进来的。

目前,主要有以下几种用用途:

  1. 显示服务器端环境变量<#echo>
  2. 将文本内容直接插入到文档中<#include>
  3. 显示WEB文档相关信息<#flastmod #fsize> (如文件制作日期/大小等)
  4. 直接执行服务器上的各种程序<#exec>(如CGI或其他可执行程序)
  5. 设置SSI信息显示格式<#config>(如文件制作日期/大小显示方式)

高级SSI<XSSI>可设置变量使用if条件语句。

使用SSI

SSI是为WEB服务器提供的一套命令,这些命令只要直接嵌入到HTML文档的注释内容之中即可。如:

<!–#include file=”info.htm”–>

就是一条SSI指令,其作用是将”info.htm”的内容拷贝到当前的页面中,当访问者来浏览时,会看到其它HTML文档一样显示info.htm其中的内容。其它的SSI指令使用形式基本同刚才的举例差不多,可见SSI使用只是插入一点代码而已,使用形式非常简单。当然,如果WEB服务器不支持SSI,它就会只不过将它当作注释信息,直接跳过其中的内容;浏览器也会忽略这些信息。

如何在我的WEB服务器上配置SSI功能?

在一些WEB服务器上(如IIS 4.0/SAMBAR 4.2),包含 #include 指令的文件必须使用已被映射到 SSI 解释程序的扩展名;否则,Web 服务器将不会处理该SSI指令;默认情况下,扩展名 .stm、.shtm 和 .shtml 被映射到解释程序(Ssinc.dll)。
Apache则是根据你的设置情况而定,修改srm.conf如:

AddType text/x-server-parsed-html .shtml 将只对.shtml扩展名的文件解析SSI指令
AddType text/x-server-parsed-html .html 将对所有HTML文档解析SSI指令

Netscape WEB服务器直接使用 Administration Server(管理服务器)可打开SSI功能。
Website 使用 Server Admin 程序中的 Mapping 标签,扩展名添加内容类型为:wwwserver/html-ssi
Cern 服务器不支持SSI,可用SSI诈骗法,到 http://sw.cse.bris.ac.uk/WebTools/fakessi.html 上下载一个PERL脚本,即可使你的CERN服务器使用一些SSI指令。(不支持exec指令。)

SSI指令基本格式

程序代码:

<!– 指令名称=”指令参数”>

示例:

<!–#include file=”info.htm”–>

说明:

  1. <!– –>是HTML语法中表示注释,当WEB服务器不支持SSI时,会忽略这些信息。
  2. #include 为SSI指令之一。
  3. file 为include的参数, info.htm为参数值,在本指令中指将要包含的文档名。

注意:

  1. <!–与#号间无空格,只有SSI指令与参数间存在空格。
  2. 上面的标点=””,一个也不能少。
  3. SSI指令是大小写敏感的,因此参数必须是小写才会起作用。

SSI指令使用详解

#echo 示范

作用:将环境变量插入到页面中。

语法:

<!–#echo var=”变量名称”–>

示例:

<!–#echo var=”DOCUMENT_NAME”–> 本文档名称
<!–#echo var=”DATE_LOCAL”–> 现在时间
<!–#echo var=”REMOTE_ADDR”–> 你的IP地址

#include 示范

作用:将文本文件的内容直接插入到文档页面中。

语法:

<!–#include file=”文件名称”–>
<!–#include virtual=”文件名称”–>

file 文件名是一个相对路径,该路径相对于使用 #include 指令的文档所在的目录。被包含文件可以在同一级目录或其子目录中,但不能在上一级目录中。如表示当前目录下的的nav_head.htm文档,则为file=”nav_head.htm”。
virtual 文件名是 Web 站点上的虚拟目录的完整路径。如表示相对于服务器文档根目录下hoyi目录下的nav_head.htm文件;则为file=”/hoyi/nav_head.htm”

参数:

file 指定包含文件相对于本文档的位置
virtual 指定相对于服务器文档根目录的位置

注意:

  1. 文件名称必须带有扩展名。
  2. 被包含的文件可以具有任何文件扩展名,我觉得直接使用htm扩展名最方便,微软公司推荐使用 .inc 扩展名(这就看你的爱好了)。

示例:

<!–#include file=”nav_head.htm”–> 将头文件插入到当前页面
<!–#include file=”nav_foot.htm”–> 将尾文件插入到当前页面

#flastmod 和 #fsize 示范

作用:

#flastmod 文件最近更新日期
#fsize 文件的长度

语法:

<!–#flastmod file=”文件名称”–>
<!–#fsize file=”文件名称”–>

参数:

file 指定包含文件相对于本文档的位置 如 info.txt 表示当前目录下的的info.txt文档
virtual 指定相对于服务器文档根目录的位置 如 /hoyi/info.txt 表示

注意:文件名称必须带有扩展名。

示例:

<!–#flastmod file=”news.htm”–> 将当前目录下news.htm文件的最近更新日期插插入到当前页面
<!–#fsize file=”news.htm”–> 将当前目录下news.htm的文件大小入到当前页面

#exec 示范

作用:将某一外部程序的输出插入到页面中。可插入CGI程序或者是常规应用程序的输入,这取决于使用的参数是cmd还是cgi。

语法:

<!–#exec cmd=”文件名称”–>
<!–#exec cgi=”文件名称”–>

参数:

cmd 常规应用程序
cgi CGI脚本程序

示例:

<!–#exec cmd=”cat /etc/passwd”–> 将会显示密码文件
<!–#exec cmd=”dir /b”–> 将会显示当前目录下文件列表
<!–#exec cgi=”/cgi-bin/gb.cgi”–> 将会执行CGI程序gb.cgi。
<!–#exec cgi=”/cgi-bin/access_log.cgi”–> 将会执行CGI程序access_log.cgi。

注意:从上面的示例可以看出,这个指令相当方便,但是也存在安全问题。

禁止方法:

  1. Apache,将access.conf中的”Options Includes ExecCGI”这行代码删除;
  2. 在IIS中,要禁用 #exec 命令,可修改 SSIExecDisable 元数据库;

#config

作用: 指定返回给客户端浏览器的错误信息、日期和文件大小的格式。

语法:

<!–#config errmsg=”自定义错误信息”–>
<!–#config sizefmt=”显示单位”–>
<!–#config timefmt=”显示格式”–>

参数:

errmsg 自定义SSI执行错误信息,可以为任何你喜欢的方式。
sizefmt 文件大小显示方式,默认为字节方式(“bytes”)可以改为千字节方式(“abbrev”)
timefmt 时间显示方式,最灵活的配置属性。

示例:显示一个不存在文件的大小

<!–#config errmsg=”服务器执行错误,请联系管理员 yiho@126.com,谢谢!”–>
<!–#fsize file=”不存在的文件.htm”–>

以千字节方式显示文件大小

语法:

<!–#config sizefmt=”abbrev”–>
<!–#fsizefile=”news.htm”–>

以特定的时间格式显示时间

<!–#config timefmt=”%Y年/%m月%d日 星期%W 北京时间%H:%M:%s,%Y年已过去了%j天 今天是%Y年的第%U个星期”–>
<!–#echo var=”DATE_LOCAL”–> 显示今天是星期几,几月,时区
<!–#config timefmt=”今天%A, %B ,服务器时区是 %z,是”–>
<!–#echo var=”DATE_LOCAL”–>

XSSI

XSSI(Extended SSI)是一组高级SSI指令,内置于Apache 1.2或更高版本的mod-include模块之中。其中可利用的的指令有:

#printenv
#set
#if

#printenv

作用: 显示当前存在于WEB服务器环境中的所有环境变量。

语法:

<!–#printenv–>

#set

作用:可给变量赋值,以用于后面的if语句。

语法:

<!–#set var=”变量名” value=”变量值”–>

示例:

<!–#set var=”color” value=”红色”–>

#if

作用:创建可以改变数据的页面,这些数据根据使用if语句时计算的要求予以显示。

语法:

<!–#if expr=”$变量名=\”变量值A\””–>
显示内容
<!–#elif expr=”$变量名=\”变量值B\””–>
显示内容
<!–#else–>
显示内容
<!–#endif”–>

示例:

<!–#if expr=”$SERVER_NAME=\”www.baidu.com\””–>
欢迎光临 http://www.baidu.com
<!–#elif expr=”$SERVER_NAME=\”www.google.com\”” –>
欢迎光临 http://www.google.com
<!–#else–>
欢迎光临 Afly’s Blog!
<!–#endif”–>

注意:用于前面指令中的反斜杠,是用来代换内部的引号,以便它们不会被解释为结束表达式。不可省略。

1、Config 命令

Config 命令主要用于修改SSI的默认设置。其中:

Errmsg:设置默认错误信息。为了能够正常的返回用户设定的错误信息,在HTML文件中Errmsg参数必须被放置在其它SSI命令的前面,否则客户端只能显示默认的错误信息,而不是由用户设定的自定义信息。

<!–#config errmsg=”Error! Please email webmaster@mydomain.com” –>

Timefmt:定义日期和时间的使用格式。Timefmt参数必须在echo命令之前使用。

<!–#config timefmt=”%A, %B %d, %Y”–>
<!–#echo var=”LAST_MODIFIED” –>

显示结果为:

Wednesday, April 12, 2000

也许用户对上例中所使用的%A %B %d感到很陌生,下面我们就以表格的形式总结一下SSI中较为常用的一些日期和时间格式。

Sizefmt:决定文件大小是以字节、千字节还是兆字节为单位表示。如果以字节为单位,参数值为”bytes”;对于千字节和兆字节可以使用缩写形式。同样,sizefmt参数必须放在fsize命令的前面才能使用。

<!–#config sizefmt=”bytes” –>
<!–#fsize file=”index.html” –>

2、Include 命令

Include 命令可以把其它文档中的文字或图片插入到当前被解析的文档中,这是整个SSI的关键所在。通过Include命令只需要改动一个文件就可以瞬间更新整个站点!

Include 命令具有两个不同的参数:

Virtual:给出到服务器端某个文档的虚拟路径。
File:给出到当前目录的相对路径,其中不能使用”../”,也不能使用绝对路径。

<!–#include virtual=”/includes/header.html” –>
<!–#include file=”header.html” –> 这就要求每一个目录中都包含一个header.html文件。

3、Echo 命令

Echo 命令可以显示以下各环境变量:

DOCUMENT_NAME:显示当前文档的名称。
DOCUMENT_URI:显示当前文档的虚拟路径。例如:

<!–#echo var=”DOCUMENT_NAME” –>
<!–#echo var=”DOCUMENT_URI” –>

随着网站的不断发展,那些越来越长的URL地址肯定会让人头疼。如果使用SSI,一切就会迎刃而解。因为我们可以把网站的域名和SSI命令结合在一起显示完整的URL,即:

http://YourDomain<!–#echo var=”DOCUMENT_URI” –>

QUERY_STRING_UNESCAPED:显示未经转义处理的由客户端发送的查询字串,其中所有的特殊字符前面都有转义符”\”。例如:

<!–#echo var=”QUERY_STRING_UNESCAPED” –>

DATE_LOCAL:显示服务器设定时区的日期和时间。用户可以结合config命令的timefmt参数,定制输出信息。例如:

<!–#config timefmt=”%A, the %d of %B, in the year %Y” –>
<!–#echo var=”DATE_LOCAL” –>

显示结果为:

Saturday, the 15 of April, in the year 2000

DATE_GMT:功能与DATE_LOCAL一样,只不过返回的是以格林尼治标准时间为基准的日期。例如:

<!–#echo var=”DATE_GMT” –>

LAST_MODIFIED:显示当前文档的最后更新时间。同样,这是SSI中非常实用的一个功能,只要在HTML文档中加入以下这行简单的文字,就可以在页面上动态的显示更新时间。

<!–#echo var=”LAST_MODIFIED” –>

CGI环境变量

除了SSI环境变量之外,echo命令还可以显示以下CGI环境变量:

SERVER_SOFTWARE:显示服务器软件的名称和版本。例如:
<!–#echo var=”SERVER_SOFTWARE” –>
SERVER_NAME: 显示服务器的主机名称,DNS别名或IP地址。例如:
<!–#echo var=”SERVER_NAME” –>
SERVER_PROTOCOL:显示客户端请求所使用的协议名称和版本,如HTTP/1.0。例如:
<!–#echo var=”SERVER_PROTOCOL” –>
SERVER_PORT:显示服务器的响应端口。例如:
<!–#echo var=”SERVER_PORT” –>
REQUEST_METHOD:显示客户端的文档请求方法,包括GET, HEAD, 和POST。例如:
<!–#echo var=”REQUEST_METHOD” –>
REMOTE_HOST:显示发出请求信息的客户端主机名称。
<!–#echo var=”REMOTE_HOST” –>
REMOTE_ADDR:显示发出请求信息的客户端IP地址。
<!–#echo var=”REMOTE_ADDR” –>
AUTH_TYPE:显示用户身份的验证方法。
<!–#echo var=”AUTH_TYPE” –>
REMOTE_USER:显示访问受保护页面的用户所使用的帐号名称。
<!–#echo var=”REMOTE_USER” –>

4、Fsize:显示指定文件的大小,可以结合config命令的sizefmt参数定制输出格式。

<!–#fsize file=”index_working.html” –>

5、Flastmod:显示指定文件的最后修改日期,可以结合config 命令的timefmt参数控制输出格式。

<!–#config timefmt=”%A, the %d of %B, in the year %Y” –>
<!–#flastmod file=”file.html” –>

这里,我们可以利用flastmod参数显示出一个页面上所有链接页面的更新日期。方法如下:

<!–#config timefmt=” %B %d, %Y” –>
<A HREF=”/directory/file.html”>File</A>
<!–#flastmod virtual=”/directory/file.html” –>
<A HREF=”/another_directory/another_file.html”>Another File</A>
<!–#flastmod virtual=”/another_directory/another_file.html” –>

显示结果为:

File April 19, 2000
Another File January 08, 2000

6、Exec

Exec命令可以执行CGI脚本或者shell命令。使用方法如下:

Cmd:使用/bin/sh执行指定的字串。如果SSI使用了IncludesNOEXEC选项,则该命令将被屏蔽。
Cgi:可以用来执行CGI脚本。例如,下面这个例子中使用服务端cgi-bin目录下的counter.pl脚本程序在每个页面放置一个计数器:

<!–#exec cgi=”/cgi-bin/counter.pl” –>

关于SHTML和HTML的区别

让我们先来看看SHTML和HTML的区别,如果用一句话来解释就是:SHTML 不是HTML而是一种服务器 API,shtml是服务器动态产成的html.

虽然两者都是超文本格式,但shtml是一种用于SSI技术的文件。也就是Server Side Include–SSI 服务器端包含指令。如果Web Server有SSI功能的话,大多数(尤其是基于Unix平台)的WEB服务器,如Netscape Enterprise Server等均支持SSI命令。

By柏小白

WebStorm设置shtml测试服务器-局域网内其他设备访问

一、WebStorm配置版本:
63001655-7A67-4e20-B5D3-85D86B9AA309
步骤:
1. “File” -> “Settings…”, 打开设置界面
2. 选中”Debugger”【调试程序】, Port输入”9090″, “Allow unsigned requests”选中, 打钩
2
3. 选中”Deployment”, 点击”+”, Name置为”Localhost”, Type选择为”Local or mounted folder”
3
4. 设置”Connection”, 设置Folder, 我自己的项目文件是在”E:\Work_V1_B\branch\dggschoo\04_Coding\WebSites\Dgg.Web.Static”下,  Web server root URL设置为”http://172.16.3.135:9090″, IP是自己电脑的
4
注:
Web server root URL: http://172.16.3.135:9090, 点击界面里的浏览器, 自动打开的地址如下:
http://172.16.3.135:9090/index.html
上面的地址是打不开的, 因为我是放在Dgg.Web.Static文件下的,
所以应修改成 Web server root URL: http://172.16.3.135:9090/Dgg.Web.Static
OK 能正常访问了
5
5. “Mappings”下保持不变, 点击”OK”, 即可
7

6. OK,设置完成,现在用webstorm直接页面预览,可以看到页面地址

已经由原先的:http://localhost:63342/****.html
更改为现在的:http://172.16.3.135:9090/****.html
直接复制这个路径给你的小伙伴吧,只要他们的设备和你的电脑保持在同局域网,即可打开预览了.

二、在nginx下配置:

nginx服务器,如何支持ssi包含文件。

主要是三个参数,ssi,ssi_silent_errors和ssi_types,均可以放在http,server和location的作用域下。

ssi on
开启ssi支持,默认是off

ssi_silent_errors on
默认值是off,开启后在处理SSI文件出错时不输出错误提示:”[an error occurred while processing the directive] ”

ssi_types
默认是ssi_types text/html,所以如果需要htm和html支持,则不需要设置这句,如果需要shtml支持,则需要设置:ssi_types text/shtml

SSI的格式:
<!–#include file=”bottom.htm”–>

<!–#include virtual=”/hx/bottom.htm”–>
路径是相对server中root根目录。

更多请参见官方文档:http://wiki.nginx.org/NginxChsHttpSsiModule

示例:

 

server {
    listen       1212;
    server_name  172.16.3.135;

    ssi on;
    ssi_silent_errors on;
    ssi_types text/shtml;

    root   "E:/Work_V1_B/branch/dggschoo/04_Coding/WebSites/Dgg.Web.Static/";

    location / {
        index  index.html index.htm index.shtml;
    }
}
By柏小白

IDEA编译less插件LESS CSS Compiler的安装

1.IDEA插件地址:LESS CSS Compiler  百度云盘链接:http://pan.baidu.com/s/1kVLvL6R 密码:mfsx

2.安装Node.js,下载

3.打开idea→settings→plugins 安装:“nodejs”插件,并按以下步骤进行配置:

4.打开idea→settings→Languages & Frameworks→Node.js and NPM;

在打开的面板中点击右侧“+”加号按钮添加需要的“less”组件

(如果此处不能添加,请使用npm命令进行全局安装;在“cmd”命令行 输入“npm install -g less”,安装less)

5.打开idea→settings→plugins ; 安装:file watchers插件,并按以下步骤进行设置

6.打开idea→settings→tools→file watchers; 在打开的面板中点击右侧加号按钮添加less配置,貌似插件自动就配置好了

7.安装LESS CSS Compiler插件 idea→Plugins→Install plugin from disk 选择第一步下载的插件文件,安装完成后无需进行任何配置

By柏小白

nvm安装和配置详细备忘录

一.win下安装

新电脑新配置,以前配置不小心忘记了,今天做一个备忘总结:

nvm是nodejs的版本管理工具,为什么要用nvm,nodejs官方更新的速度非常快,有时候业务需要需要用某某版本,如果用的是msi安装,虽然安装的时候挺简单,但是后面模块就麻烦了.

我用的win64系统,先安装nvm,接着nodejs,最后npm

nvm百度网盘下载地址:链接:http://pan.baidu.com/s/1bDWuBW 密码:vmpm

C盘建立 【Develop】 文件 下载解压 nvm_x64文件在当前
1

确保目录下有一个setting.txt文件(图片是我配置好后的截图,默认没有那些内容)

2

root: C:\Develop\nvm // nvm 文件地址路径
path: C:\Develop\nodejs // nodejs 文件地址 先填写上和nvm 文件路径一致,我们马上运行命令会生成这个文件夹
arch: 64 // 系统版本号 我这是win7_x64 位系统
proxy: // 可不填 有的大概是 none

cmd 命令行输入nvm回车看到nvm的版本号表示nvm安装成功

我报如下错误:nvm报错 ERROR open \settings.txt: The system cannot find the file specified

没关系,报错就好办了,这边是 环境变量没有配置 如下:

二:环境变量配置:点击我的电脑》属性》高级设置》环境变量》
1.删除系统自带的nvm变量:NVM_HOME和NVM_SYMLINK
2.打开path:删除nvm自动添加的变量C:\Develop\nvm;C:\Develop\nodejs
3.配置用户变量:
NVM_HOME = C:\Develop\nvm
NVM_SYMLINK = C:\Develop\nodejs
Path = %NVM_HOME%;%NVM_SYMLINK%
配置完成保存

注:上面添加环境变量没有用,我直接添加:Path = C:\Develop\nvm;C:\Develop\nodejs 就在环境变量中
下载需要的nodejs版本,解压后改名(如v8.2.1)放到nvm目录,注意里面如果有嵌套文件夹就把文件拿到外层

cmd 打开 输入nvm 出现以下就为正常:

3

nvm ls 查看当前版本带星号8.2.1 为正在使用版本:

4

nvm use 5.7.0  切换到指定版本:

5

nodejs快捷键中查看属性,查看 ‘目标’文件路径是不是改变

7

接下来打开命令窗口安装一个包测试一下,npm install -g gulp,安装完成后会看到npm 》node_modules目录下有新下载的包,由于npm和nodejs是分离的,无论你切换到任何版本,都不需要重新安装这些包了

 

一.linux下安装

github官网 https://github.com/creationix/nvm

 curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.2/install.sh | bash
  wget -qO- https://raw.githubusercontent.com/creationix/nvm/v0.33.2/install.sh | bash

next:
vim ~/.bashrc 写入下面代码

export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" # This loads nvm

下一步即可安装node
如 v6.11.0版本

nvm i 8.2.1

具体安装sh脚本:

 

#/bin/bash
# -*- codeing: utf-8 -*-
   cd ~
   mkdir .nvm
   cd .nvm
   curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash
   source ~/.bashrc
   nvm install v8.2.1
   node -v
   nvm --version
   nvm ls

 

 

以上用到以下命令:

     nvm uninstall 6.11.0     // 移除 node 6.11.0
     nvm use 6.11.0           // 使用 node 6.11.0
     nvm ls                   // 查看目前已安装的 node 及当前所使用的 node
     nvm ls-remote            // 查看目前线上所能安装的所有 node 版本
     nvm alias default 6.11.0 // 使用 6.11.0 作为预设使用的 node 版本

nvm 查看是否安装成功
nvm ls 查看当前版本带星标 为正当前运行版本
nvm use 5.7.0 切换到指定版本
node -v 查看当前nodejs版本
gulp -v 查看当前gulp版本
webpack -v 查看当前webpack版本

By柏小白

B.js工具库

B.JS

柏小白 javascript store

整理笔记、知识,并将其中承载的价值传播给他人 —— 记录思想和分享知识

  • 整理知识,学习笔记
  • 发布日记,杂文,所见所想

BJS


什么是 B.JS

B.JS 工具库,包括对象扩展、通用方法、队列、JSON、Cookie、Storage、Array、Ajax、JSONP等

1. B.seed.js

  •  __BUILD_TIME 时间
  •  VERSION 版本
  •  Env
  •  Config 配置
  •  is 类型判断
  •  isBoolean 布尔类型判断
  •  isDate 日期类型判断
  •  isRegExp 是否是正则表达式判断
  •  isObject 对象类型判断
  •  isArray 数组类型判断
  •  isNumber 数字类型判断
  •  isFunction 函数类型判断
  •  isNull null类型判断
  •  isString 字符串类型判断
  •  isEmpty 对象是否为空判断
  •  isUndefined undefined 类型判断
  •  log 打印
  •  getLogger
  •  _mix
/**
 * @class B
 * @author 柏小白
 * @date 2015/12/12
 */
(function (){
    var self = this,
        B,
        EMPTY = '',
        loggerLevel = {
            debug: 10,
            info: 20,
            warn: 30,
            error: 40
        };

    function getLogger(logger){
        var obj = {};
        for (var cat in loggerLevel) {
            if(!loggerLevel.hasOwnProperty(cat))
                continue;
            (function (obj, cat){
                obj[cat] = function (msg){
                    return B.log(msg, cat, logger);
                };
            })(obj, cat);
        }
        return obj;
    }

    B = {
        __BUILD_TIME: '2016-11-03',
        VERSION: '0.01',
        Env: {
            host: self
        },
        Config: {
            debug: true,
            loggerLevel: 'debug',
            fns: {}
        },
        /**
         * 类型判断
         * @param obj
         * @param type
         * @return boolean
         */
        is: function (obj, type){
            var isNan = {"NaN": 1, "Infinity": 1, "-Infinity": 1};
            type = type.toLowerCase();
            if(type == "finite"){
                return !isNan["hasOwnProperty"](+obj);
            }
            if(type == "array"){
                return obj instanceof Array;
            }
            if(undefined === obj && type !== "undefined") return false;
            return (type == "null" && obj === null) ||
                (type == typeof obj && obj !== null) ||
                (type == "object" && obj === Object(obj)) ||
                (type == "array" && Array.isArray && Array.isArray(obj)) ||
                Object.prototype.toString.call(obj).slice(8, -1).toLowerCase() == type;
        },
        /**
         * 布尔类型判断
         * @param obj
         * @returns {boolean|*|Boolean}
         */
        isBoolean: function (obj){
            return B.is(obj, "boolean");
        },
        /**
         * 日期类型判断
         * @param obj
         * @returns {boolean|*|Boolean}
         */
        isDate: function (obj){
            return B.is(obj, "date");
        },
        /**
         * 是否是正则表达式判断
         * @param obj
         * @returns {*|boolean}
         */
        isRegExp: function (obj){
            return B.is(obj, "regexp");
        },
        /**
         * 对象类型判断
         * @param obj
         * @returns {*|boolean}
         */
        isObject: function (obj){
            return B.is(obj, "object");
        },
        /**
         * 数组类型判断
         * @param obj
         * @returns {*|boolean}
         */
        isArray: function (obj){
            return B.is(obj, "array");
        },
        /**
         * 数字类型判断
         * @param obj
         * @returns {*|boolean}
         */
        isNumber: function (obj){
            return B.is(obj, "number");
        },
        /**
         * fun 类型判断
         * @param obj
         * @returns {*|boolean}
         */
        isFunction: function (obj){
            return B.is(obj, "function");
        },
        /**
         * null类型判断
         * @param obj
         * @returns {*|boolean}
         */
        isNull: function (obj){
            return B.is(obj, "null");
        },
        /**
         * 字符串类型判断
         * @param obj
         * @returns {*|boolean}
         */
        isString: function (obj){
            return B.is(obj, "string");
        },
        /**
         * 对象是否为空判断
         * @param obj
         * @returns {boolean|*}
         */
        isEmpty: function (obj){
            return EMPTY === obj || B.isNull(obj);
        },
        /**
         * undefined 类型判断
         * @param obj
         * @returns {*|boolean}
         */
        isUndefined: function (obj){
            return B.is(obj, "undefined");
        },
        /**
         * 打印console.log();
         * @param msg
         * @param cat
         * @param logger
         * @returns {*}
         */
        log: function (msg, cat, logger){
            if(!B.Config.debug) return undefined;
            if((loggerLevel[B.Config.loggerLevel] || 1000) > loggerLevel[cat == 'log' ? 'debug' : cat])
                return "min level";
            var matched = false;
            if(logger){
                matched = B.isObject(msg);
                if(!matched)
                    msg = logger + ": " + msg;
            }
            if(typeof console !== 'undefined' && console.log){
                if(matched) console[cat && console[cat] ? cat : 'log'](logger + ":");
                console[cat && console[cat] ? cat : 'log'](msg);
                return msg;
            }
        },
        getLogger: function (logger){
            return getLogger(logger);
        },
        _mix: function (target, resource){
            for (var name in resource) {
                if(resource.hasOwnProperty(name)){
                    target[name] = resource[name];
                }
            }
        }
    };
    B.Logger = {};
    B.Logger.Level = {
        DEBUG: 'debug',
        INFO: 'info',
        WARN: 'warn',
        ERROR: 'error'
    };
    'B' in self || ( self['B'] = B);

}).call(this);

 

再一次感谢您花费时间阅读 祝您在这里阅读、分享愉快!

作者 @柏小白
2017 年 07月 20日

By柏小白

快速激活webstorm JetBrains系列产品

随着 JetBrains 新版本的发布,注册机已然不行了。

 

注册时选择 License server,填 http://idea.xn--w0sz4as21fs7k.com/,然后点击 OK,就搞定了。如有异常联系我

License server分享:

http://www.qidianban.site:1203/

http://idea.enjoysala.top/

http://idea.lianghongbo.com/license
http://idea.qinxi1992.cn
http://idea.lanyus.com/

 

 

使用网上传统的那种输入网址的方式激活不了,使用http://idea.lanyus.com/这个网站提供的工具进行,有效期已经更新了

1、进入hosts文件中:C:\Windows\System32\drivers\etc\hosts

2、将“0.0.0.0 account.jetbrains.com”添加到hosts文件中

注意:添加只有重新打开hosts文件进行确认之后在进行下一步操作。

修改成功后如图所示:

注:将这条数据加入之后会提示保存,然后确认之后,重新打开hosts文件确认是否添加成功,有时候会提示确认两次。

另可以直接将hosts文件复制到桌面,然后就可以直接进行编辑,保存操作,编辑之后再复制到原地址中,然后在cmd命令窗口执行: ipconfig /flush dns即可。

3、进入http://idea.lanyus.com/站点,点击获得注册码,然后将注册码复制,粘贴到IDEA中

 

注:爱前端 || 爱老婆

 

By柏小白

js面向对象学习

对象

JavaScript本身是一门面向对象的语言,JavaScript所有变量都可以当作对象使用(这里是说可以当对象使用,并不是说均是对象,应该理解为可以通过点操作符来调用一些属性方法),除了两个例外 null 和 undefined。

beauty.jpg

对象使用和属性

看到这个描述的时候,我果断尝试了一下 number 类型的数字字面值( literals ),敲下回车的一瞬间笑了,这话写错了啊。查阅了JavaScript 秘密花园的内容才知道问题所在,原来是JavaScript解析器把点操作符解析为了浮点字面量。可以通过一些方法让数字字面值看起来像对象,终究而言还是不能被称为对象。

1
2
3
4
5
6
1.toString(); // Uncaught SyntaxError: Invalid or unexpected token
// 数字字面量
1..toString(); // “1”
1 .toString(); // “1”
(1).toString(); // “1”

再尝试一些其他的类型作为对象的使用

1
2
3
4
5
6
7
8
9
10
11
12
// Boolean
false.toString(); // “false”
// Array
[1, 2, 3].toString(); // 1, 2, 3
// String
“string”.match(‘s’); // [“s”]
// Function
function D() {}
D.toString(); // “function D() {}”

原型

JavaScript没有类继承模型,而是使用 prototype 原型模型。虽然在ES6中增加了 class 关键字,但只是语法糖,仍旧是基于原型。
JavaScript对象有一个指向一个原型对象的链。当试图访问一个对象上的属性时,会先搜寻该对象的属性,再搜寻该对象的原型以及原型的原型,依次网上搜索,直到找到一个名字匹配的属性或者达到原型链的末尾。

  • 原型的使用方式一
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    var F = function(x) {
    this.x = x || 1;
    }
    F.prototype = {
    add: function(y) {
    return this.x + y;
    }
    }
    var f = new F();
    f.add(2); // 3
    var f1 = new F(2);
    f1.add(4); // 6

定义了函数F模拟类,其函数表达式相当于构造函数 constructor 。函数也是对象,通过给F对象的 prototype 属性赋值对象字面量来设定F的原型。通过关键字new来实例化函数F,返回实例化对象, x 为f对象的属性, add 为f对象的方法。

  • 原型的使用方式二
    赋值原型的时候立即执行函数表达式
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    var F = function() {};
    F.prototype = function() {
    var add = function(x, y) {
    return x+y;
    };
    var test = function() {
    console.log(‘private’);
    };
    return {
    add: add
    }
    }()
    var f = new F();
    f.add(3, 3); // 6
    f.test(); // f.test is not a function

给F函数的 prototype 属性赋值了一个立即执行函数表达式,函数表达式返回需要暴露的方法的一个对象,这种方式可以实现方法public/private。

原型链

JavaScript使用原型链的继承方式,如下面的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
function Foo() {
this.name = ‘unofficial’;
}
Foo.prototype.who = function() {
return this.name;
}
function Bar() {}
// 设置Bar的prototype属性值为Foo的实例化对象
Bar.prototype = new Foo();
Bar.prototype.foo = ‘Hello world!’;
// 修正Bar.prototype.constructor为Bar本身 ?
Bar.prototype.constructor = Bar;
var b = new Bar();
/*
* 原型链为
b [Bar的实例]
bar.prototype [Foo的实例]
{ foo: ‘Hello world’, name: ‘unofficial’ }
Foo.prototype
{method: …}
Object.prototype
{toString: …}
*/

实例b对象从Bar.prototype和Foo.prototype继承下来,因为b能访问自身原型属性foo,以及Foo原型方法who,也能访问Foo上的原型属性name。需要注意的是new Bar()不会重新创造出一个Foo实例,而是重复使用原型上的实例。

如果直接 Bar.prototype = Foo.prototype; 将会导致两个对象共享相同的原型。改变一个对象的原型将会影响到另外一个对象的原型。

属性查找

在查找一个属性的时候,JavaScript会向上遍历原型链,直到找到给定名称位置或者到达原型链的顶部Object.prototype,如果仍然没找到即返回undefined。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var Foo = function() {
this.add = function(x, y) {
return x + y;
}
}
Foo.prototype.add = function(x, y) {
return x + y;
}
Foo.prototype.test = function() {
console.log(‘来源于prototype的test方法’);
}
var f = new Foo();
console.log(f.add(1, 3)); // 4
f.test(); // 来源于prototype的test方法

调用f.add方法的后首先会在Foo中找add方法,找到了直接就调用add方法。test方法在实例中没有找到,就在原型链上找,能找到直接就执行,如果找不到会继续Object的原型上找,找不到才返回undefined

原型属性

当原型属性创建原型链的时候,任何类型都可以为它赋值,然而将原子类型的值赋值给它是被忽略。

1
2
3
4
5
6
// 用代码解释上面的话
function Foo() {}
// 可以赋值任何类型,比如说
Foo.prototype = 1; // 但是直接赋值类型值只是会被忽略,不会报错,相应的如果后面继续给原型赋值也会被忽略。原型直接是赋值为Object.prototype
console.log(new Foo()); // function Foo() {}

如果直接赋值对象就会像上面的应用一样,创建原型链。通过这种方法可以创建私有方法与公共方法。

性能

由于上文提到的属性查找会从当前对象一直沿着原型链查找,如果找寻一个不存在的问题是需要遍历整个原型链。
for in 循环遍历对象的属性时,原型链上的所有属性也都会被遍历。

扩展内置类型

虽然目前涉及到的应用环境不够复杂,对于复杂引用更多的类或者框架对于相应模块的封装的时候就需要用到原型来实现继承等等,但是不建议扩展内置类型的原型对象,这样会存在性能问题。

isPrototypeOf vs hasOwnProperty

  • isPrototypeOf() 方法测试一个对象是否存在于另一个对象的原型链上。
    prototype.isPrototypeOf(object) 检查prototype对象是否存在object的原型链上
1
2
3
4
5
6
7
8
9
var Foo = function() {};
var Bar = function() {};
Bar.prototype = new Foo();
var b = new Bar();
Foo.prototype.isPrototypeOf(new Foo()); // true
// 在b的原型链上查找对象Foo.prototype
Foo.prototype.isPrototypeOf(b); // true
  • isPrototypeOf vs instanceof
    instanceof运算符可以用来判断某个构造函数的prototype属性所指向的對象是否存在于另外一个要检测对象的原型链上。
    object instanceof constructor
    检查构造函数constructor的原型属性是不是存在object对象的原型链上

    Code one:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    var Foo = function() {};
    var Bar = function() {};
    var f = new Foo();
    var b = new Bar();
    f instanceof Foo; // true
    Foo.prototype.isPrototypeOf(f); // true
    f instanceof Bar; // false
    Bar.prototype = new Foo();
    var b1 = new Bar();
    b1 instanceof Foo; // true
    Foo.prototype.isPrototypeOf(b1); // true

    Code two:

    1
    2
    3
    4
    var human = {mortal: true};
    var socrates = Object.create(human);
    human.isPrototypeOf(socrates); //=> true
    socrates instanceof human; //=> ERROR!

    综上所述:在存在构造函数的时候,instanceof 与 isPrototypeOf 是没有区别的,在没有构造函数的时候只能使用isPrototypeOf

  • hasOwnProperty
    hasOwnProperty用于判断一个对象上是否包含自定义属性,而不是原型链上的属性。hasOwnProperty继承自Object.prototype。

    注意不能通过判断值为undefined来判断属性是否存在,因为该属性的值可能就是undefined

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var Foo = function() {
this.name = ‘unofficial’;
}
Foo.prototype = function() {
return {
getName: function() {
return this.name;
},
age: undefined
};
}()
Foo.prototype.color;
var f = new Foo();
f.color; // undefined
f.hasOwnProperty(‘color’); // false
f.hasOwnProperty(‘age’); // false
f.hasOwnProperty(‘name’); // true

可以在循环遍历的时候用来判断属性是不是是当前对象的属性,而不是继承自原型链

hasOwnProperty可以在当前对象中重写,如果如下例子:

1
2
3
4
5
6
7
8
9
10
11
12
var Foo = function() {
this.hasOwnProperty = function() {
return false;
}
this.name = ‘unofficial’;
}
var f = new Foo();
f.hasOwnProperty(‘name’); // false
// 通过其他对象继承的Object.prototype的hasOwnProperty方法
({}).hasOwnProperty.call(f, ‘name’); //true

ES6中方法如何实现类呢?

以下内容均是在chrome最新版本中测试

ES6中添加了关键字 class ,表面上是的写法和其他语言的类是一样的写法,实际上只是实现了prototype的语法糖。

1
2
3
4
5
6
7
8
9
10
11
‘use strict’;
class Foo {
constructor() {
this.name = ‘unofficial’;
}
getName() {
return this.name;
}
}
let f = new Foo();
console.log(f.getName());

当我们使用 console.log(‘%O’, f) ;时,返回的Foo对象和之前ES5通过function模拟的类实例的对象是一致的。
ES6

  • use strict
    必须在严格模式下执行
  • constructor
    例子中已经使用了 constructor ,实例化Foo类的时候自动执行构造方法。构造方法必须唯一
  • 原型方法
    关键字 get , set 的使用。
1
2
3
4
5
6
7
8
9
10
11
12
class Foo {
set username(value) {
this.name = value;
}
get username() {
return ‘my name is ‘ + this.name;
}
}
let f = new Foo();
f.username = ‘unofficial’;
console.log(f.username);
  • 静态方法
    静态方法指不需要对类进行实例化就可以使用类名直接访问类里面的方法, static 关键字用来定义类的静态方法。
1
2
3
4
5
6
class Foo {
static info() {
console.log(‘随意写的内容’);
}
}
Foo.info(); // 随意写的内容
  • 继承
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(this.name + ‘ 发了个声’);
}
}
class Dog extends Animal {
speak() {
console.log(this.name + ‘说自己饿了’);
}
}
let cat = new Animal(‘kitty’);
cat.speak(); // Kitty 发了个声
new Dog(‘哮天犬’).speak(); // 哮天犬说自己饿了

dog 类继承了 Animal 类,重写了父类的 speak 方法。

  • super 调用父类方法
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    ‘use strict’;
    class Animal {
    constructor(obj) {
    var {name, food} = obj;
    this.name = name;
    this.food = food;
    }
    speak() {
    console.log(this.name + ‘ 发了个声’);
    }
    eat() {
    console.log(this.name + ‘喜欢’ + this.food);
    }
    }
    class Dog extends Animal {
    speak() {
    console.log(this.name + ‘说自己饿了’);
    }
    eat() {
    super.eat();
    if(this.food == ‘耗子’) {
    console.log(‘又闲的蛋疼了吧’);
    }
    }
    }
    new Dog({name: ‘哮天犬’, food: ‘耗子’}).eat(); // 哮天犬喜欢耗子 又闲的蛋疼了吧
  • isPrototypeOf 的使用
    就上面的例子使用 isPrototypeOf

    1
    2
    let dog = new Dog({name: ‘哮天犬’, food: ‘耗子’});
    console.log(Animal.prototype.isPrototypeOf(dog));
  • hasOwnProperty 的使用
    1
    2
    console.log(dog.hasOwnProperty(‘name’)); // true
    console.log(dog.hasOwnProperty(‘speak’)); // false

prototy.js是怎么做的?

参考github上prototype.js的文档以及class.js可以学习到,如何创建一个类?

1
2
3
4
5
var Humen = Class.create();
// or
var Humen = Class.create({
// 这里可以自定义类方法
});

理解class.js时,Class是一个 立即执行的函数表达式 ,不成名的规定就是函数名大写作为类名。

1
2
3
4
5
6
7
8
9
var Class = (function() {
// 返回Class的方法
return {
create: create,
Methods: {
addMethods: addMethods
}
};
})();

这一个需要学习的点,闭包的立即执行的匿名函数中返回一个对象,对象中包含一个create的方法,以及Methods方法对象。

  • 创建类
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    function create() {
    // 可能会有两个参数
    // 第一个参数是父类,需要被继承的类 var gay = Class.create(‘Humen’);
    // 第二个参数是当前类的方法
    /*
    * 判断传入的参数
    * 1. $A方法处理arguments类数组对象为数组,这里使用了[].slice.call(arguments)来代替数组浅复制
    * 2. 判断第一个参数是不是类,如果是赋值给parent
    */
    var parent = null, properties = $A(arguments);
    if (Object.isFunction(properties[0]))
    parent = properties.shift();
    // 自定义Klass类,create函数最后返回的也是创建的Klass类
    /*
    * Klass为 Class.create 创建的类
    * initialize 为自定义构造方法
    * this.initialize 中的this指当前对象
    * apply(this, arguments) 参数this指实例化对象
    * new 实例化对象的时候,Klass函数会自动执行,其中的this.initialize.apply(this, arguments);也就执行了,即属性初始化了
    */
    function Klass() {
    this.initialize.apply(this, arguments);
    }
    // 当前类添加属性 superclass 存放父类;subclass 存放子类
    // 如果父类存在,父类的原型赋值给子类的原型,并初始化子类赋值给当前原型,添加当前类到父类的子类中
    // 将传入的当前类的方法添加到当前类的原型上
    /*
    * 继承addMethods方法
    * 设置父类 superclass
    * 设置子类 subclass
    */
    Object.extend(Klass, Class.Methods);
    Klass.superclass = parent;
    Klass.subclasses = [];
    /*
    * 如果父类存在
    * Subclass是一个类,父类的原型赋值给这个子类的原型
    * 实例化子类赋值给当前类的原型
    * 添加当前类到父类的子类数组中
    */
    if (parent) {
    Subclass.prototype = parent.prototype;
    Klass.prototype = new Subclass;
    parent.subclasses.push(Klass);
    }
    /*
    * 循环添加方法给当前类
    */
    for (var i = 0, length = properties.length; i < length; i++)
    Klass.addMethods(properties[i]);
    // 如果当前类方法中没有initialize方法,使用默认的空函数作为构造方法
    if (!Klass.prototype.initialize)
    Klass.prototype.initialize = function() { };
    // 重置当前类的constructor函数为自身
    Klass.prototype.constructor = Klass;
    // 返回构造的类Klass
    return Klass;
    }
  • 自定义方法,添加传入的参数方法作为当前类的方法
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    function addMethods(source) {
    // 判断父类是不是存在
    // 获取参数的键名
    var ancestor = this.superclass && this.superclass.prototype,
    properties = Object.keys(source);
    // 循环数组
    for (var i = 0, length = properties.length; i < length; i++) {
    var property = properties[i], value = source[property];
    // 这里主要是对于继承父类方法的调用的处理
    // 如果父类存在,并且是方法,方法的第一个参数必须是$super,如果是重写value
    if (ancestor && Object.isFunction(value) && value.argumentNames()[0] == “$super”) {
    var method = value;
    // 处理当前方法
    // wrap()
    value = (function(m) {
    return function() { return ancestor[m].apply(this, arguments); };
    })(property).wrap(method);
    // 新增valueOf
    value.valueOf = (function(method) {
    return function() { return method.valueOf.call(method); };
    })(method);
    // 新增toString
    value.toString = (function(method) {
    return function() { return method.toString.call(method); };
    })(method);
    }
    // 直接赋值给当前类的原型
    this.prototype[property] = value;
    }
    }

到这里基本上就学习完了prototype.js创建类的方法,但是如果需要融会贯通自己来实现一次,我想过程肯定还是会比较艰辛,继续加油。

面向对象是什么?

面向对象编程最美的调侃就是,“我还是单身,我是不是不适合面向对象编程”。也许是的,但是如果你能在脑海中抽象出类,需要的时候撸一发,对象迟早会有的。
OOP
面向对象是一种编程的范式方法,面向对象中的对象是类的实例,类是属性,方法的集合,对于一类对象可能有公共的行为与样式, 封装 在一起就形成了类。如果具体到这个类的一个子类型(狗与阿拉斯加雪橇犬),阿拉斯加肯定是狗,,既有狗的特性,但是同时他又有自己的特点,于是乎 继承 了狗类的一些行为。这是如果在拿来一直猫,猫和狗又都属于动物类,这事又可以抽象出一个动物类,他们都会叫,狗是汪汪汪,猫是喵喵喵,这个是叫的多种表现形式,被称为 多态

面向对象提高了程序的重用性,对于模块化开发以及重构等都带来很多好处。

实践 – 坦克大战游戏

坦克大战在玩小霸王卡版的时候经常约上邻居家的伙伴一起,其实最多的玩的还是雪人兄弟,这个是记忆比较深刻的。不扯远了,今天主要来实现一个简单的坦克大战游戏。
截止目前,还是没能还好的实现坦克大战,保留这个版本,再继续学习学习。

参考资料

JavaScript 秘密花园
强大的原型和原型链
JavaScript isPrototypeOf vs instanceof usage
Classes in ECMAScript 6 (final semantics)
prototype.js
面向对象程序设计

By柏小白

js开发过程中的小函数……陆续更新

1 获取指定范围内的随机数

当我们需要获取指定范围(min,max)内的整数的时候,下面的代码非常适合。

    function getRadomNum(min, max){
        return Math.floor(Math.random() * (max - min + 1)) + min;
    }

 

测试
2016-03-26-2

2 随机获取数组中的元素

    function getRadomFromArr(arr){
        return arr[Math.floor(Math.random() * arr.length)];
    }

 

测试
2016-03-26-3

3 生成从0到指定值的数字数组

  var arr = [], length = 100, i = 1;
    for (; arr.push(i++) < length;) {
    }
    console.log(arr)

 

测试

3

4 打乱数字数组的顺序

   var arr = [1, 2, 3, 4, 5, 6, 7, 'a', 'dsfs', 8, 9, 'v'];
    arr.sort(function (){
        return Math.random() - 0.5
    });

 

测试
4

5 对象转换为数组

//注意对象必须是以下格式的才可以通过此方式转化为数组
//获取的DOM集合,以及函数的arguments也可以通过此方式转化为数组
    /**
     * 对象转换为数组
     * @type {{0: string, 1: string, 2: string, 3: string, length: number}}
     */
    var obj = {
        0: 'qian',
        1: 'long',
        2: 'chu',
        3: 'tian',
        length: 4
    }
    var _slice = [].slice;
    var objArr = _slice.call(obj);

 

测试
5

6 验证是否为数组

   function isArray(obj){
        return Object.prototype.toString.call(obj) === '[object Array]';
    }

测试

6

7 获取数组中最大或者最小值

    function maxAndMin(arr){
        return {
            max: Math.max.apply(null, arr.join(',').split(',')),
            min: Math.min.apply(null, arr.join(',').split(','))
        }
    }
//该方法适合一维或者多维数组求最大最小值的情况

测试
7

8 清空数组

//方式一 通过将长度设置为0
    var arr = [1, 2, 3, 4, 5];
    arr.length = 0;
//方式二 通过splice方法
    var arr = [1, 2, 3, 4, 5];
    arr.splice(0, arr.length);
//方式三 通过将空数组 [] 赋值给数组(严格意义来说这只是将ary重新赋值为空数组,之前的数组如果没有引用在指向它将等待垃圾回收。)
    var arr = [1, 2, 3, 4, 5];
    arr = [];

 

9 保留指定小数位

   var num =4.345678;
    num = num.toFixed(4);  // 4.3457 第四位小数位以四舍五入计算

 

10 不要直接使用delete来删除数组中的元素

    * 数组在js中也是对象,有时候我们可能会通过delete来删除数组中的元素,但是其实仅仅是将数组的元素的值赋值为了undefined。
     */
    var arr=[1,2,3,4,5,'谦龙','雏田'];
    delete arr[5];
    console.log(arr,arr[5],arr.length);

 

测试

10

可以通过splice来删除数组中的某一项

   var arr=[1,2,3,4,5,'谦龙','雏田'];
    arr.splice(5,1);
    console.log(arr,arr[5],arr.length);

测试

10-2

11 生成指定长度的随机字母数字字符串

    function getRandomStr(len) {
        var str = "";
        for( ; str.length < len; str  += Math.random().toString(36).substr(2));
        return  str.substr(0, len);
    }

测试
11

12 null 与 undefined

    function test(obj){
        if(obj!=null){// obj除了undefined 和 null 之外都会走这里
        //....这里写代码逻辑
        }
    }

 

13 找出数组中出现次数最的元素,并给出其出现过的位置

    function getMaxAndIndex( arr ){
        var obj = {};
        arr.forEach(function(item,index){
            if(!obj[item]){
                obj[item]= {indexs: [index]}
            }else{
                obj[item]['indexs'].push(index);
            }
        });
        var num=0;//记录出现次数最大值
        var str='';//记录出现次数最多的字符
        var reArr;//返回最大值的位置数组
        for(var attr in obj){
            var temp=obj[attr]['indexs'];
            if(temp.length>num){
                num=temp.length;
                str=attr;
                reArr=temp;
            }
        }
        return {
            maxStr:str,
            indexs:reArr
        }
    }

 

测试结果13

String Skill

时间对比:时间个位数形式需补0

const time1 = "2019-02-14 21:00:00";
const time2 = "2019-05-01 09:00:00";
const overtime = time1 > time2;
// overtime => false

格式化金钱

const ThousandNum = num => num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
const money = ThousandNum(20190214);
// money => "20,190,214"

生成随机ID

const RandomId = len => Math.random().toString(36).substr(3, len);
const id = RandomId(10);
// id => "jg7zpgiqva"

生成随机HEX色值

const RandomColor = () => "#" + Math.floor(Math.random() * 0xffffff).toString(16).padEnd(6, "0");
const color = RandomColor();
// color => "#f03665"

生成星级评分

const StartScore = rate => "★★★★★☆☆☆☆☆".slice(5 - rate, 10 - rate);
const start = StartScore(3);
// start => "★★★"

操作URL查询参数

const params = new URLSearchParams(location.search.replace(/\?/ig, "")); // location.search = "?name=young&sex=male"
params.has("young"); // true
params.get("sex"); // "male"

Number Skill

取整:代替正数的Math.floor(),代替负数的Math.ceil()

const num1 = ~~ 1.69;
const num2 = 1.69 | 0;
const num3 = 1.69 >> 0;
// num1 num2 num3 => 1 1 1

补零

const FillZero = (num, len) => num.toString().padStart(len, "0");
const num = FillZero(169, 5);
// num => "00169"

转数值:只对null、""、false、数值字符串有效

const num1 = +null;
const num2 = +"";
const num3 = +false;
const num4 = +"169";
// num1 num2 num3 num4 => 0 0 0 169

时间戳

const timestamp = +new Date("2019-02-14");
// timestamp => 1550102400000

精确小数

const RoundNum = (num, decimal) => Math.round(num * 10 ** decimal) / 10 ** decimal;
const num = RoundNum(1.69, 1);
// num => 1.7
复制代码

判断奇偶

const OddEven = num => !!(num & 1) ? "odd" : "even";
const num = OddEven(2);
// num => "even"

取最小最大值

const arr = [0, 1, 2];
const min = Math.min(...arr);
const max = Math.max(...arr);
// min max => 0 2
复制代码

生成范围随机数

const RandomNum = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min;
const num = RandomNum(1, 10);

Boolean Skill

短路运算符

const a = d && 1; // 满足条件赋值:取假运算,从左到右依次判断,遇到假值返回假值,后面不再执行,否则返回最后一个真值
const b = d || 1; // 默认赋值:取真运算,从左到右依次判断,遇到真值返回真值,后面不再执行,否则返回最后一个假值
const c = !d; // 取假赋值:单个表达式转换为true则返回false,否则返回true

判断数据类型:undefined、null、string、number、boolean、array、object、symbol、date、regexp、function、asyncfunction、arguments、set、map、weakset、weakmap

function DataType(tgt, type) {
    const dataType = Object.prototype.toString.call(tgt).replace(/\[object /g, "").replace(/\]/g, "").toLowerCase();
    return type ? dataType === type : dataType;
}
DataType("young"); // "string"
DataType(20190214); // "number"
DataType(true); // "boolean"
DataType([], "array"); // true
DataType({}, "array"); // false

是否为空数组

const arr = [];
const flag = Array.isArray(arr) && !arr.length;
// flag => true

是否为空对象

const obj = {};
const flag = DataType(obj, "object") && !Object.keys(obj).length;
// flag => true

满足条件时执行

const flagA = true; // 条件A
const flagB = false; // 条件B
(flagA || flagB) && Func(); // 满足A或B时执行
(flagA || !flagB) && Func(); // 满足A或不满足B时执行
flagA && flagB && Func(); // 同时满足A和B时执行
flagA && !flagB && Func(); // 满足A且不满足B时执行

为非假值时执行

const flag = false; // undefined、null、""、0、false、NaN
!flag && Func();

数组不为空时执行

const arr = [0, 1, 2];
arr.length && Func();

对象不为空时执行

const obj = { a: 0, b: 1, c: 2 };
Object.keys(obj).length && Func();

函数退出代替条件分支退出

if (flag) {
    Func();
    return false;
}
// 换成
if (flag) {
    return Func();
}

switch/case使用区间

const age = 26;
switch (true) {
    case isNaN(age):
        console.log("not a number");
        break;
    case (age < 18):
        console.log("under age");
        break;
    case (age >= 18):
        console.log("adult");
        break;
    default:
        console.log("please set your age");
        break;
}

Array Skill

克隆数组

const _arr = [0, 1, 2];
const arr = [..._arr];
// arr => [0, 1, 2]

合并数组

const arr1 = [0, 1, 2];
const arr2 = [3, 4, 5];
const arr = [...arr1, ...arr2];
// arr => [0, 1, 2, 3, 4, 5];

去重数组

const arr = [...new Set([0, 1, 1, null, null])];
// arr => [0, 1, null]

混淆数组

const arr = [0, 1, 2, 3, 4, 5].slice().sort(() => Math.random() - .5);
// arr => [3, 4, 0, 5, 1, 2]

清空数组

const arr = [0, 1, 2];
arr.length = 0;
// arr => []

截断数组

const arr = [0, 1, 2];
arr.length = 2;
// arr => [0, 1]

交换赋值

let a = 0;
let b = 1;
[a, b] = [b, a];
// a b => 1 0

过滤空值:undefined、null、””、0、false、NaN

const arr = [undefined, null, "", 0, false, NaN, 1, 2].filter(Boolean);
// arr => [1, 2]

异步累计

async function Func(deps) {
    return deps.reduce(async(t, v) => {
        const dep = await t;
        const version = await Todo(v);
        dep[v] = version;
        return dep;
    }, Promise.resolve({}));
}
const result = await Func(); // 需在async包围下使用

数组首部插入成员

let arr = [1, 2]; // 以下方法任选一种
arr.unshift(0);
arr = [0].concat(arr);
arr = [0, ...arr];
// arr => [0, 1, 2]

数组尾部插入成员

let arr = [0, 1]; // 以下方法任选一种
arr.push(2);
arr.concat(2);
arr[arr.length] = 2;
arr = [...arr, 2];
// arr => [0, 1, 2]

统计数组成员个数

const arr = [0, 1, 1, 2, 2, 2];
const count = arr.reduce((t, c) => {
    t[c] = t[c] ? ++ t[c] : 1;
    return t;
}, {});
// count => { 0: 1, 1: 2, 2: 3 }

解构数组成员嵌套

const arr = [0, 1, [2, 3, [4, 5]]];
const [a, b, [c, d, [e, f]]] = arr;
// a b c d e f => 0 1 2 3 4 5

解构数组成员别名

const arr = [0, 1, 2];
const { 0: a, 1: b, 2: c } = arr;
// a b c => 0 1 2

解构数组成员默认值

const arr = [0, 1, 2];
const [a, b, c = 3, d = 4] = arr;
// a b c d => 0 1 2 4

获取随机数组成员

const arr = [0, 1, 2, 3, 4, 5];
const randomItem = arr[Math.floor(Math.random() * arr.length)];
// randomItem => 1

创建指定长度数组

const arr = [...new Array(3).keys()];
// arr => [0, 1, 2]

创建指定长度且值相等的数组

const arr = new Array(3).fill(0);
// arr => [0, 0, 0]

reduce代替map和filter

const _arr = [0, 1, 2];

// map
const arr = _arr.map(v => v * 2);
const arr = _arr.reduce((t, c) => {
    t.push(c * 2);
    return t;
}, []);
// arr => [0, 2, 4]

// filter
const arr = _arr.filter(v => v > 0);
const arr = _arr.reduce((t, c) => {
    c > 0 && t.push(c);
    return t;
}, []);
// arr => [1, 2]

// map和filter
const arr = _arr.map(v => v * 2).filter(v => v > 2);
const arr = _arr.reduce((t, c) => {
    c = c * 2;
    c > 2 && t.push(c);
    return t;
}, []);
// arr => [4]

Object Skill

克隆对象

const _obj = { a: 0, b: 1, c: 2 }; // 以下方法任选一种
const obj = { ..._obj };
const obj = JSON.parse(JSON.stringify(_obj));
// obj => { a: 0, b: 1, c: 2 }

合并对象

const obj1 = { a: 0, b: 1, c: 2 };
const obj2 = { c: 3, d: 4, e: 5 };
const obj = { ...obj1, ...obj2 };
// obj => { a: 0, b: 1, c: 3, d: 4, e: 5 }

对象字面量:获取环境变量时必用此方法,用它一直爽,一直用它一直爽

const env = "prod";
const link = {
    dev: "Development Address",
    test: "Testing Address",
    prod: "Production Address"
}[env];
// link => "Production Address"

对象变量属性

const flag = false;
const obj = {
    a: 0,
    b: 1,
    [flag ? "c" : "d"]: 2
};
// obj => { a: 0, b: 1, d: 2 }

创建纯空对象

const obj = Object.create(null);
Object.prototype.a = 0;
// obj => {}

删除对象无用属性

const obj = { a: 0, b: 1, c: 2 }; // 只想拿b和c
const { a, ...rest } = obj;
// rest => { b: 1, c: 2 }

解构对象属性嵌套

const obj = { a: 0, b: 1, c: { d: 2, e: 3 } };
const { c: { d, e } } = obj;
// d e => 2 3

解构对象属性别名

const obj = { a: 0, b: 1, c: 2 };
const { a, b: d, c: e } = obj;
// a d e => 0 1 2

解构对象属性默认值

const obj = { a: 0, b: 1, c: 2 };
const { a, b = 2, d = 3 } = obj;
// a b d => 0 1 3

Function Skill

函数自执行

const Func = function() {}(); // 常用

(function() {})(); // 常用
(function() {}()); // 常用
[function() {}()];

+ function() {}();
- function() {}();
~ function() {}();
! function() {}();

new function() {};
new function() {}();
void function() {}();
typeof function() {}();
delete function() {}();

1, function() {}();
1 ^ function() {}();
1 > function() {}();

隐式返回值:只能用于单语句返回值箭头函数,如果返回值是对象必须使用()包住

const Func = function(name) {
    return "I Love " + name;
};
// 换成
const Func = name => "I Love " + name;

一次性函数:适用于运行一些只需执行一次的初始化代码

function Func() {
    console.log("x");
    Func = function() {
        console.log("y");
    }
}

惰性载入函数:函数内判断分支较多较复杂时可大大节约资源开销

function Func() {
    if (a === b) {
        console.log("x");
    } else {
        console.log("y");
    }
}
// 换成
function Func() {
    if (a === b) {
        Func = function() {
            console.log("x");
        }
    } else {
        Func = function() {
            console.log("y");
        }
    }
    return Func();
}

检测非空参数

function IsRequired() {
    throw new Error("param is required");
}
function Func(name = IsRequired()) {
    console.log("I Love " + name);
}
Func(); // "param is required"
Func("You"); // "I Love You"

字符串创建函数

const Func = new Function("name", "console.log(\"I Love \" + name)");

优雅处理错误信息

try {
    Func();
} catch (e) {
    location.href = "https://stackoverflow.com/search?q=[js]+" + e.message;
}

优雅处理Async/Await参数

function AsyncTo(promise) {
    return promise.then(data => [null, data]).catch(err => [err]);
}
const [err, res] = await AsyncTo(Func());

优雅处理多个函数返回值

function Func() {
    return Promise.all([
        fetch("/user"),
        fetch("/comment")
    ]);
}
const [user, comment] = await Func(); // 需在async包围下使用

DOM Skill

显示全部DOM边框:调试页面元素边界时使用

[].forEach.call($$("*"), dom => {
    dom.style.outline = "1px solid #" + (~~(Math.random() * (1 << 24))).toString(16);
});

自适应页面:页面基于一张设计图但需做多款机型自适应,元素尺寸使用rem进行设置

function AutoResponse(width = 750) {
    const target = document.documentElement;
    target.clientWidth >= 600
        ? (target.style.fontSize = "80px")
        : (target.style.fontSize = target.clientWidth / width * 100 + "px");
}

过滤XSS

function FilterXss(content) {
    let elem = document.createElement("div");
    elem.innerText = content;
    const result = elem.innerHTML;
    elem = null;
    return result;
}

存取LocalStorage:反序列化取,序列化存

const love = JSON.parse(localStorage.getItem("love"));
localStorage.setItem("love", JSON.stringify("I Love You"));

作者:JowayYoung
链接:https://juejin.im/post/5cc7afdde51d456e671c7e48
来源:掘金

By柏小白

使用VisualSVN Server创建版本库

  1. 打开VisualSVN Server Manager,可以在窗口的右边看到版本库的一些信息,比如状态,日志,用户认证,版本库等.要建立版本库,需要右键单击左边窗口的Repositores,如下图所示:

    使用VisualSVN Server创建版本库
  2. 2

    在弹出的右键菜单中选择Create New Repository或者新建->Repository,进入下一步,如下图所示:

    使用VisualSVN Server创建版本库
  3. 3

    输入版本库名称,勾上Create default structure复选框(推荐这么做).点击OK,版本库就创建好了,版本库中会默认建立trunk,branches,tags三个文件夹,如下图所示:

    使用VisualSVN Server创建版本库
    使用VisualSVN Server创建版本库
  4. 4

    这时候我们将项目导入到版本库中,找到你的项目文件夹,在项目文件夹上点击鼠标右键,找到SVN菜单,选择导入,如下图所示:

    使用VisualSVN Server创建版本库
  5. 5

    在弹出的对话框中填上版本库URL,这个URL可以从VisualSVN Server Manager中获取,在你的版本库上单击右键,选择Copy URL to Clipboard,这样就把版本库URL复制到你的剪贴版了.如下图所示:

    使用VisualSVN Server创建版本库
  6. 6

    将复制的版本库URL粘贴上,在URL后面加上trunk子路径。然后在导入信息里面填上导入信息”导入项目到版本库“,如下图所示:

    使用VisualSVN Server创建版本库
  7. 7

    点击确定,所选中的项目就会被导入到版本库中,如下图所示:

    使用VisualSVN Server创建版本库
  8. 8

    项目导入到版本库以后,不能随便让谁都能够读写版本库,所以需要建立用户组和用户。

    VisualSVN Server Manager窗口的左侧右键单击用户组,选择Create User或者新建->User,如下图所示:

    使用VisualSVN Server创建版本库
  9. 在弹出的对话框中填写User namePassword,然后点击OK,如下图所示:

    使用VisualSVN Server创建版本库
  10. 用相同的方式分别创建用户Develpoer1,Develpoer2,Develpoer3,Test1,Test2,Manger六个用户,分别代表3个开发人员,两个测试人员和一个项目经理,如下图所示:

    使用VisualSVN Server创建版本库
  11. 然后我们建立用户组,在VisualSVN Server Manager窗口的左侧右键单击用户组,选择Create Group或者新建->Group,如图:

    使用VisualSVN Server创建版本库
  12. 在弹出窗口中填写Group nameDevelopers,然后点Add按钮,在弹出的窗口中选择三个Developer,加入到这个组,然后点Ok,如下图所示:

    使用VisualSVN Server创建版本库
  13. 用相同的方式创建组Managers,Testers,如下图所示:

    使用VisualSVN Server创建版本库
  14. 接下来我们给用户组设置权限,在MyRepository上单击右键,选择属性,如下图所示:

    使用VisualSVN Server创建版本库
  15. 在弹出的对话框中,选择Security选项卡,点击Add按钮,选中Developers,Managers,Testers三个组,然后添加进来,给Developers,Managers权限设置为Read/Write,Tester权限设置为Read Only,如下图所示:

    使用VisualSVN Server创建版本库
  16. 到此,服务端就完成了。接下来,我们用客户端去检出代码,在桌面空白处单击右键,选择SVN检出,在弹出的对话框中填写版本库URL,选择检出目录,点击确定。如下图所示:

    使用VisualSVN Server创建版本库
  17. 开始检出项目,如下图所示:

    使用VisualSVN Server创建版本库
  18. 检出完成之后,我们打开工作副本文件夹,会看到所有文件和文件夹都有一个绿色的√。至此,创建版本库和使用TortoiseSVN导入项目,检出项目已经介绍完毕。

    如下图所示:

    使用VisualSVN Server创建版本库

 

By柏小白

WebStorm打开后无法显示文件夹目录

昨天乱整,WebStorm打开项目,发现项目的文件夹目录不见了 google 一哈,发现解决的方法!!!
项目文件夹目录消失
问题原因:WebStorm自动生成的配置文件 .idea/modules.xml损坏(就是我一开始乱搞,删项目照成)。

11

解决方法 = {

    1: "关掉webstorm;",

    2: "删除.idea文件夹(如果隐藏,请设置显示隐藏文件夹);",

    3: "重新打开项目;",

    4: "OK 搞定"
}
By柏小白

jQuery-插件开发全解析

之前写过一篇文章:jquery.fn.extend与jquery.extend插件开发

现在收集了更详细的解释文档

jQuery插件的开发包括两种:

一种是类级别的插件开发,即给jQuery添加新的全局函数,相当于给jQuery类本身添加方法。jQuery的全局函数就是属于jQuery命名空间的函数,另一种是对象级别的插件开发,即给jQuery对象添加方法。下面就两种函数的开发做详细的说明。

1、类级别的插件开发

类级别的插件开发最直接的理解就是给jQuery类添加类方法,可以理解为添加静态方法。典型的例子就是$.AJAX()这个函数,将函数定义于jQuery的命名空间中。关于类级别的插件开发可以采用如下几种形式进行扩展:

1.1 添加一个新的全局函数

添加一个全局函数,我们只需如下定义:

jQuery.foo = function() {    
alert('This is a test. This is only a test.');   
};

1.2 增加多个全局函数

添加多个全局函数,可采用如下定义:

jQuery.foo = function() {    
alert('This is a test. This is only a test.');   
};   
jQuery.bar = function(param) {    
alert('This function takes a parameter, which is "' + param + '".');   
};    
// 调用时和一个函数的一样的:jQuery.foo();jQuery.bar();或者$.foo();$.bar('bar');

1.3 使用jQuery.extend(object);

jQuery.extend({      
foo: function() {      
alert('This is a test. This is only a test.');      
},      
bar: function(param) {      
alert('This function takes a parameter, which is "' + param +'".');      
}     
});
1.4 使用命名空间

虽然在jQuery命名空间中,我们禁止使用了大量的javaScript函数名和变量名。但是仍然不可避免某些函数或变量名将于其他jQuery插件冲突,因此我们习惯将一些方法封装到另一个自定义的命名空间。

jQuery.myPlugin = {           
foo:function() {           
alert('This is a test. This is only a test.');           
},           
bar:function(param) {           
alert('This function takes a parameter, which is "' + param + '".');     
}          
};   
// 采用命名空间的函数仍然是全局函数,调用时采用的方法:   
$.myPlugin.foo();          
$.myPlugin.bar('baz');

通过这个技巧(使用独立的插件名),我们可以避免命名空间内函数的冲突。

2、对象级别的插件开发

对象级别的插件开发需要如下的两种形式:

形式1:

(function($){      
$.fn.extend({      
pluginName:function(opt,callback){      
// Our plugin implementation code goes here.        
}      
})      
})(jQuery);

形式2:

(function($) {        
$.fn.pluginName = function() {      
// Our plugin implementation code goes here.      
};      
})(jQuery);

上面定义了一个jQuery函数,形参是$,函数定义完成之后,把jQuery这个实参传递进去.立即调用执行。这样的好处是,我们在写jQuery插件时,也可以使用$这个别名,而不会与prototype引起冲突.

2.1 在JQuery名称空间下申明一个名字

这是一个单一插件的脚本。如果你的脚本中包含多个插件,或者互逆的插件(例如: $.fn.doSomething() 和$.fn.undoSomething()),那么你需要声明多个函数名字。但是,通常当我们编写一个插件时,力求仅使用一个名字来包含它的所有内容。我们的示例插件命名为“highlight“

$.fn.hilight = function() {     
  // Our plugin implementation code goes here.     
};     
我们的插件通过这样被调用:   
$('#myDiv').hilight();

但是如果我们需要分解我们的实现代码为多个函数该怎么办?有很多原因:设计上的需要;这样做更容易或更易读的实现;而且这样更符合面向对象。 这真是一个麻烦事,把功能实现分解成多个函数而不增加多余的命名空间。出于认识到和利用函数是javascript中最基本的类对象,我们可以这样做。就像其他对象一样,函数可以被指定为属性。因此我们已经声明“hilight”为jQuery的属性对象,任何其他的属性或者函数我们需要暴露出来的,都可以在”hilight” 函数中被声明属性。稍后继续。

2.2 接受options参数以控制插件的行为

让我们为我们的插件添加功能指定前景色和背景色的功能。我们也许会让选项像一个options对象传递给插件函数。例如:

// plugin definition     
$.fn.hilight = function(options) {     
  var defaults = {     
   foreground: 'red',     
   background: 'yellow'     
  };     
// Extend our default options with those provided.     
  var opts = $.extend(defaults, options);     
// Our plugin implementation code goes here.     
};     
// 我们的插件可以这样被调用:   
$('#myDiv').hilight({     
  foreground: 'blue'     
});

2.3 暴露插件的默认设置

我们应该对上面代码的一种改进是暴露插件的默认设置。这对于让插件的使用者更容易用较少的代码覆盖和修改插件。接下来我们开始利用函数对象。

// plugin definition     
$.fn.hilight = function(options) {     
  // Extend our default options with those provided.     
  // Note that the first arg to extend is an empty object -     
  // this is to keep from overriding our "defaults" object.     
  var opts = $.extend({}, $.fn.hilight.defaults, options);     
  // Our plugin implementation code goes here.     
};     
// plugin defaults - added as a property on our plugin function     
$.fn.hilight.defaults = {     
  foreground: 'red',     
  background: 'yellow'     
};      
//现在使用者可以包含像这样的一行在他们的脚本里:   
//这个只需要调用一次,且不一定要在ready块中调用   
$.fn.hilight.defaults.foreground = 'blue';     
//接下来我们可以像这样使用插件的方法,结果它设置蓝色的前景色:   
$('#myDiv').hilight();

如你所见,我们允许使用者写一行代码在插件的默认前景色。而且使用者仍然在需要的时候可以有选择的覆盖这些新的默认值:

// 覆盖插件缺省的背景颜色 

$.fn.hilight.defaults.foreground = 'blue'; 

// ... 

// 使用一个新的缺省设置调用插件 

$('.hilightDiv').hilight(); 

// ... 

// 通过传递配置参数给插件方法来覆盖缺省设置 

$('#green').hilight({ 

 foreground: 'green' 

}); 

2.4 适当的暴露一些函数

这段将会一步一步对前面那段代码通过有意思的方法扩展你的插件(同时让其他人扩展你的插件)。例如,我们插件的实现里面可以定义一个名叫”format”的函数来格式化高亮文本。我们的插件现在看起来像这样,默认的format方法的实现部分在hiligth函数下面。

// plugin definition     
$.fn.hilight = function(options) {     
// iterate and reformat each matched element     
  return this.each(function() {     
    var $this = $(this);     
// ...     
    var markup = $this.html();     
// call our format function     
    markup = $.fn.hilight.format(markup);     
    $this.html(markup);     
  });     
};     
// define our format function     
$.fn.hilight.format = function(txt) {     
return '<strong>' + txt + '</strong>';     
};

我们很容易的支持options对象中的其他的属性通过允许一个回调函数来覆盖默认的设置。这是另外一个出色的方法来修改你的插件。这里展示的技巧是进一步有效的暴露format函数进而让他能被重新定义。通过这技巧,是其他人能够传递他们自己设置来覆盖你的插件,换句话说,这样其他人也能够为你的插件写插件。

考虑到这个篇文章中我们建立的无用的插件,你也许想知道究竟什么时候这些会有用。一个真实的例子是Cycle插件.这个Cycle插件是一个滑动显示插件,他能支持许多内部变换作用到滚动,滑动,渐变消失等。但是实际上,没有办法定义也许会应用到滑动变化上每种类型的效果。那是这种扩展性有用的地方。 Cycle插件对使用者暴露”transitions”对象,使他们添加自己变换定义。插件中定义就像这样:
$.fn.cycle.transitions = { 

// ... 

};

这个技巧使其他人能定义和传递变换设置到Cycle插件。

2.5 保持私有函数的私有性

这种技巧暴露你插件一部分来被覆盖是非常强大的。但是你需要仔细思考你实现中暴露的部分。一但被暴露,你需要在头脑中保持任何对于参数或者语义的改动也许会破坏向后的兼容性。一个通理是,如果你不能肯定是否暴露特定的函数,那么你也许不需要那样做。

那么我们怎么定义更多的函数而不搅乱命名空间也不暴露实现呢?这就是闭包的功能。为了演示,我们将会添加另外一个“debug”函数到我们的插件中。这个 debug函数将为输出被选中的元素格式到firebug控制台。为了创建一个闭包,我们将包装整个插件定义在一个函数中。

 (function($) {     
// plugin definition     
  $.fn.hilight = function(options) {     
    debug(this);     
// ...     
  };     
// private function for debugging     
  function debug($obj) {     
  if (window.console && window.console.log)     
 window.console.log('hilight selection count: ' + $obj.size()); 
  };     
//  ...     
})(jQuery);

我们的“debug”方法不能从外部闭包进入,因此对于我们的实现是私有的。

2.6 支持Metadata插件

在你正在写的插件的基础上,添加对Metadata插件的支持能使他更强大。个人来说,我喜欢这个Metadata插件,因为它让你使用不多的”markup”覆盖插件的选项(这非常有用当创建例子时)。而且支持它非常简单。更新:注释中有一点优化建议。

$.fn.hilight = function(options) {     
// ...     
// build main options before element iteration     
  var opts = $.extend({}, $.fn.hilight.defaults, options);   
  return this.each(function() {     
   var $this = $(this);     
//build element specific options     
 var o = $.meta ? $.extend({}, opts, $this.data()) : opts  
//...

这些变动行做了一些事情:它是测试Metadata插件是否被安装如果它被安装了,它能扩展我们的options对象通过抽取元数据这行作为最后一个参数添加到JQuery.extend,那么它将会覆盖任何其它选项设置。现在我们能从”markup”处驱动行为,如果我们选择了“markup”:

调用的时候可以这样写: jQuery.foo(); 或 $.foo();

<!--  markup  -->     
<div class="hilight { background: 'red', foreground: 'white' } 
  Have a nice day!     
</div>     
<div class="hilight { foreground: 'orange' }">     
  Have a nice day!     
</div>     
<div class="hilight { background: 'green' }">     
  Have a nice day!     
</div>     
现在我们能高亮哪些div仅使用一行脚本:   
$('.hilight').hilight();

2.7 整合
下面使我们的例子完成后的代码:

// 创建一个闭包     
(function($) {     
  // 插件的定义     
  $.fn.hilight = function(options) {     
    debug(this);     
    // build main options before element iteration     
    var opts = $.extend({}, $.fn.hilight.defaults, options) 
    // iterate and reformat each matched element     
    return this.each(function() {     
      $this = $(this);     
      // build element specific options     
      var o = $.meta ? $.extend({}, opts, $this.data()) : opts;     
      // update element styles     
      $this.css({     
        backgroundColor: o.background,     
        color: o.foreground     
      });     
      var markup = $this.html();     
      // call our format function     
      markup = $.fn.hilight.format(markup);     
      $this.html(markup);     
    });     
  };     
  // 私有函数:debugging     
  function debug($obj) {     
    if (window.console && window.console.log)     
      window.console.log('hilight selection count: ' + $obj.size());     
  };     
  // 定义暴露format函数     
  $.fn.hilight.format = function(txt) {     
    return '<strong>' + txt + '</strong>';     
  };     
  // 插件的defaults     
  $.fn.hilight.defaults = {     
    foreground: 'red',     
    background: 'yellow'     
  };     
// 闭包结束     
})(jQuery);

这段设计已经让我创建了强大符合规范的插件。我希望它能让你也能做到。

3、总结

jQuery为开发插件提拱了两个方法,分别是:

jQuery.fn.extend(object);  给jQuery对象添加方法。
jQuery.extend(object);  为扩展jQuery类本身.为类添加新的方法。

3.1 jQuery.fn.extend(object);

fn 是什么东西呢。查看jQuery代码,就不难发现。

jQuery.fn = jQuery.prototype = {  

init: function( selector, context ) {//....   

//......  

};

原来 jQuery.fn = jQuery.prototype.对prototype肯定不会陌生啦。虽然 javascript 没有明确的类的概念,但是用类来理解它,会更方便。jQuery便是一个封装得非常好的类,比如我们用 语句 $(“#btn1”) 会生成一个 jQuery类的实例。

jQuery.fn.extend(object); 对jQuery.prototype进得扩展,就是为jQuery类添加“成员函数”。jQuery类的实例可以使用这个“成员函数”。

比如我们要开发一个插件,做一个特殊的编辑框,当它被点击时,便alert 当前编辑框里的内容。可以这么做:

$.fn.extend({        

     alertWhileClick:function(){       

         $(this).click(function(){      

              alert($(this).val());       

          });       

      }       

});

$(“#input1″).alertWhileClick(); //页面上为:<input id=”input1” type=”text”/>

$(“#input1”) 为一个jQuery实例,当它调用成员方法 alertWhileClick后,便实现了扩展,每次被点击时它会先弹出目前编辑里的内容。

 

3.2 jQuery.extend(object);

为jQuery类添加添加类方法,可以理解为添加静态方法。如:

$.extend({  

    add:function(a,b){return a+b;}  

});

便为jQuery添加一个为add的“静态方法”,之后便可以在引入jQuery的地方,使用这个方法了,$.add(3,4); //return 7

By柏小白

使用WebStorm集成开发环境Less解析安装与配置

 

1.安Node.JS

由于Less是使用JS开发的,所以Less运行时依赖Node.JS,如果你电脑之前没有安装过Node.JS,还需下载安装Node.JS

柏小白-小白变大神

node.js官网 下载

安装过程都是一路下一步。安装完成后打开控制台输入node -v,如果能显示出版本号就说明,安装成功了。

2.替换淘宝镜像 CNPM

由于长城牌防火墙的原因,可能NPM(Node.js的包管理工具)无法访问到服务器,这时就可替换成淘宝的NPM镜像

打开控制台直接输入:
npm install -g cnpm –registry=https://registry.npm.taobao.org
MAC平台前面还需加一个sodo

3.安装Less

打开控制台直接输入:
cnpm install -g less
接着输入lessc -v能看到版本号就表示安装成功了

4.添加File Watchers

打开WebStorm,点击文件—>设置—>File Watchers—>右边的+

柏小白-小白变大神

Less配置

program:你Node安装路径下的lessc.cmd
arguments:–no-color –source-map=$FileNameWithoutExtension$.css.map $FileName$ 
working directory:$FileDir$
output paths to refresh:$FileNameWithoutExtension$.css:$FileNameWithoutExtension$.css.map

之后你只要在项目中添加一个.less文件,系统就会自动为你编译了。

By柏小白

提高博客wordpres后台安全性的详细方法

加强安全设置,以避免因为漏洞而遭到不必要的损失

具体方法:

1)使用插件

1.1  使用Stealth Login Page 插件    使用方法 

1.2  使用 Protected wp-login 插件

chajian

使用方法“度娘”(个人建议Google),度娘全是给钱排名,么么哒(*  ̄3)(ε ̄ *)。。

Read More

By柏小白

jquery.fn.extend与jquery.extend插件开发

jQuery为开发插件提拱了两个方法,分别是:

JavaScript代码

  • jQuery.fn.extend(object);
  • jQuery.extend(object);

Read More

By柏小白

Nginx配置文件nginx.conf中文详解

Ps:nginx真的没用过几次,每次都是搭的apache

转自:http://www.ha97.com/5194.html

PS:Nginx使 用有两三年了,现在经常碰到有新用户问一些很基本的问题,我也没时间一一回答,今天下午花了点时间,结合自己的使用经验,把Nginx的主要配置参数说明 分享一下,也参考了一些网络的内容,这篇是目前最完整的Nginx配置参数中文说明了。更详细的模块参数请参 考:http://wiki.nginx.org/Main


#定义Nginx运行的用户和用户组
user www www;

#nginx进程数,建议设置为等于CPU总核心数。
worker_processes 8;

#全局错误日志定义类型,[ debug | info | notice | warn | error | crit ]
error_log /var/log/nginx/error.log info;

#进程文件
pid /var/run/nginx.pid;

#一个nginx进程打开的最多文件描述符数目,理论值应该是最多打开文件数(系统的值ulimit -n)与nginx进程数相除,但是nginx分配请求并不均匀,所以建议与ulimit -n的值保持一致。
worker_rlimit_nofile 65535;

#工作模式与连接数上限
events
{
#参考事件模型,use [ kqueue | rtsig | epoll | /dev/poll | select | poll ]; epoll模型是Linux 2.6以上版本内核中的高性能网络I/O模型,如果跑在FreeBSD上面,就用kqueue模型。
use epoll;
#单个进程最大连接数(最大连接数=连接数*进程数)
worker_connections 65535;
}

#设定http服务器
http
{
include mime.types; #文件扩展名与文件类型映射表
default_type application/octet-stream; #默认文件类型
#charset utf-8; #默认编码
server_names_hash_bucket_size 128; #服务器名字的hash表大小
client_header_buffer_size 32k; #上传文件大小限制
large_client_header_buffers 4 64k; #设定请求缓
client_max_body_size 8m; #设定请求缓
sendfile on; #开启高效文件传输模式,sendfile指令指定nginx是否调用sendfile函数来输出文件,对于普通应用设为 on,如果用来进行下载等应用磁盘IO重负载应用,可设置为off,以平衡磁盘与网络I/O处理速度,降低系统的负载。注意:如果图片显示不正常把这个改 成off。
autoindex on; #开启目录列表访问,合适下载服务器,默认关闭。
tcp_nopush on; #防止网络阻塞
tcp_nodelay on; #防止网络阻塞
keepalive_timeout 120; #长连接超时时间,单位是秒

#FastCGI相关参数是为了改善网站的性能:减少资源占用,提高访问速度。下面参数看字面意思都能理解。
fastcgi_connect_timeout 300;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;
fastcgi_buffer_size 64k;
fastcgi_buffers 4 64k;
fastcgi_busy_buffers_size 128k;
fastcgi_temp_file_write_size 128k;

#gzip模块设置
gzip on; #开启gzip压缩输出
gzip_min_length 1k; #最小压缩文件大小
gzip_buffers 4 16k; #压缩缓冲区
gzip_http_version 1.0; #压缩版本(默认1.1,前端如果是squid2.5请使用1.0)
gzip_comp_level 2; #压缩等级
gzip_types text/plain application/x-javascript text/css application/xml;
#压缩类型,默认就已经包含text/html,所以下面就不用再写了,写上去也不会有问题,但是会有一个warn。
gzip_vary on;
#limit_zone crawler $binary_remote_addr 10m; #开启限制IP连接数的时候需要使用

upstream blog.ha97.com {
#upstream的负载均衡,weight是权重,可以根据机器配置定义权重。weigth参数表示权值,权值越高被分配到的几率越大。
server 192.168.80.121:80 weight=3;
server 192.168.80.122:80 weight=2;
server 192.168.80.123:80 weight=3;
}

#虚拟主机的配置
server
{
#监听端口
listen 80;
#域名可以有多个,用空格隔开
server_name www.ha97.com ha97.com;
index index.html index.htm index.php;
root /data/www/ha97;
location ~ .*.(php|php5)?$
{
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi.conf;
}
#图片缓存时间设置
location ~ .*.(gif|jpg|jpeg|png|bmp|swf)$
{
expires 10d;
}
#JS和CSS缓存时间设置
location ~ .*.(js|css)?$
{
expires 1h;
}
#日志格式设定
log_format access ‘$remote_addr – $remote_user [$time_local] “$request” ‘
‘$status $body_bytes_sent “$http_referer” ‘
‘”$http_user_agent” $http_x_forwarded_for’;
#定义本虚拟主机的访问日志
access_log /var/log/nginx/ha97access.log access;

#对 “/” 启用反向代理
location / {
proxy_pass http://127.0.0.1:88;
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
#后端的Web服务器可以通过X-Forwarded-For获取用户真实IP
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
#以下是一些反向代理的配置,可选。
proxy_set_header Host $host;
client_max_body_size 10m; #允许客户端请求的最大单文件字节数
client_body_buffer_size 128k; #缓冲区代理缓冲用户端请求的最大字节数,
proxy_connect_timeout 90; #nginx跟后端服务器连接超时时间(代理连接超时)
proxy_send_timeout 90; #后端服务器数据回传时间(代理发送超时)
proxy_read_timeout 90; #连接成功后,后端服务器响应时间(代理接收超时)
proxy_buffer_size 4k; #设置代理服务器(nginx)保存用户头信息的缓冲区大小
proxy_buffers 4 32k; #proxy_buffers缓冲区,网页平均在32k以下的设置
proxy_busy_buffers_size 64k; #高负荷下缓冲大小(proxy_buffers*2)
proxy_temp_file_write_size 64k;
#设定缓存文件夹大小,大于这个值,将从upstream服务器传
}

#设定查看Nginx状态的地址
location /NginxStatus {
stub_status on;
access_log on;
auth_basic “NginxStatus”;
auth_basic_user_file conf/htpasswd;
#htpasswd文件的内容可以用apache提供的htpasswd工具来产生。
}

#本地动静分离反向代理配置
#所有jsp的页面均交由tomcatresin处理
location ~ .(jsp|jspx|do)?$ {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://127.0.0.1:8080;
}
#所有静态文件由nginx直接读取不经过tomcat或resin
location ~ .*.(htm|html|gif|jpg|jpeg|png|bmp|swf|ioc|rar|zip|txt|flv|mid|doc|ppt|pdf|xls|mp3|wma)$
{ expires 15d; }
location ~ .*.(js|css)?$
{ expires 1h; }
}
}

更详细的模块参数请参考:http://wiki.nginx.org/Main

By柏小白

Nginx下修改wordpress固定链接后导致访问文章404

开始做seo的优化,当然牵扯到永久链接,wordpress提供多种类型的链接形式

1/%year%/%monthnum%/%day%/%postname%/

2/%year%/%monthnum%/%postname%/

3/%year%/%monthnum%/%day%/%postname%.html

4/%year%/%monthnum%/%postname%.html

5/%category%/%postname%.html

6/%post_id%.html

7/%postname%/

我选择了/%postname%.html,伪静态,虽然现在貌似没什么差别了,但还是该下吧。下面就出现了修改固定链接后,访问文章会出现404错误,以前我都是apache做web服务器,所以只要apache下就三个个关键,即

  1. wordpress对目录下的.htaccess拥有读写权限
  2. 固定链接的目录结构需要 Apache服务器的mod_rewrite模块支持,所以在Apache配置文件httpd.conf中将 LoadModule rewrite_module modules/mod_rewrite.so设置为启用。
  3. 同样是Apache配置文件,其中对于站点目录下的AllowOverride None的参数设置为All。当然修改完配置后,一定要重启Apache服务。
  4. 由于是新配置的本地测试环境,2、3两项问题同时出现,逐项更正设置后,固定链接的工作正常。

现在我用的nginix,所以也要修改nginix的ngnix.conf配置文件,让其支持重定向

假设我的wordpress博客是的 server{}段是直接放到放到了nginx.conf  (有的人为了方便管理,都习惯在单独写个vhost/目录来存放每个网站的配置文件,这就要根据你自己的设置来添加了)

vi /your_nginx_path/conf/nginx.conf

按照nginix的正则表达式的规则,可参考:Nginx 的中文维基

  • ^:匹配输入字符的开始位置
  • $:匹配数日字符串的结束位置
  • +:匹配前面的子表达式一次或者多次
  • [0-9]:数字字符范围
  • $1:调用变量

在server{}  字段   中的  “root /websit/wwwroot/;”(这行就是指定网站所在目录的)  这一行的下面 ,添加下面的内容:

         

if (-f $request_filename/index.html){
rewrite (.*) $1/index.html break;
}
if (-f $request_filename/index.php){
rewrite (.*) $1/index.php;
}
if (!-f $request_filename){
rewrite (.*) /index.php;
}

rewrite /wp-admin$ $scheme://$host$uri/ permanent;//这行是为了防止打开后台、插件页等打不开的。

保存后,输入    /etc/init.d/nginx restart , 重启nginix。就ok了!

相当于告诉nginix访问这些后按照正则表达式转到其唯一正确的地址,以此打开文章。

貌似/%postname%/会以中文为链接,为了seo,可以考虑一个插件 WP Slug Translate,它会自动换中文标题为英文,不能联网就改为拼音。

By柏小白

javascript简单滚动

<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="UTF-8" />
    <title>简单滚动</title>
    <script src="http://code.jquery.com/jquery-1.7.min.js"></script>
</head>
<body>
    <h1>简单滚动</h1>
    <style type="text/css">
/*简单滚动*/

.scroll{width:300px;height:25px;line-height:25px;border:#ccc 1px solid;overflow:hidden}
.scroll a{height:25px;display:block;padding-left:10px;}
</style>
    <!--简单滚动-->
    <div class="scroll">
        <div>
            <a>这是公告标题的第一行</a>
            <a>这是公告标题的第二行</a>
            <a>这是公告标题的第三行</a>
        </div>

    </div>
    <script type="text/javascript">

            // 简单滚动
            function AutoScroll(obj){
                $(obj).find("div").animate({
                    marginTop:"-25px"
                },1000,function(){
                    $(this).css({marginTop:"0px"}).find("a:first").appendTo(this);
                });
            }

            $(function(){
                setInterval('AutoScroll(".scroll")',3000)

            });



</script>

</body>

</html>

 





简单滚动


简单滚动

By柏小白

谈谈JavaScript匿名函数

 

匿名函数的概念大家也许不会陌生,但是我相信下面的内容会打开一些新的思路。

我们知道函数的定义方式有两种:

1 function fn1(){alert(‘fn1 works’);}

2 var fn2=function(){alert(‘fn2 works’);}

这两种方式有什么区别?思考一下…

1 第一种方式定义函数,函数声明过程在整个程序执行之前的预处理就完成了,所以只要处于同一个作用域,就可以访问到,即使在定义之前调用它也可以。

2 第二章方式就是匿名函数,这种方式函数只能按照程序流程执行到定义的那一行代码才被声明,所以只能在定义之后调用它。

举个例子

var fn1;

fn1();//报错

fn1=function(){

fn2();//fn2 works

alert(‘fn1 works’);

return false;

function fn2(){

alert(‘fn2 works’);

}

}

fn1();//fn2 works + fn1 works

我们看到fn2虽然处在return之后,程序流程并没有执行到它,但是它依然可以被使用,反之fn2只有在它被定义之后才会被正常执行。

明白了这个,下面看一看匿名函数在递归里用处

递归就是函数内部调用自己,举个例子

function fn1(n){
return n>2?fn1(n-1)+fn1(n-2):n;
}

当我们想把这个函数赋给其他的对象属性时,就要用到匿名函数,比如

obj1={

fn:function(n){

return n>2?obj1.fn(n-1)+obj1.fn(n-2):n;
}
}
obj2={
fn:obj.fn;
}
这个时候可以正常调用obj2.fn(),但是这里有一个隐患,我们必须保证obj1里的fn不能被覆盖,看下面的例子
obj1={}
obj2.fn();
obj1被清空,执行出错,怎么办,解决办法有很多,自己先想一个…
最容易的想到的是使用this,更改obj1里面fn的定义如下

obj1={

fn:function(n){

return n>2?this.fn(n-1)+this.fn(n-2):n;
}
}
这样即使obj1里的fn被改写也不影响obj2.fn(),但是this,你迷惑吗?
this在JavaScript里面绝对是一个难理解的概念,理解了最好,但是很多时候其实不一定非得用this,这个例子中,我们可以选个给匿名函数添加个名字

obj1={

fn:function fnname(n){

return n>2?fnname(n-1)+fnname(n-2):n;
}
}
我们发现和this的结果一样,但是这就避开了this的混淆视听,而且注意这个函数名只有函数内部可以访问,外部是访问不了的(请私下测试),这样就能避免诸如全局变量的问题。
还有一种解决方案,这个方案是最优雅的,所以我要作为大礼送给大家
我们知道有个arguments对象,这个对象里面有好多好玩的属性和方法,其中一个叫做callee,它的作用是调用函数本身!继续修改上面的例子

obj1={

fn:function(n){

return n>2?arguments.callee(n-1)+arguments.callee(n-2):n;
}
}
这个是目前我发现最优雅的方法,大家有其他更好的方案可以拿来讨论。
匿名函数的讨论先到此为止。
By柏小白

jQuery事件绑定的最佳实践

如果你经常使用jQuery,那么你也许很熟悉事件绑定。这是很基本的东西,但是深入一点,你就能够找到机会让你事件驱动的代码变得不太零碎,并且更容易管理。

更好的选择器策略

让我们从基础的例子开始。下面的HTML代码表示的是可以开合的导航菜单。

<button class="nav-menu-toggle">Toggle Nav Menu</button>
<nav>
<ul>
<li><a href="/">West Philadelphia</a></li>
<li><a href="/cab">Cab Whistling</a></li>
<li><a href="/throne">Throne Sitting</a></li>
</ul>
</nav>

 

下面这个是点击按钮之后控制导航菜单开合的javascript代码

$('.nav-menu-toggle').on('click',function(){
$('nav').toggle();
});

 

这可能是最常用的实现方式。它能够使用,但是比较脆。javascript代码依赖了按钮的类名nav-menu-toggle。很可能在未来其他开发者或者健忘的你在重构代码的时候会删除或者重命名这个类名。

问题的核心是我们同时在表现和交互中使用了CSS的类名。这违反了关注点分离的原则,让维护更容易出错。

让我们用一个不同的方法来实现

<button data-hook="nav-menu-toggle">Toggle Nav Menu</button>
<nav data-hook="nav-menu">
<ul>
<li><a href="/">West Philadelphia</a></li>
<li><a href="/cab">Cab Whistling</a></li>
<li><a href="/throne">Throne Sitting</a></li>
</ul>
</nav>

 

这次我们使用这个data属性(data-hook)来选择元素。任何对CSS类的改变将不会影响到javascript,让我们能够实现关注点分离以及更加稳定的代码。

下面我们用data-hook属性来选择对应的元素:

$('[data-hook="nav-menu-toggle"]').on('click',function(){
$('[data-hook="nav-menu"]').toggle();
});

 

需要注意的是,我也使用data-hook作为nav元素的选择器。你不一定需要,但是我喜欢这里面包含的思想:任何使用你看到data-hook,你会知道这个元素在javascript中引用到啦。

一些语法糖

我必须承认data-hook选择器并不是很漂亮。让我们通过扩展jQuery实现一个自定义的函数:

$.extend({
hook:function(hookName){
var selector;
if(!hookName || hookName === '*'){
// select all data-hooks
selector='[data-hook]'
}else{
// select specific data-hook
selector='[data-hook*="'+hookName+'"]';
}
return $(selector);
}
});

 

上面准备完毕,我们来重写一下javascript。

$.hook('nav-menu-toggle').on('',function(){
$.hook('nav-menu').toggle();
});

 

更好的是,我们甚至可以把一系列以空格分开的hook名字放在一个元素上。

<button data-hook="nav-menu-toggle video-pause click-track">Toggle Nav Menu</button>

 

我们可以找到里面的任意个hook名字:

$.hook('click-track'); // returns the button as expected

 

我们也能够找到页面上所有的hook元素

// both are equivalent
$.hook();
$.hook('*');

 

防止函数表达式

到目前为止,我们在事件处理中使用的都是匿名函数。让我们重写一下,使用声明的函数来代替它。

function toggleNavMenu(){
$.hook('nav-menu').toggle();
}

$.hook('nav-menu-toggle').on('click',toggleNavMenu);

 

这让事件绑定的代码更加易读。这个toggleNavMenu函数名表达了意图,是代码自我注释的好例子。

我们同时也获得了可复用的能力,因为其他地方可能需要使用toggleNavMenu函数。

最后,这对于自动化测试来说是意见大喜事,因为声明的函数的单元测试要比匿名函数单元测试容易的多。

同时使用多个事件

jQuery提供了一个简单方便的语法来处理多事件的问题。比如,你可以为一系列空格隔开的事件列表绑定同一个事件处理函数。

$.hook('nav-menu-toggle').on('click keydown mouseenter',trackAction);

 

如果你需要为不同的事件绑定不同的处理函数,你可以使用对象表达方式:

$.hook('nav-menu-toggle').on({
'click':trackClick,
'keydown':tranckKeyDown,
'mouseenter':trackMouseEnter
});

 

反过来,你可以同时取消多个事件的绑定:

// unbinds keydown and mouseenter
$.hook('nav-menu-toggle').off('keydown mouseenter');

// nuclear options:unbinds everything
$.hook('nav-menu-toggle').off();

 

你可以想象到的是,不小心的取消事件绑定可能会导致严重的我们不想要的副作用。继续看我们可以通过哪些技巧来减轻这个问题。

小心的取消事件绑定

一般情况下我们不会在一个元素的同一事件类型绑定多个事件处理函数。让我们再看一下之前的那个按钮:

<button data-hook="nav-menu-toggle video-pause click-track">Toggle Nav Menu</button>

 

不同的代码区域可能会在同一个元素的同一事件绑定不同的事件处理函数:

// somewhere in the nav code
$.hook('nav-menu-toggle').on('click',toggleNavMenu);

// somewhere in the video playback code
$.hook('video-pause').on('click',pauseCarltonDanceVideo);

// somewhere in the analytics code
$.hook('click-track').on('click',trackClick);
尽管我们使用了不同的选择器,但是这个元素现在有三个事件处理函数啦。假如我们的分析代码不在关心这个按钮:
// no good
$.hook('click-track').off('click');

 

糟糕的是,上面的代码实际上回删除所有的点击事件处理函数,不仅仅是trackClick。我们应该实用更加有辨别力的方式来指定我们需要删除的事件处理函数:

$.hook('click-track').off('click',trackClick);

 

另一种方式是使用命名空间。任何事件都有资格使用一个命名空间来实现绑定和取消绑定,这样你就可以更好的控制事件绑定和取消绑定。

// binds a click event in the "analytics" namespace
$.hook('click-track').on('click.analytics', trackClick);

// unbinds only click events in the "analytics" namespace
$.hook('click-track').off('click.analytics');

 

你也可以使用多个命名空间:

// binds a click event in both the "analytics" and "usability" namespaces
$.hook('click-track').on('click.analytics.usability',trackClick);

// unbinds any events in either the "analytics" OR "usability" namespaces
$.hook('click-track').off('.usability .analytics');

// unbinds any events in both the "analytics" AND "usability" namespaces
$.hook('click-track').off('.usability.analytics');

 

需要注意的是,命名空间的顺序是没有关系的,因为命名空间不是层级式的。

如果你有一个复杂的功能需要多个元素绑定多个事件,那么使用命名空间是一种简单的把他们组织起来然后快速清除的方式:

// free all elements on the page of any "analytics" event handling
$('*').off('.analytics');

 

命名空间在写插件的时候尤其有用,因为这样你就能保证只会取消自己命名空间范围内的事件处理函数的绑定。

原文:Effective Event Binding with jQuery

转载:http://segmentfault.com/u/wangfulin

By柏小白

如何让2个并列的div根据内容自动保持同等高度

最近在工作中碰到一个需求:

有左右2个并列的div,2个div都不能限定高度。左div为导航,右div为内容。如何能让左div块自动获得和右div块相等的高度?

同时,也有网友提问到“如果右块高度比左块低,会不会导致左块的内容被溢出不显示之类的问题。应该是取左右2者的最高值吧来对齐吧”。

的确应该是哪个div Height值大,就将其值赋给Height值小的div,从而使2个div高度始终保持一致。看代码:

function $(id){ 
	return document.getElementById(id) 
} 
function getHeight() { 
	if ($("left").offsetHeight>=$("right").offsetHeight){
		$("right").style.height=$("left").offsetHeight + "px";
	}
	else{
		$("left").style.height=$("right").offsetHeight + "px";
	}	
}
window.onload = function() {
	getHeight();
}

经测试,该代码有效。

另外,在实际运用,可能还会存在由于左div或右div存在padding属性而导致上述取值变多或变少的问题。比如,最终赋值时发现left比right还高10px,那么也可以通过修改上述代码解决:

$("left").style.height=$("right").offsetHeight-10 + "px";

 

By柏小白

Html5新标签解释及用法

HTML 5 是一个新的网络标准,目标在于取代现有的 HTML 4.01, XHTML 1.0 and DOM Level 2 HTML 标准。它希望能够减少浏览器对于需要插件的丰富性网络应用服务(plug-in-based rich internet application,RIA),如Adobe Flash, Microsoft Silverlight, 与 Sun JavaFX 的需求。

HTML 5 提供了一些新的元素和属性,反映典型的现代用法网站。其中有些是技术上类似 <div> 和 <span> 标签,但有一定含义,例如 <nav>(网站导航块)和 <footer>。这种标签将有利于搜索引擎的索引整理、小屏幕装置和视障人士使用。同时为其他浏览要素提供了新的功能,通过一个标准接口,如 <audio> 和 <video> 标记。

之前的一篇:HTML5 Shiv – 让该死的IE系列支持HTML5吧介绍了如何让所有浏览器都支持html5标签,你可以放心大胆的用了!

一些过时的 HTML 4 标记将取消,其中包括纯粹用作显示效果的标记,如 <font> 和 <center>,因为它们已经被 CSS 取代。还有一些透过 DOM 的网络行为(via)。

下面我们来看一下HTML 5提供的一些新的标签用法以及和HTML 4的区别。

<article>标签定义外部的内容。比如来自一个外部的新闻提供者的一篇新的文章,或者来自 blog 的文本,或者是来自论坛的文本。亦或是来自其他外部源内容。
HTML5:<article></article>
HTML4:<div></div>

<aside>标签定义 article 以外的内容。aside 的内容应该与 article 的内容相关。
HTML5:<aside>Aside 的内容是独立的内容,但应与文档内容相关。</aside>
HTML4:<div>Aside 的内容是独立的内容,但应与文档内容相关。</div>

<audio> 标签定义声音,比如音乐或其他音频流。
HTML5:<audio src="someaudio.wav">您的浏览器不支持 audio 标签。</audio>
HTML4:<object type="application/ogg" data="someaudio.wav"><param name="src" value="someaudio.wav"></object>

<canvas> 标签定义图形,比如图表和其他图像。这个 HTML 元素是为了客户端矢量图形而设计的。它自己没有行为,但却把一个绘图 API 展现给客户端 JavaScript 以使脚本能够把想绘制的东西都绘制到一块画布上。
HTML5:<canvas id="myCanvas" width="200" height="200"></canvas>
HTML4:<object data="inc/hdr.svg" type="image/svg+xml" width="200" height="200"></object>

<command> 标签定义命令按钮,比如单选按钮、复选框或按钮。
HTML5: <command onclick=cut()" label="cut">
HTML4: none

<datalist> 标签定义可选数据的列表。与 input 元素配合使用,就可以制作出输入值的下拉列表。
HTML5: <datalist></datalist>
HTML4: see combobox.

<details> 标签定义元素的细节,用户可进行查看,或通过点击进行隐藏。与 <legend> 一起使用,来制作 detail 的标题。该标题对用户是可见的,当在其上点击时可打开或关闭 detail。
HTML5: <details></details>
HTML4: <dl style="display:hidden"></dl>

<embed> 标签定义嵌入的内容,比如插件。
HTML5: <embed src="horse.wav" />
HTML4: <object data="flash.swf"  type="application/x-shockwave-flash"></object>

<figcaption> 标签定义 figure 元素的标题。”figcaption” 元素应该被置于 “figure” 元素的第一个或最后一个子元素的位置。
HTML5: <figure><figcaption>PRC</figcaption></figure>
HTML4: none

<figure> 标签用于对元素进行组合。使用 <figcaption> 元素为元素组添加标题。
HTML5: <figure><figcaption>PRC</figcaption><p>The People's Republic of China was born in 1949...</p></figure>
HTML4: <dl><h1>PRC</h1><p>The People's Republic of China was born in 1949...</p></dl>

<footer> 标签定义 section 或 document 的页脚。典型地,它会包含创作者的姓名、文档的创作日期以及/或者联系信息。
HTML5: <footer></footer>
HTML4: <div></div>

<header> 标签定义 section 或 document 的页眉。
HTML5: <header></header>
HTML4: <div></div>

<hgroup> 标签用于对网页或区段(section)的标题进行组合。
HTML5: <hgroup></hgroup>
HTML4: <div></div>

<keygen> 标签定义生成密钥。
HTML5: <keygen>
HTML4: none

<mark>主要用来在视觉上向用户呈现那些需要突出的文字。<mark>标签的一个比较典型的应用就是在搜索结果中向用户高亮显示搜索关键词。
HTML5: <mark></mark>
HTML4: <span></span>

<meter> 标签定义度量衡。仅用于已知最大和最小值的度量。必须定义度量的范围,既可以在元素的文本中,也可以在 min/max 属性中定义。
HTML5: <meter></meter>
HTML4: none

<nav> 标签定义导航链接的部分。
HTML5: <nav></nav>
HTML4:<ul></ul>

<output> 标签定义不同类型的输出,比如脚本的输出。
HTML5: <output></output>
HTML4: <span></span>

<progress> 标签运行中的进程。可以使用 <progress> 标签来显示 JavaScript 中耗费时间的函数的进程。
HTML5: <progress></progress>
HTML4: none

<rp> 标签在 ruby 注释中使用,以定义不支持 ruby 元素的浏览器所显示的内容。
HTML5: <ruby>漢 <rt><rp>(</rp>ㄏㄢˋ<rp>)</rp></rt></ruby>
HTML4: none

<rt> 标签定义字符(中文注音或字符)的解释或发音。
HTML5: <ruby>漢 <rt> ㄏㄢˋ </rt></ruby>
HTML4: none

<ruby> 标签定义 ruby 注释(中文注音或字符)。
HTML5: <ruby>漢 <rt><rp>(</rp>ㄏㄢˋ<rp>)</rp></rt></ruby>
HTML4: none

<section> 标签定义文档中的节(section、区段)。比如章节、页眉、页脚或文档中的其他部分。
HTML5: <section></section>
HTML4: <div></div>

<source> 标签为媒介元素(比如 <video> 和 <audio>)定义媒介资源。
HTML5: <source>
HTML4: <param>

<summary> 标签包含 details 元素的标题,”details” 元素用于描述有关文档或文档片段的详细信息。”summary” 元素应该是 “details” 元素的第一个子元素。
HTML5: <details><summary>HTML 5</summary>This document teaches you everything you have to learn about HTML 5.</details>
HTML4: none

<time> 标签定义日期或时间,或者两者。
HTML5: <time></time>
HTML4: <span></span>

<video> 标签定义视频,比如电影片段或其他视频流。
HTML5: <video src="movie.ogg" controls="controls">您的浏览器不支持 video 标签。</video>
HTML4:<object type="video/ogg" data="movie.ogv"><param name="src" value="movie.ogv"></object>

By柏小白

iframe背景透明设置方法

allowtransparency=”true”

如下:

<iframe width="100%" height="200" src="demo.html" allowTransparency="true" frameBorder="0" scrolling="no"></iframe>

 

By柏小白

针对IE的CSS hack 全面 实用

.all IE{property:value\9;}
.gte IE 8{property:value\0;}
.lte IE 7{*property:value;}
.IE 8/9{property:value\0;}
.IE 9{property:value\9\0;}
.IE 7{+property:value;}
.IE 6{_property:value;}
.not IE{property//:value;}

te:就是Less than or equal to的简写,也就是小于或等于的意思。

lt :就是Less than的简写,也就是小于的意思。

gte:就是Greater than or equal to的简写,也就是大于或等于的意思。

gt :就是Greater than的简写,也就是大于的意思。

!  :就是不等于的意思,跟javascript里的不等于判断符相同

By柏小白

CSS实现单行、多行文本溢出显示省略号(…)

如果实现单行文本的溢出显示省略号同学们应该都知道用text-overflow:ellipsis属性来,当然还需要加宽度width属来兼容部分浏览。

实现方法:

overflow: hidden;
text-overflow:ellipsis;
white-space: nowrap;

效果如图:
dome1

但是这个属性只支持单行文本的溢出显示省略号,如果我们要实现多行文本溢出显示省略号呢。

接下来重点说一说多行文本溢出显示省略号,如下。

实现方法:

display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
overflow: hidden;

效果如图:
dome2

适用范围:
因使用了WebKit的CSS扩展属性,该方法适用于WebKit浏览器及移动端;

注:

  1. -webkit-line-clamp用来限制在一个块元素显示的文本的行数。 为了实现该效果,它需要组合其他的WebKit属性。常见结合属性:
  2. display: -webkit-box; 必须结合的属性 ,将对象作为弹性伸缩盒子模型显示 。
  3. -webkit-box-orient 必须结合的属性 ,设置或检索伸缩盒对象的子元素的排列方式 。

实现方法:

p{position: relative; line-height: 20px; max-height: 40px;overflow: hidden;}
p::after{content: "..."; position: absolute; bottom: 0; right: 0; padding-left: 40px;
background: -webkit-linear-gradient(left, transparent, #fff 55%);
background: -o-linear-gradient(right, transparent, #fff 55%);
background: -moz-linear-gradient(right, transparent, #fff 55%);
background: linear-gradient(to right, transparent, #fff 55%);
}

效果如图:
dome3
适用范围:
该方法适用范围广,但文字未超出行的情况下也会出现省略号,可结合js优化该方法。

注:

  1. 将height设置为line-height的整数倍,防止超出的文字露出。
  2. 给p::after添加渐变背景可避免文字只显示一半。
  3. 由于ie6-7不显示content内容,所以要添加标签兼容ie6-7(如:<span>…<span/>);兼容ie8需要将::after替换成:after。

 

By柏小白

JS特效:类似QQ对话框上下部分可拖动代码

<!DOCTYPE html>
<html>
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
<title>例子</title>
<style>
ul,li{margin:0;padding:0;}
body{font:14px/1.5 Arial;color:#666;}
#box{position:relative;width:600px;height:400px;border:2px solid #000;margin:10px auto;overflow:hidden;}
#box ul{list-style-position:inside;margin:10px;}
#top{color:#FFF;overflow-x:hidden;overflow-y:auto;}
#bottom{color:#FFF;overflow-x:hidden;overflow-y:auto;}
#top{background:green;}
#bottom{background:blue;}
#line{position:absolute;bottom:100px;width:100%;height:4px;overflow:hidden;margin-top:-2px;background:red;cursor:n-resize;}
</style>
<script>
function $(id) {
    return document.getElementById(id)  
}
window.onload = function() {
    var oBox = $("box"), oTop = $("top"), oBottom = $("bottom"), oLine = $("line");
    oLine.onmousedown = function(e) {
        var disY = (e || event).clientY;
        oLine.top = oLine.offsetTop;
        document.onmousemove = function(e) {
            var iT = oLine.top + ((e || event).clientY - disY);
            var maxT = oBox.clientHeight - oLine.offsetHeight;
            oLine.style.margin = 0;
            iT < 0 && (iT = 0);
            iT > maxT && (iT = maxT);
            oLine.style.top = oTop.style.height = iT + "px";
            oBottom.style.height = oBox.clientHeight - iT + "px";
            return false
        };  
        document.onmouseup = function() {
            document.onmousemove = null;
            document.onmouseup = null;  
            oLine.releaseCapture && oLine.releaseCapture()
        };
        oLine.setCapture && oLine.setCapture();
        return false
    };
};
</script>
</head>
<body>
<center>上下拖动红条改变显示区域高度</center>
<div id="box">
    <div id="top" style="height:300px;">
        <ul>
            <li>西安一大厦发生爆炸7人遇难31人受伤</li>
            <li>意大利经济学家蒙蒂出任过渡政府总理</li>
            <li>天宫神八今晚分离后再对接 全程需半小时</li>
            <li>吉林骗子承包厨子施工铁路桥墩将爆破拆除</li>
            <li>胡锦涛:人民币升值无法解决美国问题</li>
            <li>红会否认通过民政部门索捐 称按工龄捐款属谣言</li>
            <li>昆明警车拒绝救助临产孕妇 市民称警察当时在玩游戏</li>
            <li>网帖称贫困县人社局80名员工公款赴港澳旅游</li>
            <li>云南师宗矿难副矿长承认用煤灰抹脸假装逃生</li>
            <li>中介操控卵子黑市 北大清华女生卖卵可得数万元</li>
            <li>云南一村庄户籍"不存在" 村民身份不明四处碰壁</li>
            <li>河北燕郊数千人陷传销 称发展下线可获利百万</li>
            <li>国际原子能机构出示图片证明伊朗研发核武器</li>
        </ul>
    </div>
    <div id="bottom" style="height:100px;">
        <ul>
            <li>京沪高铁因质量问题被召回动车拟16日恢复运营</li>
            <li>黑龙江穆棱河污染致数万人饮水难近10年</li>
            <li>湖南政府采购买高不买低 琴行老板揭招标内幕</li>
        </ul>
    </div>
    <div id="line"></div>
</div>
</body>
</html>

 





例子




上下拖动红条改变显示区域高度

  • 西安一大厦发生爆炸7人遇难31人受伤
  • 意大利经济学家蒙蒂出任过渡政府总理
  • 天宫神八今晚分离后再对接 全程需半小时
  • 吉林骗子承包厨子施工铁路桥墩将爆破拆除
  • 胡锦涛:人民币升值无法解决美国问题
  • 红会否认通过民政部门索捐 称按工龄捐款属谣言
  • 昆明警车拒绝救助临产孕妇 市民称警察当时在玩游戏
  • 网帖称贫困县人社局80名员工公款赴港澳旅游
  • 云南师宗矿难副矿长承认用煤灰抹脸假装逃生
  • 中介操控卵子黑市 北大清华女生卖卵可得数万元
  • 云南一村庄户籍”不存在” 村民身份不明四处碰壁
  • 河北燕郊数千人陷传销 称发展下线可获利百万
  • 国际原子能机构出示图片证明伊朗研发核武器
  • 京沪高铁因质量问题被召回动车拟16日恢复运营
  • 黑龙江穆棱河污染致数万人饮水难近10年
  • 湖南政府采购买高不买低 琴行老板揭招标内幕


By柏小白

手机网站前端开发布局技巧

在 此所说的移动平台前端开发是指针对高端智能手机(如Iphone、Android)做站点适配也就是WebApp,并非是针对普通手机开发Wap 2.0,所以在阅读本篇文章以前,你需要对webkit内核的浏览器有一定的了解,你需要对HTML5和CSS3有一定的了解。如果你已经对此有所了解, 那现在就开始往下阅读吧……

1、首先我们来看看webkit内核中的一些私有的meta标签,这些meta标签在开发webapp时起到非常重要的作用

<meta content=”width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0;” name=”viewport” />
<meta content=”yes” name=”apple-mobile-web-app-capable” />
<meta content=”black” name=”apple-mobile-web-app-status-bar-style” />
<meta content=”telephone=no” name=”format-detection” />

第一个meta标签表示:强制让文档的宽度与设备的宽度保持1:1,并且文档最大的宽度比例是1.0,且不允许用户点击屏幕放大浏览;
第二个meta标签是iphone设备中的safari私有meta标签,它表示:允许全屏模式浏览;
第三个meta标签也是iphone的私有标签,它指定的iphone中safari顶端的状态条的样式;
第四个meta标签表示:告诉设备忽略将页面中的数字识别为电话号码

2、HTML5标签的使用
在开始编写webapp时,哥建议前端工程师使用HTML5,而放弃HTML4,因为HTML5可以实现一些HTML4中无法实现的丰富的WEB应 用程序 的体验,可以减少开发者很多的工作量,当然了你决定使用HTML5前,一定要对此非常熟悉,要知道HTML5的新标签的作用。比如定义一块内容或文章区域 可使用section标签,定义导航条或选项卡可以直接使用nav标签等等。

3、放弃CSS float属性
在项目开发过程中可以会遇到内容排列排列显示的布局(见下图),假如你遇见这样的视觉稿,哥建议你放弃float,可以直接使用display:block;

4、利用CSS3边框背景属性
看看这样一个按钮
这个按钮有圆角效果,有内发光效果还有高光效果,这样的按钮使用CSS3写是无法写出来的,当然圆角可以使用CSS3来写,但高光和内发光却无法使用CSS3编写,
这个时候你不妨使用-webkit-border-image来定义这个按钮的样式。
-webkit-border-image就个很复杂的样式属性,你一开始可以无法快速理解,建议你阅读一篇关于border-image的文章

5、块级化a标签
请保证将每条数据都放在一个a标签中,为何这样做?因为在触控手机上,为提升用户体验,尽可能的保证用户的可点击区域较大。

6、自适应布局模式
在编写CSS时,我不建议前端工程师把容器(不管是外层容器还是内层)的宽度定死。为达到适配各种手持设备,我建议前端工程师使用自适应布局模式 (支付宝 采用了自适应布局模式),因为这样做可以让你的页面在ipad、itouch、ipod、iphone、android、web safarik、chrome都能够正常的显示,你无需再次考虑设备的分辨率。

By柏小白

使用sessionStorage、localStorage存储数组与对象

有时候,我们需要将数据存储到sessionStorage和localStorage中,这样做的好处有:

1 缓存数据

2 减少对内存的占用

但是,storage只能存储字符串的数据,对于JS中常用的数组或对象却不能直接存储。

var obj = { name:'Jim' };
sessionStorage.obj = obj;
localStorage.obj = obj;
 
var arr = [1,2,3];
sessionStorage.obj = arr;
localStorage.obj = arr;

上面的写法都是不能成功的!但我们可以通过JSON对象提供的parse和stringify将其他数据类型转化成字符串,再存储到storage中就可以了。请看下面的代码。

var obj = { name:'Jim' };
var str = JSON.stringify(obj);
 
//存入
sessionStorage.obj = str;
//读取
str = sessionStorage.obj;
//重新转换为对象
obj = JSON.parse(str);

localStorage也一样,只是和sessionStorage的存储时间不一样。
需要注意的是,JS中的数组本质上也是对象类型,所以上面的代码对数组也是适用的。

By柏小白

js判断上传图片类型 以及图片文件大小,和高度宽度尺寸大小控制

js判断上传图片类型 以及图片文件大小,和高度宽度尺寸大小控制:

/* 
 * 判断图片类型 
 *  
 * @param ths  
 *          type="file"的javascript对象 
 * @return true-符合要求,false-不符合 
 */ 
function checkImgType(ths){  
    if (ths.value == "") {  
        alert("请上传图片");  
        return false;  
    } else {  
        if (!/\.(gif|jpg|jpeg|png|GIF|JPG|PNG)$/.test(ths.value)) {  
            alert("图片类型必须是.gif,jpeg,jpg,png中的一种");  
            ths.value = "";  
            return false;  
        }  
 
         else
        {
             var img=new Image(); 
             img.src=filepath;   
          while(true){ 
                 if(img.fileSize>0){ 
                 if(img.fileSize>10*1024){       
                     alert("图片不大于10M。"); 
                      return false; 
                      } 
                      break; 
                     } 
 
                  }
          }
    }  
    return true;  
}  
 
/* 
 * 判断图片大小 
 *  
 * @param ths  
 *          type="file"的javascript对象 
 * @param width 
 *          需要符合的宽  
 * @param height 
 *          需要符合的高 
 * @return true-符合要求,false-不符合 
 */ 
function checkImgPX(ths, width, height) {  
    var img = null;  
    img = document.createElement("img");  
    document.body.insertAdjacentElement("beforeEnd", img); // firefox不行  
    img.style.visibility = "hidden";   
    img.src = ths.value;  
    var imgwidth = img.offsetWidth;  
    var imgheight = img.offsetHeight;  
       
    alert(imgwidth + "," + imgheight);  
       
    if(imgwidth != width || imgheight != height) {  
        alert("图的尺寸应该是" + width + "x"+ height);  
        ths.value = "";  
        return false;  
    }  
    return true;  
}

 

By柏小白

jquery操作select(取值,设置选中)

每一次操作select的时候,总是要出来翻一下资料,不如自己总结一下,以后就翻这里了。

比如

<select class="selector"></select>

1、设置value为pxx的项选中

	
$(".selector").val("pxx");

2、设置text为pxx的项选中

$(".selector").find("option[text='pxx']").attr("selected",true);

这里有一个中括号的用法,中括号里的等号的前面是属性名称,不用加引号。很多时候,中括号的运用可以使得逻辑变得很简单。

3、获取当前选中项的value

$(".selector").val();

4、获取当前选中项的text

$(".selector").find("option:selected").text();

这里用到了冒号,掌握它的用法并举一反三也会让代码变得简洁。

很多时候用到select的级联,即第二个select的值随着第一个select选中的值变化。这在jquery中是非常简单的。

如:

By柏小白

超酷的固定菜单页面滚动效果

<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>演示:超酷的页面滚动效果</title>
<style type="text/css">
.nav{width:50px; /*position:fixed; right:5px;*/ position:fixed; margin-left:920px; top:30%; z-index:1999; background:#f0f0f0; border: 1px solid #ccc;
  -webkit-border-radius: 6px;-moz-border-radius: 6px;border-radius: 6px;
  -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);-moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);}
.nav li{height:50px; line-height:50px; border-bottom:1px solid #d3d3d3; background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAEECAYAAABqa2e1AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAABZ0RVh0Q3JlYXRpb24gVGltZQAwNC8xMi8xM/3pQrMAAAAYdEVYdFNvZnR3YXJlAEFkb2JlIEZpcmV3b3Jrc0+zH04AAA1QSURBVHic7Z1rbBzFAcd/M3e+5OwzTnxxnqSJMUmBJBZKUkhpWslNKG0JIRKqFEAW6gPUiqoBBaiEQK1UtUKofGgbIT60qQgtbYWgiEiBtiEqtMJQo0ohUGKS5oVKXrYT++yz77XTD7MX2/Gdfbs7S0bR/qVTovPuzvxu3jP/nRFKKS4HyUsdAVOKQGxTBGKbIhDbFIHYpgjENsVNPEQIMd0lXwA+BPor/dFEf88IyDTaAmySUp6bM2fOz8+cOXMaeAaYASggBtwTNJAws5YEvglsBM45jhPv7+9/ZOHChYuBAaDX/QwAc4IGJkwka4WslQDuAz4LDAF5NFi9lDLnOI4CCu619UqpJ9FQvhVG1koB9wMLgQw6wgooAVnHcSTgmA7UNEgzsA1oQqdEEQ1RVsn9GJdJkAXAg+4zyxCfmkwV9mXAI+gaKIs3CLV69errg0YgcGEXQlwPfAcYBUbwnnUSQFNTU9PL58+f/5vveAQBEUJ8EbgTGEZD+CnEApgJNDY2Nr42ODj4iq+4+AURQmwGvoqumXIEq4kEuoFsTKVSf89kMi94foAfECFEJ3AjulDnmFgz+VUZJtXQ0NA9NDT0rKebvYAIIeLAvcB1jDV0JifGBLrMpOrr6w9ks9lfK6VqSmm/WasR/evphwjxAwJkLSllsVQqPVPhT6PoH2xa+W1HMu6nrDp0FvOrOnTK9vl9gKl2JHaJ7798BlYRiBfF4/GRsMMIG0QsWrTo/UKh8JslS5Z0o6vXUBQ2SOyhhx56Fxg5fvz4W4Q4tA51zC6lVA888MAQuh82TEhjEQg5RaSUeUAJIcqNpfGR4YWwwnowIBzHmcnELkzg9qJqYKYmH5RS1WZClBDiQoutlEpTudAHatnDmkXxJBNxuGwaRL/jkWcJsQYCYkopT7OPfqvfAXQXOyzNRM8+1jxp5xdkFD1bYo2CFPbA87U1qOYUMVJr2aDLptaKQGxTBGKbIhDbFIHYpgjENkUgtikCsU0RiG2KQGxTBGKbAq+PTDPvmwJa3P+fA85ffIGpWRzTCz31wFpgNXCt+/zymkg59T8E3gPeBgZNBWzC5gTadvE14CvoCOfQnq0SY+sjwv1bnXu9iMVib5VKpReVUoFnLU2AzEHb/5rRS2wFNITDZJ9KGSaGBkpKKUcTicQvR0ZGTgSKR0C/1jLge24EyxC1PlCgs15SSjkzlUr9dmBgoNtvXHzXWkKIFuC76F++qlMolUp9kkqlPqnwiLJldthxnOGhoaF72tralvuNjy8Q1+50vxuZavY/uWXLlpczmcxLmUzmT3fcccfvq4RXAkYcxxk5ceLEfR0dHbN8xcnnQs8taPfcEFUWfJLJ5GA2m90FDAghCgBSym2O48yu8lgJNLS0tPznzJkzO/HoA/OcIkKIemADUxsxRS6XawaKZQgAx3EaqO5+cIDRs2fPrtq8efNSr/Hyk7XWufdNaYl1HCfR3Ny8Fd221KN98tVSo6wikO/u7v4SHpeyPWctIcSD6NY6P82ldUADGgL0CtcwY574qvfF43EKhcLP3OtrkqcUEUJItOe9loXQUmtr676lS5fuWbp06Z7W1tZ9td5XLBZnPv7443O9xM1rF6W83FaLFSN25MiRtxi31iiEuLGGex2g2NXVNR84XmNYnkEaqdxiV322ECJ70XfTZS0Ap7+/vx5dTmoC8VrYBd5a7lq+m0o1x88rSE3WVRO64oorPHUkvYL0YtawXFU33HCDp7A8gSilisD/vEbKq+Lx+MiTTz55Dg82ET8NYo/P+2qVaG5uPoYu5KGCvEOITjggduutt77L9A3uBHkGUUoNxmKxsByjIp1OH965c+cZPJp2fGWRUqm0V0pp3MsrpSzee++9/2RsqFyzfI8Q6+vrr8zlct9yX8erpBnALMbeasihZ1GqvgzQ0dHx6r59+w6713nygwUa6jY3N7cPDAxsqQJTnmgo92JL6Fa9UvlSK1eu7Dpw4MC/0TMrnspHOTDf6u/vf6+tre138Xi8Un520L9+1v1UfH1JSlnasGHDHheiPGT2rMDV6KFDh46sX7/+mZaWlg/w1liKdDp9+NFHH31+7969R9Ap4duVZ2peC6WUvPPOOxe9/fbbq0+ePHlVLpdrqnR9PB4fnj9//n9vvvnmg27tVE61QB5JYyBlKaViwIyHH3543tmzZ+t7enpm5XK5eHt7e286nS489dRT/YxlO8+1U9V4mAYZLxdKoAu8wH13VwhRGndNoPAvxCOyAlqmCMQ2RSC2KQKxTRGIbYpAbFMEYpsiENsUgdimCMQ2RSC2ybQVsAH4IbAY70t0nl80Hi+TVsAGYDt6/zk/a42eXzQeL1MgZYjZ6D2FioDctGnTy0qpKReEDh06NPejjz5aFzQCJkDGQwwzNgUa37179wn0K+NVtWDBgmXoLUIDKRCIEKIaBLjrIuNtTlXkcCk3QZoGAmpfYzSyFhmk+l2KdpZWgvjUFQSkvDRwySEgeGF3qFI7lUqlT7WxNVFr1VQ7hS0TILXWTqHKRPKHtmeWF102ncYIxDZFILYpArFNEYhtikBsUwRim0x049XGjRuXAfP93AssMhAHIyCl119//S70a6te5aB9jMMEnEkxAVJEGyv9ZlMjJ2AEddDVoadITcrXlGlkBbRNEYhtikBsUwRimyIQ2xSB2KYIxDZFILYpArFNEYhtikBsU2AQIcRUny8LIXa5/1a8xpTCTpFNQL+U8jal1MwwAwoT5Dr03G7GcRyno6Mj8EmtUylMkGvQOwqUgEJPT0+bUqourMDCBLmasTnd0rlz55bgb6K7JoUF0oJeZrgAMjo6OmfHjh2m54kvKCyQa5m4UYUDFJ9++unrp7PP+lVYIIuZvFRQ7O3tXcC4Q1NNKiyQVUwGcQYGBpYQ0ol/YYBcx8RdZcty8vl8w0033XRdCGHWvj4ihJiL3qLwGqr73ss7aVbbpGUGevu3JNWddwI4COxQStW8K6CXZF4CXMnUBn6FzlLVLLQFNOQwU4NcuXbt2hVA9xRhTZAXkA+klIcdx2mu9eEV5DD9TjQimUye2r59+0lq33zP89KbaG1tveXYsWOfJ5wt3MTy5cvf6enp+Rc6VQdqDcdrYVdHjx59bc2aNbuSyaTvQxgrKZlM9nV2dr7gQgyjd3Sq+ccKshgab21t3WggdS5OhSF82NSDVL/FoKlTJRV8ee2NbLmjlIoLIX6Et4X/mFLqFwRIhfEy0iAKIWahzQNeFN+6desiAqTCeJlq2df6uEe8+eabKzHUZTEFciXetzws9fX1XYOhTqQJkAZgJd6NMaV8Pl9/++23txmIgxGQtejWelKKJJPJvscee+y5dDp9lMldEgcodHd3r8LEi50Gaq27gRVM7HqIefPmfXjq1Km96IKcaWlp+Xpvb+9aJrY5dYlEwsnlck/gYdvoSjKRIhePPcTy5cvfcSFGhRDnhRCl3t7e3YsXL97rHqxdVimfz9evWrXqc0EjEQhECHHx2EO0t7e/UW7ghBAT9gf++OOP/7FixYo/joNxgPzp06fbCFjog6bIYtx95aSU+c7Ozhf279//HjAkhKi4ReiBAweObNq06VfjegOlbDZ7Bd7boYlSSvn+AHOklD9OpVL3dXZ2rlRKpZVSNRVcpZSYN2/eZuCnV1999e1KqaYgcTHhoIuh9ywt4u/lygb0iHEYPbr0pcgKaJsiENsUgdimCMQ2RSC2KQKxTRGIbYpAbFMEYpsiENsUgdimywYkzJOOn2VsTlgCLwK7L77I1HRUmCkygHZJ9AL9V111VUIplQwrsFCcOq5GGTsLsU4IEeYhXpdPGYlAbFMEYpsuG5Cge5nOBSqdfzvppNfBwcFZy5Ytu5aLjGdug3rUi+2vYlwCns/eADzBZId1Hr1dbjnSMfSJx0kmbhsiEonE67lc7iXctUjfcQnaRUgmk0vy+fy3HccZv5hZPibzwmovGkAyZhwQc+fO/eD06dOvopfcLl2KgM4a6XT6mr6+vrvw4EdJJpP92Wz2eXQPIPAxt0YKe19f38HGxsbXqHHzyWQy2b9z584/M+bVCixjtVYmk3mrqanpTaaBkVIWtm3btmfr1q0ZDO5/avzQulQq9Y2hoaGVVCi4Usr83Xff/cquXbtOAueFECVrDq2rNB6pq6v7fqFQmHPR13LdunV/6erqOggMCCGKYPl4pFAo7JwxY8Z4w6Zob29/o6urqwdt7zC+2XFYLXs2kUj8QUpZQFueDu7fv38/GqLqKa5BFOrBjrNnz/5MIpFYf+rUqb+iLU+TaihrykgNiqN36Q/1SHRfIG4f60YApdSkCQUfz/sy2lxzVCn1vp9n+C0jLeiXJW9D95+C6nrg1lmzZrXh07flt/froDuFEmioZjKrRW6OyAND6XRa4uFVi/EK0o0vAAghfkIAG5+7KfggPiI/XkGngwpoS3iQHf0c3NMxgkTExAb4ptqFQJ5GvyDH58+f/9yaNWuMzRwqpcSKFSt8dyKDtCOCcGYqy4MyT4o8jbYpArFNEYhtikBsUwRimyIQ2/R/UXHpI1TPp5AAAAAASUVORK5CYII=) no-repeat; text-align:center; cursor:pointer}
.nav li:hover{background-color:#f9f9f9; text-decoration:none}
.nav li:last-child{border-bottom:none}
.nav li.cur{background-color:#ffc}
.nav li.pro{background-position:0 0}
.nav li.news{background-position:0 -55px}
.nav li.ser{background-position:0 -105px}
.nav li.con{background-position:0 -155px}
.nav li.job{background-position:0 -207px}
.box{height:500px; margin: 0 10px}
.box h3{height:32px; line-height:32px; padding-left:20px; font-size:14px}
.box p{line-height:30px; margin:20px; text-align:center; font-size:28px}
.box p span{margin:10px}

</style>
<script src="http://code.jquery.com/jquery-1.7.min.js"></script>
<!-- <script type="text/javascript" src="jquery.easing.min.js"></script> -->
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/jquery-easing/1.3/jquery.easing.min.js"></script>

<script type="text/javascript">
$(function(){
    navpos();
    
    var pro_top = $("#pro").offset().top;
    var news_top = $("#news").offset().top;
    var ser_top = $("#ser").offset().top;
    var con_top = $("#con").offset().top;
    var job_top = $("#job").offset().top;
    //alert(tops);
    $(window).scroll(function(){
        var scroH = $(this).scrollTop();
        if(scroH>=job_top){
            set_cur(".job");
        }else if(scroH>=con_top){
            set_cur(".con");
        }else if(scroH>=ser_top){
            set_cur(".ser");
        }else if(scroH>=news_top){
            set_cur(".news");
        }else if(scroH>=pro_top){
            set_cur(".pro");
        }
    });
    
    $(".nav li").click(function() {
        var el = $(this).attr('class');
        $('html, body').animate({
            scrollTop: $("#"+el).offset().top
            },{
            easing: 'easeOutSine',
            duration: 300,
            complete:function(){
            }
        });
    });
});
$(window).resize(function(){
  navpos();
});
function navpos(){
    var page_w = $(document).width();
    var offset = $("#main").offset().left;
    var main_w = $("#main").outerWidth();
    var right = page_w-offset-main_w-50;
    //alert(right);
    if(right>10){
        $(".nav").css('right',right-10);
    }else{
        $(".nav").css('right',10);
    }
}
function set_cur(n){
    if($(".nav li").hasClass("cur")){
        $(".nav li").removeClass("cur");
    }
    $(".nav li"+n).addClass("cur");
}
</script>
</head>
 
<body>
 
<div id="main">
  <ul class="nav">
    <li class="pro"></li>
    <li class="news"></li>
    <li class="ser"></li>
    <li class="con"></li>
    <li class="job"></li>
</ul>
     <div id="pro" class="box">
        <h3>产品展示</h3>
        
        <br/>
       
     </div>
     <div id="news" class="box">
        <h3>新闻中心</h3>
     </div>
     <div id="ser" class="box">
        <h3>服务支持</h3>
       
     </div>
     <div id="con" class="box">
        <h3>联系我们</h3>
     </div>
     <div id="job" class="box" style="height:680px">
        <h3>人才招聘</h3>
     </div>
</div>
</body>
</html>

 





演示:超酷的页面滚动效果




产品展示

新闻中心

服务支持

联系我们

人才招聘


By柏小白

javaScript & jquery完美判断图片是否加载完毕

好久没写东西了,正好最近因为工作需要,写了一个瀑布流异步加载的程序。

今天就不谈瀑布流,来谈一下关于load的问题。

————————————————————-

众所周知,常见瀑布流当鼠标滚动到浏览器底部的时候,就会发起一个ajax的请求。在服务端生成item列表后,通过 js append到相应的div里边。

看起来很简单的样子,关键问题就出在图片的加载问题上,图片一般都放在服务器上,通过http下载到客户端。

例如我的图片地址:

http://xxx.xxx.com/sc/item/cover/9-4352-c400.jpg

而图片下载到本地是需要一定时间的(网速快的路过)。当图片还没有下载完的时候,使用js获取到元素的宽高将会是0。

——————————————————————-

有的同学说了我使用jquery的ready不就好了。如下:

$(document).ready(function(){
  // 在这里写你的代码...
});

如果这么简单就好了,我这里就说下ready与window.onload的区别。

jquery的ready只是dom的结构加载完毕,便视为加载完成。(缺点是图片没有加载完毕,宽高为0,程序出错)

js的window.onload是指dom的生成和资源的加载,比如flash、图片完全加载出来后才执行onload。(缺点就是当某一张图片很大的时候,岂不阻止了其它js的正常执行)

————————————————————————————-

知道了他们的区别后,我们再来谈谈如何避免错误和选择性使用。

如果你进行了百度,很多人会告诉你。

这样:

$('img').load(function(){
  // 加载完成    
});

好像很强大的样子,其实不然,他的缺点是每加载一张图片,回调函数就执行一次。好吧太烦了,我只想全部加载完走一次就可以了。当然可以,你可以进行修改如下:

va imgNum=$('img').length;
$('img').load(function(){
    if(!--imgNum){
        // 加载完成
    }
});

这样总可以了吧,我加载一张,就用图片总数去减一,减到0我就加载完毕。看起来很完美,前提是你没遇到IE。

IE的图片总是从缓存文件里去拿,这就造成load方法根本就不执行,只有是新图片才会走load。

服了吧?继续往下看。

—————————————————————

或者是这样:

document.getElementById('img').onload=function(){
        // 加载完成 
};

看我原生代码一统天下,实际上效果甚微,一次只能处理一个你准备写多少个document,有人说我可以用循环去绑定,经过我测试貌似根本没效果。

还是一笑而过吧。看看我的最终解决方案(兼容:谷歌&火狐&IE)

————————————————————-

利用图片没有加载完成的时候,宽高为0。我们很容易判断图片的一个加载情况。如下:

var t_img; // 定时器
var isLoad = true; // 控制变量
 
// 判断图片加载状况,加载完成后回调
isImgLoad(function(){
    // 加载完成
});
 
// 判断图片加载的函数
function isImgLoad(callback){
    // 注意我的图片类名都是cover,因为我只需要处理cover。其它图片可以不管。
    // 查找所有封面图,迭代处理
    $('.cover').each(function(){
        // 找到为0就将isLoad设为false,并退出each
        if(this.height === 0){
            isLoad = false;
            return false;
        }
    });
    // 为true,没有发现为0的。加载完毕
    if(isLoad){
        clearTimeout(t_img); // 清除定时器
        // 回调函数
        callback();
    // 为false,因为找到了没有加载完成的图,将调用定时器递归
    }else{
        isLoad = true;
        t_img = setTimeout(function(){
            isImgLoad(callback); // 递归扫描
        },500); // 我这里设置的是500毫秒就扫描一次,可以自己调整
    }
}

 

By柏小白

更换网页背景的jquery代码(写入cookie)

<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="UTF-8" />
    <title>更换网页背景的jquery代码(写入cookie)</title>

<style type="text/css">
    body,p,ul{margin:0;padding:0;}
    ul{float:right;height:40px;margin-top:20px;margin-right:20px;}
    ul li{list-style-type:none;float:left;width:20px;height:20px;margin-left:10px;cursor:pointer;}
    .skin{height:40px;position:fixed;background:#fff;border-bottom:solid 1px #cccc;top:0;left:0;width:100%;}
    .red{background:#F06;}/*红色*/
    .black{background:#000;}/*黑色*/
    .blue{background:#09F;}/*蓝色*/
    .green{background:#093;}/*绿色*/
</style>
<script type="text/javascript" src="http://ajax.useso.com/ajax/libs/jquery/1.7.2/jquery.min.js?ver=3.4.2"></script>
<script type="text/javascript">
    $(document).ready(function(){
            //为了安全 google chrome 等浏览器是禁止本地文件写Cookie的即file:///F:/Lord%20community/lrtk/Untitled-2.html这样的以file开头的是不能写本地文件的
            var cookieClass = getCookie('class');//读取需要缓存的对象。
            $("body").attr("class",cookieClass);//
            $(".skin_list li").each(function(){
                    $(this).click(function(){                          
                            var className=$(this).attr("class");//保存当前选择的类名
                            $("body").attr("class",className,30);//把选中的类名给body
                            function SetCookie(name,value,day)//两个参数,一个是cookie的名子,一个是值
                            {
                                var exp  = new Date();    //new Date("December 31, 9998");
                                exp.setTime(exp.getTime() + day*24*60*60*1000);
                                document.cookie = name + "="+ escape (value) + ";expires=" + exp.toGMTString();
                            }
                            SetCookie("class",className,30);
                    })
                });
            });
            function getCookie(name)//取cookies函数       
            {
                var nameEQ = name + "=";
                var ca = document.cookie.split(';');
                for(var i=0;i < ca.length;i++) {
                    var c = ca[i];
                    while (c.charAt(0)==' ') c = c.substring(1,c.length);
                    if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
                }
                return null;
            }
</script>
</head>
                                
<body>
<div class="skin"><ul class="skin_list"><li style="width:100px;text-align:right;">更换背景:</li></li><li class="red"></li><li class="black"></li><li class="blue"></li><li class="green"></li></ul></div>
 
</body>
</html>

 





更换网页背景的jquery代码(写入cookie)



  • 更换背景:


By柏小白

jquery批量链接设置新窗口打开

//方法一
$("a[href^='http://']").click(function(){
 this.target = "_blank";
});
//方法二
$(function(){
  $("a[href^='http://']").attr({'target':'_blank'})
})

 

By柏小白

使用jQuery判断元素是否存在

使用传统javascript方法,如下:

if(document.getElementById('div')) {     
    // 找到到对应元素 
} else {     
    // 没有找到找到到对应元素 
}

使用jQuery则比较简单,只需判断此元素的长度是否为0,如果为0则此元素不存在,代码如下:

if ($("#div").length > 0){ 
    // 找到对应id=div的元素,然后执行此块代码 
}

甚至能找到组合元素,如下,我们找一个id定义为div的元素里面是否包含img,代码如下:

if ($("#div img").length > 0){ 
    // 找到对应id=div并且包含img的元素,然后执行此块代码 
}

 

By柏小白

判断safari_判断IE_判断firefox_判断Opera—JS判断浏览器

JS

//----------------------------- 判断浏览器 -------------------------  
function myBrowser(){  
var userAgent = navigator.userAgent; //取得浏览器的userAgent字符串  
var isOpera = userAgent.indexOf("Opera") > -1; //判断是否Opera  
var isMaxthon = userAgent.indexOf("Maxthon") > -1 ; //判断是否傲游3.0  
var isIE = userAgent.indexOf("compatible") > -1 && userAgent.indexOf("MSIE") > -1 && !isOpera ; //判断是否IE   
var isFF = userAgent.indexOf("Firefox") > -1 ; //判断是否Firefox  
var isSafari = userAgent.indexOf("Safari") > -1 && userAgent.indexOf("Chrome") < 1 ; //判断是否Safari  
var isChrome = userAgent.indexOf("Chrome") > -1 ; //判断是否Chrome  
  
if(isIE){   
   var IE5 = IE55 = IE6 = IE7 = IE8 = false;  
   var reIE = new RegExp("MSIE (+);");  
   reIE.test(userAgent);  
   var fIEVersion = parseFloat(RegExp["$1"]);  
  
   IE55 = fIEVersion == 5.5 ;  
   IE6 = fIEVersion == 6.0 ;  
   IE7 = fIEVersion == 7.0 ;  
   IE8 = fIEVersion == 8.0 ;  
  
   if(IE55){ return "IE55"; }  
   if(IE6){ return "IE6"; }  
   if(IE7){ return "IE7"; }  
   if(IE8){ return "IE8"; }  
}  
  
if(isFF){ return "FF"; }  
if(isOpera){ return "Opera"; }  
if(isMaxthon){ return "Maxthon"; }  
if(isSafari){ return "Safari"; }  
if(isChrome){ return "Chrome"; }  
  
} //myBrowser() end  
  
  
window.onload=function(){  
  
document.getElementById("ua").innerHTML=navigator.userAgent;  
  
if(myBrowser()=="FF"){alert("我是 Firefox");}  
if(myBrowser()=="Maxthon"){alert("我是傲游(webkit核心)");}  
if(myBrowser()=="Opera"){alert("我是 Opera");}  
if(myBrowser()=="Safari"){alert("我是 Safari");}  
if(myBrowser()=="Chrome"){alert("我是 Chrome");}  
if(myBrowser().indexOf("IE")>-1){alert("我是 IE");}   
if(myBrowser()=="IE55"){alert("我是 IE5.5");}  
if(myBrowser()=="IE6"){alert("我是 IE6");}  
if(myBrowser()=="IE7"){alert("我是 IE7");}  
if(myBrowser()=="IE8"){alert("我是 IE8");}  
}

Jquery判断浏览器版本:

$.browser.msie; 
if ($.browser.webkit) { alert( "this is webkit!" ); }
if ($.browser.safari) { alert( "this is safari" ); }
var ua = $.browser; if ( ua.mozilla && ua.version.slice(0,3) == "1.9" ) { alert( "Do stuff for firefox 3" ); }
if ( $.browser.msie ) { $("#div ul li").css( "display","inline" ); } else { $("#div ul li").css( "display","inline-table" ); }

 

By柏小白

图片垂直居中的使用技巧

当然出题并不是随意,而是有其现实的原因,垂直居中是 淘宝 工作中最常遇到的一个问题,很有代表性。

题目的难点在于两点:
1.垂直居中;
2.图片是个置换元素,有些特殊的特性。

至于如何解决,下面是一个权衡的相对结构干净,CSS简单的解决方法:

.box {
/*非IE的主流浏览器识别的垂直居中的方法*/
display: table-cell;
vertical-align:middle;
/*设置水平居中*/
text-align:center;
/* 针对IE的Hack */
*display: block;
*font-size: 175px;/*约为高度的0.873,200*0.873 约为175*/
*font-family:Arial;/*防止非utf-8引起的hack失效问题,如gbk编码*/
width:200px;
height:200px;
border: 1px solid #eee;}
.box img {
/*设置图片垂直居中*/
vertical-align:middle;}<div class="box">
<img src="http://pics.taobao.com/bao/album/promotion/taoscars_180x95_071112_sr.jpg" /></div>

 

By柏小白

支持 Firefox、Chrome 等主流浏览器的全站变灰 CSS 代码

cccc

 

html{
-webkit-filter: grayscale(100%);
-moz-filter: grayscale(100%);
-ms-filter: grayscale(100%);
-o-filter: grayscale(100%);
filter: grayscale(100%);
filter: url("data:image/svg+xml;utf8,<svg xmlns=\'http://www.w3.org/2000/svg\'><filter id=\'grayscale\'><feColorMatrix type=\'matrix\' values=\'0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0 0 0 1 0\'/></filter></svg>#grayscale");
filter: progid:DXImageTransform.Microsoft.BasicImage(grayscale=1);
}

 

 

 

By柏小白

如何让未知尺寸的图片在已知宽高的容器内水平垂直居中?

<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="UTF-8">
    <title>已知宽高的容器内水平垂直居中?</title>
    <style>

.test{display:table-cell;*display:block;*position:relative;width:200px;height:400px;text-align:center;vertical-align:middle; background:#58d0fe;}
.test p{*position:absolute;*top:50%;*left:50%;margin:0;}
.test p img{*position:relative;*top:-50%;*left:-50%;vertical-align:middle;}

    </style>
</head>
<body>
    <div class="test">
        <p>
            
            <img src="" alt="">
        </p>

    </div>
</body>
</html>

 





已知宽高的容器内水平垂直居中?


柏小白家臭小子



By柏小白

纯CSS3实现的Android Logo

 

html

<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="UTF-8">
    <title>纯CSS3实现的Android Logo</title>
   
</head>
<body>
    <div class="android">
        <div class="head">
            <div class="l_ant"></div>
            <div class="r_ant"></div>
            <div class="l_eye"></div>
            <div class="r_eye"></div>
        </div>
        <div class="body">
            <div class="l_arm"></div>
            <div class="r_arm"></div>
            <div class="l_leg"></div>
            <div class="r_leg"></div>
        </div>
    <

css

  div {margin: o; padding: 0;}
            div div {background: #A4CA39; position: relative;}
             
            .android{
                height: 404px; width: 334px;
                margin: 100px auto;
                
            }
            .head{
                width: 220px; height: 100px;
                top: 32px;
                
                border-radius: 110px 110px 0 0;
                -moz-border-radius: 110px 110px 0 0;
                -webkit-border-radius: 110px 110px 0 0;
                
                -webkit-transition: all 0.1s ease-in;
            }
            .l_eye, .r_eye {
                background: #fff;
                width: 20px; height: 20px;
                position: absolute; top: 42px;
                
                border-radius: 10px;
                -moz-border-radius: 10px;
                -webkit-border-radius: 10px;
            }
            .l_eye {left: 50px;}
            .r_eye {right: 50px;}
             
            .l_ant, .r_ant{
                width: 6px; height: 50px;
                position: absolute; top: -34px;
                border-radius: 3px;
                -webkit-border-radius: 3px;
                -moz-border-radius: 3px;
            }
            .l_ant {
                left: 50px;
                transform: rotate(-30deg);
                -webkit-transform: rotate(-30deg);
                -moz-transform: rotate(-30deg);
                -ms-transform:rotate(-30deg);
            }
            .r_ant {
                right: 50px;
                transform: rotate(30deg);
                -webkit-transform: rotate(30deg);
                -moz-transform: rotate(30deg);
                -ms-transform:rotate(30deg);
            }
             
            .body{
                width: 220px; height: 184px;
                top: 40px;
                
                border-radius: 0 0 25px 25px;
                -webkit-border-radius: 0 0 25px 25px;
                -moz-border-radius: 0 0 25px 25px;
            }
             
            .l_arm, .r_arm, .l_leg, .r_leg {
                width: 50px; position: absolute;
                -webkit-transition: all 0.1s ease-in;
                -moz-transition:all 0.1s ease-in;
                cursor:pointer;
            }
            .l_arm, .r_arm {
                height: 150px;
                border-radius: 25px;
                -moz-border-radius: 25px;
                -webkit-border-radius: 25px;
            }
            .l_leg, .r_leg {
                height: 80px; top: 182px;
                border-radius: 0 0 25px 25px;
                -moz-border-radius: 0 0 25px 25px;
                -webkit-border-radius: 0 0 25px 25px;
            }
            .l_arm {left: -58px;}
            .r_arm {right: -58px;}
            .l_leg {left: 45px;}
            .r_leg {right: 45px;}
             
            .head:hover {
                -webkit-transform: rotate(-5deg) translate(-4px, -8px);
                -transform: rotate(-5deg) translate(-4px, -8px);
                -moz-transform: rotate(-5deg) translate(-4px, -8px);
                -ms-transform: rotate(-5deg) translate(-4px, -8px);
            }
            .l_arm:hover{
                -webkit-transform: rotate(15deg) translate(-14px, 0);
                -transform: rotate(15deg) translate(-14px, 0);
                -moz-transform: rotate(15deg) translate(-14px, 0);
                -ms-transform:rotate(15deg) translate(-14px,0);
            }
            .r_arm:hover{
                -webkit-transform: rotate(-30deg) translate(30px, 0);
                -transform: rotate(-30deg) translate(30px, 0);
                -moz-transform: rotate(-30deg) translate(30px, 0);
                -ms-transform:rotate(-30deg) translate(30px,0);
            }

 





纯CSS3实现的Android Logo



By柏小白

如何去掉链接虚线框

链接的虚线框影响整体风格,我们在工作经常会将它去掉,而采用图片高亮的方式来显示焦点状态。然而去掉虚线框在两种浏览器中却分别对待,这种技巧经常用到,作个记录,以备不时之需。

当一个链接得到焦点时,默认会有个虚线框。如图:

在 Firefox 里可以用 -moz-outline:none; 或者 outline:none; 来将其去掉。所以我们可以这样写:

input,textarea {
  outline:none;
}

 

顺便提一下,如果你用过 Safari 和 Chrome 可能会发现,当输入框得到焦点时边框会出现阴影效果。

如果想去掉阴影效果也可以用 outline 属性。

input,textarea {
  outline:none;
}

 

言归正传,刚刚说的是 Firefox ,现在说说 IE。首先比较遗憾,还没有找到通过 CSS 去掉 IE 链接虚线框比较好的解决办法。所以只能用一个替代的办法,就是 a 标签的 hidefocus 属性(这个属性是 IE 独有的)。

	
<a href="#" hidefocus="true">链接</a>

 

注意:JS 脚本对应的属性名是:hideFocus。对应的 JS 代码应该是:

xxx.hideFocus ="true";

Read More

By柏小白

CSS解决Chrome浏览器限制使用12px以下字体的问题

在谷歌的浏览器Chrome中有一个奇怪的问题,页面上小于12px的字都以12px显示。

在其它浏览器中都没有此问题,不知道是谷歌真没发现这个bug,还是谷歌为了考虑到chrome的用户体验,故意把字号限制到最小12px ?

我看了那么多网站,应用10px或其它小于12px字号的站还真不多见,大多出现在全英文的网站上,因为10px的字母看着也算清晰,即使清晰,我也觉得没必要搞个10px的字,那么地小,节约页面空间?布局美观?还是为了排版需要?这也太狭义了吧。。。

然而,事实上小于12px的汉字看的眼睛胀痛,笔画多点的根本不能识别,那就更不应该应用10px的字了。能清晰地观看到页面中的信息,应该是用户对网站最基本的要求了。

不管是bug也好,还是功能也罢,即然有人需要在Chrome上显示10px的字,那就满足他们的需求。

要解决chrome中最小字体为12px的问题,可以使用Webkit 的内核 -webkit-text-size-adjust 的私有属性来解决,比如下面的代码就可以成功的解决,简单有效,通过- webkit-text-size-adjust即可实现字体大小不随终端设备或浏览器影响。

css样式定义如下:

	
.chrome10px { -webkit-text-size-adjust:none; font-size:10px; }

如果还不能满足你在来瞧瞧:“针对谷歌浏览器内核,加webkit前缀,用transform:scale()这个属性进行缩放!”

.chrome10px {font-size:10px;-webkit-transform:scale(0.8);display:block; }

 

By柏小白

给input的placeholder设置颜色

html5提供了placeholder让前端开发人员省了不少事,但是如果你要设置的颜色就有点蛋疼了,css没直接提供这样的选择器,毕竟placeholder是后来者,那怎么办呢?能不能修改?答案是可以了,css没有提供,我们可爱的现代浏览器有提供,嘿嘿~~~收藏吧童鞋们~~~

3
4
5
6
7
8
9
10
11
12
::-webkit-input-placeholder { /* WebKit browsers */
    color:    #999;
}
:-moz-placeholder { /* Mozilla Firefox 4 to 18 */
    color:    #999;
}
::-moz-placeholder { /* Mozilla Firefox 19+ */
    color:    #999;
}
:-ms-input-placeholder { /* Internet Explorer 10+ */
    color:    #999;
}

 

By柏小白

修改微信朋友圈分享链接后的小小图标

方法/步骤
在网页的头部加上以下代码,图片路径自行修改。

<head>
<div id='wx_pic' style='margin:0 auto;display:none;'>
<img src='/image/data/pic300.jpg' />
</div>
</head>

制作像素是 300*300px的图片,命名为pic300.jpg。将图片放到步骤一对应的路径下。

保存好文件后,就可以分享到朋友圈了。此时分享的网页链接就会有小图片显示了

By柏小白

jQuery实现购物车多物品数量的加减小计+总价计算

<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="UTF-8">
    <title>jQuery实现购物车多物品数量的加减小计+总价计算</title>
    <script src="http://code.jquery.com/jquery-1.7.min.js"></script>
    <script>
$.each($('input[class*=text_box]'),function(i,t){
    subtotal($(t));
})
$(function(){
$(".add").click(function(){
    var t=$(this).parent().find('input[class*=text_box]');
    t.val(parseInt(t.val())+1);
    if(isNaN(t.val())){
        t.val(1);
    }
    subtotal(t)
});
$(".min").click(function(){ 
    var t=$(this).parent().find('input[class*=text_box]'); 
    t.val(parseInt(t.val())-1);
    if(parseInt(t.val())<=0 || isNaN(t.val())){ 
        t.val(1);
    }
    subtotal(t);
});
$('input[class*=text_box]').keyup(function(){
    var t=$(this);
    t.val(parseInt(t.val()));
    if (isNaN(t.val()) || parseInt(t.val()) <= 0) {
        t.val(1);
    }
    if (t.val(parseInt(t.val())) != t.val()) {
        t.val(parseInt(t.val()));
    }
    subtotal(t);
});
function subtotal(sum){
    var subtotal=0;
    subtotal=parseFloat(sum.siblings('.price').text())*parseInt(sum.val());
    sum.siblings('.subtotal').html(subtotal.toFixed(2));
    setTotal();
}
function setTotal(){
    var s=0; 
    $("#tab td").each(function(){ 
        s+=parseInt($(this).find('input[class*=text_box]').val())*parseFloat($(this).find('span[class*=price]').text()); 
    });
    $("#total").html(s.toFixed(2));
    } 
    setTotal();
});
</script></head>
<body>
    <table id="tab">
        <tr>
            <td>
                <span>单价:</span>
                <span class="price">1.50</span>
                <input class="min" name="" type="button" value="-" />
                <input class="text_box" name="" type="text" value="1" />
                <input class="add" name="" type="button" value="+" />
                <span class="subtotal">1.50</span>
            </td>
        </tr>
        <tr>
            <td>
                <span>单价:</span>
                <span class="price">3.95</span>
                <input class="min" name="" type="button" value="-" />
                <input class="text_box" name="" type="text" value="1" />
                <input class="add" name="" type="button" value="+" />
                <span class="subtotal">3.95</span>
            </td>
        </tr>
    </table>

    <p>
        总价:
        <label id="total"></label>
    </p>
</body>
</html>

 





jQuery实现购物车多物品数量的加减小计+总价计算


单价:
1.50



1.50
单价:
3.95



3.95

总价:


By柏小白

jquery全屏banner自动轮播切换

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>jquery全屏banner自动轮播切换</title>
<script src="http://code.jquery.com/jquery-1.7.min.js"></script>
<script type="text/javascript">
function banner(){  
    var d=0;
    var speed=5000;
    var count=1;
    var time;
    var fouse=$('#banner .d1');
    var dot=$('#banner_id li');
    fouse.hide();
    fouse.eq(0).fadeIn('slow');
    if(fouse.length>0){
        dot.eq(0).addClass('nuw');
        function Carousel(){
            var c=d+1;
            if(c>fouse.length-1){
                c=0;
            }
            fouse.eq(d).css('z-index','2');
            fouse.eq(c).css('z-index','1');
            fouse.eq(c).show();
            fouse.eq(d).fadeOut('slow');
            dot.removeClass('nuw');
            dot.eq(c).addClass('nuw');
            d=c;
        }
        time=setInterval(Carousel,speed);
        dot.click(function(){
            var e=dot.index(this);
            if(e!=d&&count==1){
                count=0;
                fouse.eq(d).css('z-index','2');
                fouse.eq(e).css('z-index','1');
                fouse.eq(e).show();
                fouse.eq(d).fadeOut('slow',function(){count=1});
                dot.removeClass('nuw');
                dot.eq(e).addClass('nuw');
                d=e;
            }
        });
        $('#banner_id').hover(function(){
            clearInterval(time);
        },function(){
            time=setInterval(Carousel,speed);
        });
    }
    else{
        $('#banner').hide();
    }
}
</script>
</head>
<body>
<style type="text/css">
*{margin:0;padding:0;list-style-type:none;}
a,img{border:0;}
body{font:12px/180% Arial, Helvetica, sans-serif, "新宋体";}
/* banner */
.banner{height:400px;overflow:hidden;}
.banner .d1{width:100%;height:392px;display:block;position:absolute;left:0px;top:0px;}
.banner .d2{width:100%;height:30px;clear:both;position:absolute;z-index:100;left:0px;top:360px;}
.banner .d2 ul{float:left;position:absolute;left:50%;top:0;margin:0 0 0 -96px;display:inline;}
.banner .d2 li{width:17px;height:15px;overflow:hidden;cursor:pointer;background:url(images/img1.png) white no-repeat center;float:left;margin:0 3px;display:inline;}
.banner .d2 li.nuw{background:url(images/img1_1.png) white no-repeat center;}
</style>
<div class="banner" id="banner" >
    <a href="#" class="d1" style="background:url(images/banner1.jpg) red center no-repeat;"></a> 
    <a href="#" class="d1" style="background:url(images/banner2.jpg) yellow center no-repeat;"></a>
    <a href="#" class="d1" style="background:url(images/banner3.jpg) #03A9F4 center no-repeat;"></a>
    <a href="#" class="d1" style="background:url(images/banner4.jpg) #795548 no-repeat;"></a>
    <a href="#" class="d1" style="background:url(images/banner5.jpg) #CDDC39 no-repeat;"></a>
    <div class="d2" id="banner_id">
        <ul>
            <li></li>
            <li></li>
            <li></li>
            <li></li>
            <li></li>
        </ul>
    </div>
</div>
<script type="text/javascript">banner()</script>
<div style="text-align:center;clear:both">
<p>适用浏览器:IE6+、360、FireFox、Chrome、Safari、Opera、傲游、搜狗、世界之窗.图片自行配图</p>
</div>
</body>
</html>

 





jquery全屏banner自动轮播切换




By柏小白

Jquery 实现表单验证,所有验证通过方可提交

<html>
    <head>
        <meta charset=utf-8"> 
        <title>Reg</title>
        <style>
            .state1{
                color:#aaa;
            }
            .state2{
                color:#000;
            }
            .state3{
                color:red;
            }
            .state4{
                color:green;
            }
        </style>
        <script src="jquery.js"></script>
        <script>
            $(function(){
 
                var ok1=false;
                var ok2=false;
                var ok3=false;
                var ok4=false;
                // 验证用户名
                $('input[name="username"]').focus(function(){
                    $(this).next().text('用户名应该为3-20位之间').removeClass('state1').addClass('state2');
                }).blur(function(){
                    if($(this).val().length >= 3 && $(this).val().length <=12 && $(this).val()!=''){
                        $(this).next().text('输入成功').removeClass('state1').addClass('state4');
                        ok1=true;
                    }else{
                        $(this).next().text('用户名应该为3-20位之间').removeClass('state1').addClass('state3');
                    }
                     
                });
 
                //验证密码
                $('input[name="password"]').focus(function(){
                    $(this).next().text('密码应该为6-20位之间').removeClass('state1').addClass('state2');
                }).blur(function(){
                    if($(this).val().length >= 6 && $(this).val().length <=20 && $(this).val()!=''){
                        $(this).next().text('输入成功').removeClass('state1').addClass('state4');
                        ok2=true;
                    }else{
                        $(this).next().text('密码应该为6-20位之间').removeClass('state1').addClass('state3');
                    }
                     
                });
 
                //验证确认密码
                    $('input[name="repass"]').focus(function(){
                    $(this).next().text('输入的确认密码要和上面的密码一致,规则也要相同').removeClass('state1').addClass('state2');
                }).blur(function(){
                    if($(this).val().length >= 6 && $(this).val().length <=20 && $(this).val()!='' && $(this).val() == $('input[name="password"]').val()){
                        $(this).next().text('输入成功').removeClass('state1').addClass('state4');
                        ok3=true;
                    }else{
                        $(this).next().text('输入的确认密码要和上面的密码一致,规则也要相同').removeClass('state1').addClass('state3');
                    }
                     
                });
 
                //验证邮箱
                $('input[name="email"]').focus(function(){
                    $(this).next().text('请输入正确的EMAIL格式').removeClass('state1').addClass('state2');
                }).blur(function(){
                    if($(this).val().search(/\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/)==-1){
                        $(this).next().text('请输入正确的EMAIL格式').removeClass('state1').addClass('state3');
                    }else{                  
                        $(this).next().text('输入成功').removeClass('state1').addClass('state4');
                        ok4=true;
                    }
                     
                });
 
                //提交按钮,所有验证通过方可提交
 
                $('.submit').click(function(){
                    if(ok1 && ok2 && ok3 && ok4){
                        $('form').submit();
                    }else{
                        return false;
                    }
                });
                 
            });
        </script>
    </head>
<body>
  
<form action='do.php' method='post' >
    用 户 名:<input type="text" name="username">
                <span class='state1'>请输入用户名</span><br/><br/>
    密  码:<input type="password" name="password">
                <span class='state1'>请输入密码</span><br/><br/>
    确认密码:<input type="password" name="repass">
                <span class='state1'>请输入确认密码</span><br/><br/>
    邮  箱:<input type="text" name="email">
                <span class='state1'>请输入邮箱</span><br/><br/>   
 
</form>
</body>

 




Reg




用 户 名:
请输入用户名

密  码:
请输入密码

确认密码:
请输入确认密码

邮  箱:
请输入邮箱

By柏小白

jQuery 实现回到顶部代码

HTML 结构
我使用了JS添加,需要提取出来也比较方便,需要美化的自行添加style

CSS 代码

/*返回顶部*/
.GoTop { width: 50px; height: 45px; bottom: 55px; cursor: pointer; background: red; color: white; text-align: center; position: fixed; right: 50px; display: none; z-index: 580; }

jQuery 代码

$(function() {

	var globalConfig = true;  //是否启用回到顶部  true启用 : false 关闭 
	if(!globalConfig)return false;  


	var $GoTop = $('.GoTop'),right,



	$window = $(window);

	if(!$GoTop.length){ //如果不存在返回顶部append添加

	    $GoTop = $('<div class="GoTop">返回顶部</div>');

	    $("body").append($GoTop);
	}


	if($window.width() < 1280){ //浮动右边right距离 
	    right = 10;
	}
	else{
	    right = Math.abs(($window.width() - 1200) / 2 - $GoTop.width());  //1200  定义主体宽度 
	    $GoTop.css("right", right);
	}


	$GoTop.bind("click.GoTop", function (){  //当点击标签的时候,使用animate在500毫秒的时间内,滚到顶部
	    $('body,html').animate({scrollTop: 0}, "500");
	});


	$window.bind("scroll.GoTop", function (){ //只要窗口滚动,就触发下面代码 

      $(this).scrollTop()>100?$GoTop.fadeIn():$GoTop.fadeOut();   //判断滚动后高度超过100px,就显示  

	});






});

 





返回顶部





By柏小白

jquery 文字滚动大全 单行滚动 多行滚动 带按钮控制滚动

<!DOCTYPE html>
<html lang="zh-cn">
<head>
	<meta charset="UTF-8" />
<title>jquery 文字滚动大全 单行滚动 多行滚动 带按钮控制滚动</title>
<script src="http://code.jquery.com/jquery-1.7.min.js"></script>
<style type="text/css">
*{margin:0;padding:0;}
ul,li{list-style-type:none;}
body{font:12px/180% Arial, Helvetica, sans-serif;}
a{color:#333;text-decoration:none;}
a:hover{color:#3366cc;text-decoration:underline;}
.demopage{width:960px;margin:0 auto;}
.demopage h2{font-size:14px;margin:20px 0;}
/* scrollDiv */
.scrollDiv{height:25px;/* 必要元素 */line-height:25px;border:#ccc 1px solid;overflow:hidden;/* 必要元素 */}
.scrollDiv li{height:25px;padding-left:10px;}
#s2,#s3{height:100px;}
</style>
</head>
 
<body>
<div class="demopage">
	<h2>jquery 文字上下滚动--单行 批量多行 文字图片上下翻滚 | 单行滚动</h2>
	<div class="scrollDiv" id="s1">
		<ul>
			<li><a href="http://www.17sucai.com/">jquery 滚动条 Scrollbar 设置浏览器默认滚动条样式</a></li>
			<li><a href="http://www.17sucai.com/">jquery 图片切换 switchable 带左右按钮控制分页索引图片切换</a></li>
			<li><a href="http://www.17sucai.com/">jquery powerFloat万能浮动框提示插件 支持图片、文字、ajax异步加载、表单验证等</a></li>
			<li><a href="http://www.17sucai.com/">jquery 弹出层插件 ThickBox 多功能弹出层插件支持图片、ajax、内嵌内容弹等</a></li>
			<li><a href="http://www.17sucai.com/">jquery 表单美化 jquery tzCheckbox 复选框美化 自定义默认复选框</a></li>
			<li><a href="http://www.17sucai.com/">jquery HTML5 幻灯片插件 用 Canvas 制作类似百叶窗拍摄快门摄影拍摄效果</a></li>
			<li><a href="http://www.17sucai.com/">jquery 图片放大镜 图片类似放大镜效果鼠标滑过小图异步加载中图、大图</a></li>
			<li><a href="http://www.17sucai.com/">jquery 图片幻灯片 点击小图显示大图异步加载 支持按钮播放</a></li>
		</ul>
	</div><!--scrollDiv end-->
	<script type="text/javascript">
	function AutoScroll(obj){
		$(obj).find("ul:first").animate({
			marginTop:"-25px"
		},500,function(){
			$(this).css({marginTop:"0px"}).find("li:first").appendTo(this);
		});
	}
	$(document).ready(function(){
		setInterval('AutoScroll("#s1")',3000);
	});
	</script>
	
	
	<h2>jquery 文字上下滚动--单行 批量多行 文字图片上下翻滚 | 多行滚动</h2>
	<div class="scrollDiv" id="s2">
		<ul>
			<li><a href="http://www.17sucai.com/">jquery Xslider 插件焦点图片特效图片淡隐淡现、图片上下滚动、图片左右滚动、选项卡</a></li>
			<li><a href="http://www.17sucai.com/">jquery 文字连续滚动 节奏感十足的齿轮式滚动图片展示与文字内容特效展示</a></li>
			<li><a href="http://www.17sucai.com/">jquery cycle 循环幻灯片插件多功能幻灯片插件支持多种幻灯片特效</a></li>
			<li><a href="http://www.17sucai.com/">jquery轻量级进度条 progressbar 带动画显示的进度过程的jquery进度条特效</a></li>
			<li><a href="http://www.17sucai.com/">jquery菜单特效 鼠标滑过菜单区域图标和文本类似flash动画酷炫移动展示</a></li>
			<li><a href="http://www.17sucai.com/">jquery 图片切换 自动切换显示隐藏show/hide带左右按钮与分页索引按钮控制图片自动切换显示隐藏show/hide</a></li>
			<li><a href="http://www.17sucai.com/">jquery图片特效 slide banner焦点图片切换图片上下翻滚、图片左右翻滚、图片淡隐淡现3种图片滚动特效</a></li>
			<li><a href="http://www.17sucai.com/">javascript jscolor colorpicker js颜色选择器插件10多种调用颜色方法与取值</a></li>
		</ul>
	</div>
	<script type="text/javascript">
	//滚动插件
	(function($){
		$.fn.extend({
			Scroll:function(opt,callback){
					//参数初始化
					if(!opt) var opt={};
					var _this=this.eq(0).find("ul:first");
					var lineH=_this.find("li:first").height(), //获取行高
						line=opt.line?parseInt(opt.line,10):parseInt(this.height()/lineH,10), //每次滚动的行数,默认为一屏,即父容器高度
						speed=opt.speed?parseInt(opt.speed,10):500, //卷动速度,数值越大,速度越慢(毫秒)
						timer=opt.timer?parseInt(opt.timer,10):3000; //滚动的时间间隔(毫秒)
					if(line==0) line=1;
					var upHeight=0-line*lineH;
					//滚动函数
					scrollUp=function(){
							_this.animate({
									marginTop:upHeight
							},speed,function(){
									for(i=1;i<=line;i++){
											_this.find("li:first").appendTo(_this);
									}
									_this.css({marginTop:0});
							});
					}
					//鼠标事件绑定
					_this.hover(function(){
							clearInterval(timerID);
					},function(){
							timerID=setInterval("scrollUp()",timer);
					}).mouseout();
			}       
		});
	})(jQuery);
	
	$(document).ready(function(){
		$("#s2").Scroll({line:4,speed:500,timer:4000});
	});
	</script>
	
	
	<h2>jquery 上下滚动--单行 批量多行 文字图片上下翻滚 | 可控制向前向后的多行滚动</h2>
	<div class="scrollDiv" id="s3">
		<ul>
			<li><a href="http://www.17sucai.com/">jquery colorpicker 插件颜色选择器 点击颜色选择颜色值与颜色相应变化</a></li>
			<li><a href="http://www.17sucai.com/">jquery评论星星打分特效、鼠标滑过星星显示评论信息</a></li>
			<li><a href="http://www.17sucai.com/">jquery图片切换滚动 水平手风琴切换滚动鼠标滑过图片水平切换</a></li>
			<li><a href="http://www.17sucai.com/">jquery 图片切换滚动特效带分页索引按钮控制左右图片切换滚动</a></li>
			<li><a href="http://www.17sucai.com/">jquery筛选器插件选项卡 css3制作一个漂亮的HTML5筛选容器插件选项卡</a></li>
			<li><a href="http://www.17sucai.com/">jquery 图片特效用CSS3和HTML5制作仿动画头条报纸缩小到放大翻转图片展示</a></li>
			<li><a href="http://www.17sucai.com/">jquery特效基于jquery幻灯片插件制作一个泡沫幻灯片图片展示特效</a></li>
			<li><a href="http://www.17sucai.com/">jquery 图片幻灯片仿IBM首页焦点图切换,类似flash动态效果图片切换</a></li>
		</ul>
	</div>
	<span id="btn1" >点击向上滚动</span>&nbsp;&nbsp;<span id="btn2">点击向下滚动</span>
	<script type="text/javascript">
	(function($){
		$.fn.extend({
			Scroll:function(opt,callback){
					//参数初始化
					if(!opt) var opt={};
					var _btnUp = $("#"+ opt.up);//Shawphy:向上按钮
					var _btnDown = $("#"+ opt.down);//Shawphy:向下按钮
					var timerID;
					var _this=this.eq(0).find("ul:first");
					var     lineH=_this.find("li:first").height(), //获取行高
							line=opt.line?parseInt(opt.line,10):parseInt(this.height()/lineH,10), //每次滚动的行数,默认为一屏,即父容器高度
							speed=opt.speed?parseInt(opt.speed,10):500; //卷动速度,数值越大,速度越慢(毫秒)
							timer=opt.timer //?parseInt(opt.timer,10):3000; //滚动的时间间隔(毫秒)
					if(line==0) line=1;
					var upHeight=0-line*lineH;
					//滚动函数
					var scrollUp=function(){
							_btnUp.unbind("click",scrollUp); //Shawphy:取消向上按钮的函数绑定
							_this.animate({
									marginTop:upHeight
							},speed,function(){
									for(i=1;i<=line;i++){
											_this.find("li:first").appendTo(_this);
									}
									_this.css({marginTop:0});
									_btnUp.bind("click",scrollUp); //Shawphy:绑定向上按钮的点击事件
							});
	
					}
					//Shawphy:向下翻页函数
					var scrollDown=function(){
							_btnDown.unbind("click",scrollDown);
							for(i=1;i<=line;i++){
									_this.find("li:last").show().prependTo(_this);
							}
							_this.css({marginTop:upHeight});
							_this.animate({
									marginTop:0
							},speed,function(){
									_btnDown.bind("click",scrollDown);
							});
					}
				   //Shawphy:自动播放
					var autoPlay = function(){
							if(timer)timerID = window.setInterval(scrollUp,timer);
					};
					var autoStop = function(){
							if(timer)window.clearInterval(timerID);
					};
					 //鼠标事件绑定
					_this.hover(autoStop,autoPlay).mouseout();
					_btnUp.css("cursor","pointer").click( scrollUp ).hover(autoStop,autoPlay);//Shawphy:向上向下鼠标事件绑定
					_btnDown.css("cursor","pointer").click( scrollDown ).hover(autoStop,autoPlay);
	
			}      
		})
	})(jQuery);
	
	$(document).ready(function(){
		$("#s3").Scroll({line:4,speed:500,timer:2000,up:"btn1",down:"btn2"});
	});
	</script>
	
</div><!--demopage end-->	
</body>
</html>

 





jquery 文字滚动大全 单行滚动 多行滚动 带按钮控制滚动

jquery 文字上下滚动–单行 批量多行 文字图片上下翻滚 | 单行滚动


jquery 文字上下滚动–单行 批量多行 文字图片上下翻滚 | 多行滚动

jquery 上下滚动--单行 批量多行 文字图片上下翻滚 | 可控制向前向后的多行滚动

点击向上滚动  点击向下滚动



By柏小白

jQuery弹性滑动导航菜单

最近看到很多鼠标滑过的效果,今天来整理下

<div id="nav">
	<div class="nav-menu">
		<a class="current" href="#">首页</a>
		<a href="#">Menu YI</a>
		<a href="#">Menu ER</a>
		<a href="#">Menu SAN</a>
		<a href="#">Menu SI</a>
		<a href="#">Menu WU</a>
	</div>
	<div class="nav-current"></div>
</div>

Read More

By柏小白

jQuery表单输入框焦点效果

//聚焦型验证
$("#focus .inputText").each(function() {
    $(this).focus(function() {
        $(this).siblings("span").hide();
    }).blur(function() {
        if ($(this).val() == "") {
            $(this).siblings("span").show();
        } else {
            $(this).siblings("span").hide();
        }
    })
})
 
//输入型验证
$("#keydown .inputText").each(function() {
    $(this).keydown(function() {
        $(this).siblings("span").hide();
    }).blur(function() {
        if ($(this).val() == "") {
            $(this).siblings("span").show();
        } else {
            $(this).siblings("span").hide();
        }
    })
})

CSS代码

body {
    background: #333;
    padding: 0;
    margin: 0;
}
 
#focus, #keydown {
    width: 400px;
    padding: 20px;
    background: #FCF9EF;
    margin: 30px 0 0 30px;
}
 
#focus h2, #keydown h2 {
    font-size: 24px;
    font-family: "微软雅黑";
    color: #b00000;
}
 
#focus label, #keydown label {
    display: block;
    position: relative;
    height: 40px;
    margin-top: 20px;
}
 
#focus span, #keydown span {
    display: block;
    position: absolute;
    top: 0;
    left: 10px;
    height: 40px;
    line-height: 40px;
    font-size: 14px;
    color: #999;
    cursor: text;
}
 
.radius {
    -moz-border-radius: 5px;
    -webkit-border-radius: 5px;
    border-radius: 5px;
}
 
.inputText {
    width: 378px;
    height: 14px;
    padding: 12px 10px;
    border: 1px #ccc solid;
    font-size: 14px;
    color: #333;
    -moz-box-shadow: inset 1px 1px 5px #ddd;
    -webkit-box-shadow: inset 1px 1px 5px #ddd;
    box-shadow: inset 1px 1px 5px #ddd;
}
 
.inputText:focus {
    outline: none;
    border: 1px #B00000 solid;
    -moz-box-shadow: 0 0 4px rgba(255,153,164,0.8);
    -webkit-box-shadow: 0 0 4px rgba(255,153,164,0.8);
    box-shadow: 0 0 4px rgba(255,153,164,0.8);
}

HTML代码

<form class="radius" id="focus">
    <h2>聚焦型提示语消失</h2>
    <label> <span>请输入帐号</span>
        <input type="text" class="inputText radius" />
    </label>
    <label> <span>请输入密码</span>
        <input type="password" class="inputText radius" />
    </label>
</form>
 
<form class="radius" id="keydown">
    <h2>输入型提示语消失</h2>
    <label> <span>请输入帐号</span>
        <input type="text" class="inputText radius" />
    </label>
    <label> <span>请输入密码</span>
        <input type="password" class="inputText radius" />
    </label>
</form>

Read More

By柏小白

用JS控制iframe里的页面,做到3秒自动换

<iframe id="ifr" src="http://www.qietu.cn/?xxx";></iframe>

假定iframe的id为ifr

下面是js程序

var times = 10;  //循环次数
var iframe = document.getElementById('ifr');   //获取iframe元素
//设置定时执行
var t = setInterval(function(){
     if(times--<=0)  clearInterval(t);
     changeFrameSrc(iframe);
},3000);   //3000毫秒
//改变iframe的src属性的函数
function changeFrameSrc(f){
    var src = 'http://www.qietu.cn/?'+rand(100,999);  //生成地址
    f.src = src;
}
//随机函数
function rand(min,max){
    return parseInt(Math.random()*(max-min+1)+min);
}

Read More

By柏小白

CSS+Cookie实现的固定页脚广告条

经常看到有些网站为了吸引用户注意,在页面底部放置固定横幅广告,用户滚动页面时,横幅广告一直固定在页底,并不随页面滚动而滚动,当然一般允许用户可以关闭广告条,并设置一定时间内不再显示此广告条。本文将介绍使用CSS+Cookie来实现这一效果。
HTML
首先,我们将横幅广告的html代码放到页面最底部,因为是最后加载的。也可以使用外部js动态插入到页面底部。整个HTML结构由遮罩层.float_layer,内容层.float_content组成,其中.float_bg为广告部分,内容可以是图片、文字等任意形式的html元素,.float_close是关闭按钮,用户不喜欢广告可以关闭展示。

<div class="float_mask" id="float_mask"> 
    <div class="float_layer"> 
    </div> 
    <div class="float_content clearfix"> 
        <div class="float_bg"> 
            <a target="_blank" href="http://www.helloweba.com/" title='广告部分'> 
                <div class="float_slogan"><!--广告内容--></div> 
            </a> 
        </div> 
        <div class="float_close"> 
            <a onclick="closeFootAd()" href="#" title="我知道了"></a> 
        </div> 
    </div> 
</div>

Read More

By柏小白

chrome下去掉保存密码后输入框变成黄色背景样式

做前端的童鞋一定经常遇到过chrome保存密码后input输入框会变成黄色,对于正在开发中的项目,老是出来黄色背景很是不爽。

我们用代码审查查看了input样式发现有如下样式设定。
]A}O5L_1S40XW{[LK0BT3OA

然后我用!important设定后发现不能修改默认状态。最后用了阴影实现了

input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus {
    box-shadow:0 0 0 60px #fff inset;
    -webkit-text-fill-color: #333;
}

如果不想保存密码的话加个autocomplete=”off”到form或者input就行了。

相关链接:http://labs.enonic.com/articles/remove-forced-yellow-input-background-in-chrome

By柏小白

网页中点击链接跳转到QQ聊天界面

scheme = "mqqwpa://im/chat?chat_type=wpa&uin=" + g.tuin + "&version=1&src_type=web&web_src=" + host;

是的,具体的是:

mqqwpa://im/chat?chat_type=wpa&uin=360708355&version=1

,点击试一下?

可是,不知道为什么现在只能到达手机QQ界面,无法到达QQ聊天界面,我用的ios测试的,继续抛砖引玉中。

后来进行了另外的尝试,点击这里试一下。是不是可以进入聊天界面。

链接是这样的:

mqqwpa://im/chat?chat_type=wpa&uin=574201314&version=1&src_type=web&web_src=qietu.cn

 

<a class="qqzaixian" href="http://wpa.qq.com/msgrd?v=3&amp;uin=360708355&amp;site=qq&amp;menu=yes" target="_blank">点我与“柏小白”聊天</a>

 

pc:点我与“柏小白”聊天

By柏小白

怎样替换为默认图片,加载图片失败

img元素加载图片失败,则变成一个小图标,让页面变得难看。此时如何替换为默认图片?
onerror属性
img元素自带onerror属性,加载失败时,触发error事件

<img src="http://yongqing.is-programmer.com/posts/image.gif" onerror='this.src="http://yongqing.is-programmer.com/posts/default.gif" />

Read More

By柏小白

javascript addLoadEvent延迟加载函数

addLoadEvent 函数 jQuery之父John Resig(提示:噢!也许真的是他写的,但是谁知道呢?)

/*
延迟加载脚本
*func 参数 “函数”
*
*/

function addLoadEvent(func) {
    var oldonload = window.onload;
    if (typeof window.onload != 'function') {
        window.onload = func;
    } else {
        window.onload = function() {
            oldonload();
            func();
        }
    }
}

 

 

By柏小白

animate-css3动画演示

413870769-JOJO 提供 还没有使用,好用在给于说明

无码无真相:

从上往下渐显

 
  <div class="tip tbShow ani-time1 ani-jy"></div>

从下往上渐显

 
    <div class="tip btShow ani-time1 ani-jy"></div>

从右往左渐显

 
    <div class="tip rlShow ani-time1 ani-jy"></div>

从左往右渐显

 
    <div class="tip lrShow ani-time1 ani-jy"></div>

闪烁,最好设置反向动画更佳:ani-yjfx

 
    <div class="tip shanshuo ani-time1 ani-yjfx"></div>

从小变大

    <div class="tip bianda ani-time1 ani-jy"></div>

上下跳动

    <div class="tip shangxia ani-time1 ani-yjfx"></div>

顺时针转圈

    <div class="tip zhuanquan ani-time1 ani-jy"></div>

逆时针转圈

    <div class="tip zhuanquan-ni ani-time1 ani-jy"></div>






动画

从上往下渐显

从下往上渐显

从右往左渐显

从左往右渐显

闪烁,最好设置反向动画更佳:ani-yjfx

从小变大

上下跳动

顺时针转圈

逆时针转圈



By柏小白

加载Loading 让网页加载完后显示

初次渲染页面页面闪动处理方法:

一个JavaScript网页加载特效,当网页没有加载完成时,会一直显示出这个Loading,当Loading结束后,再会显示网页内容。

现在很多网站仍然在用的网页进度条效果。

//页面加载完成后影藏 loading
function subSomething(){
  if(document.readyState == "complete") // 当前页面状态
  $("#webloading").fadeOut(500,function(){
    $(this).remove();
  });
}
document.onreadystatechange = subSomething;  // 当前页面状态改变的时候执行这个方法
<div id="webloading"></div>

加上定时器

function subSomething() {

var timeId=setInterval(function(){
if (document.readyState == "complete") { // 当前页面状态
    $("#webloading").fadeOut(500, function() {
      $(this).remove();
       clearInterval(timeId);
    });
 
  }

}, 1000)

}

 






Document



By柏小白

慢慢,收集js代码块(持续更新……)

酷爱代码,但无记性

经常看,经常忘记,今天开始总结下代码块,便于今后翻阅

1.window.onload 事件处理函数

//  加载函数
function addLoadEvent(func) {
  var oldonload = window.onload;
  if (typeof window.onload != 'function') {
    window.onload = func;
  } else {
    window.onload = function() {
      oldonload();
      func();
    }
  }
}

2.添加class 函数

function addClass(element, value) {
  if (!element.className) {
    element.className = value;
  } else {
    newClassName = element.className;
    newClassName += " ";
    newClassName += value;
    element.className = newClassName;
  }
}

3.跳转页面-当前导航菜单添加属性

function highlightPage() {

  // 现代浏览器一般都支持
  // if (!document.getElementsByTagName) return false;
  // if (!document.getElementById) return false;

  if (!document.getElementById("navigation")) return false;
  var nav = document.getElementById("navigation");
  var links = nav.getElementsByTagName("a");

 
  for (var i = 0; i < links.length; i++) {
    //links[i]的 URL 
    var linkurl = links[i].getAttribute("href");  
    // 当前页面URL相匹配的链接 
    var currenturl = window.location.href; 
    // links[i]的 URL与当前页面的URL进行比较
    if (currenturl.indexOf(linkurl) != -1) {
      // 添加值为here的class属性
      links[i].className = "here";
      // 获取当前最后一个子节点---就是当表示文本,并转换成小写字母
      var linktext = links[i].lastChild.nodeValue.toLowerCase();
      // 把变量linktext 赋值给 body元素的id属性即可
      document.body.setAttribute("id", linktext);
    }
  }

}

// 调用 window.onload 事件处理函数
addLoadEvent(highlightPage);
<div id="navigation">
    <ul>
        <li><a href="index.html">Home</a></li>
        <li><a href="about.html">About</a></li>
        <li><a href="photos.html">Photos</a></li>
        <li><a href="live.html">Live</a></li>
        <li><a href="contact.html">Contact</a></li>
    </ul>
</div>

4. 点击空白或者页面其他地方,关闭弹框

$(document).mouseup(function(e){
  var _con = $(' 目标区域 ');   // 设置目标区域
  if(!_con.is(e.target) && _con.has(e.target).length === 0){ // Mark 1
    some code...   // 功能代码
  }
});

//  Mark 1 的原理:
// 判断点击事件发生在区域外的条件是:
// 1. 点击事件的对象不是目标区域本身
// 2. 事件对象同时也不是目标区域的子元素

 

未完待续……

By柏小白

javascript

——人脑不是机器,记忆都会退化,我们需要文档辅助作知识沉淀

javascript

基本功

语言特性
  • 数据类型:
    • Undefined, Null, Bollean, Number, String
    • ObjectArray
    • DateRegExp
  • typeof输出(以下六个值之一):
    • undefined javascript var x; typeof(x); // "undefined"
    • boolean javascript var x = false; typeof x; // "boolean"
    • string javascript var x = ''; typeof x; // "string"
    • number javascript var x = NaN; typeof x; // "number"
    • object javascript var x = {}; var y = []; var z = null; typeof x; // "object" typeof y; // "object" typeof z; // "object"
    • function javascript var x = function() {}; typeof x; // "function"
类型转换:
  • 简单类型 -> 简单类型: javascript '1'-0; // 0, equal to Number(1)
  • 简单类型 -> 对象(使用基本函数的构造函数:Number(), String(), Boolean()等生成): javascript var n = 5; console.log(n.toString(2)); // 快速进制转换
  • 对象 -> 简单类型(参考JavaScript 类型转换
1. 隐式转换:除Date外,统统是先 `valueOf`、再 `toString`(`Date` 在 `+` 和 `==` 时优先转化为字串):
``` javascript
[] + 1; // 1
```

2. 显式Number(对象):先`valueOf`,再`toString()`,都不存在则返回`NaN`:
``` javascript
Number({}); // NaN
```

3. 显式String(对象):先取`valueOf()`,再取`valueOf()`,都不存在则抛异常:
``` javascript
String({}); // [object Object]
```
DOM操作(增、删、查、改、移、数据交换)
  • createElement, createTextNode, createDocumentFragment, appendChild
  • removeChild, removeNode
  • getElementById, getElementsByTagName, getElementsByClassName, querySelector, querySelectorAll, parentNode, firstChild, lastChild, nextSibling, previousSibling, childNodes
  • replaceChild, insertBefore
  • getAttribute, setAttribute, data-x, jQuery.attr(), jQuery().prop(), jQuery().data(), classList, innerHTML, innerText, textContent
事件机制(IE VS W3C)
  • 事件绑定与解绑:addEventListener(type, handler, flag), attechEvent('on' + type, handler), removeEventListener(type, handler), detechEvent('on' + type, handler)
  • 事件流:
    • 事件捕获流:沿着文档树由外到内
    • 事件对象 javascript function handler(e) { var e = e || window.event; var target = e.target || e.srcElement; // e.currentTarget 指的是绑定事件的元素,不一定和target是同一个 }
    • 事件冒泡流:沿着文档树由内到外,load、unload、focus、blur、submit和change事件不支持冒
OOP(原型链、继承。。。)
  • 比较(参考 全面理解面向对象的 JavaScript
    • 基于类Class的面向对象,对象由类Class产生:如JavaC#
    • javascript:基于原型prototype的OOP,对象由构造器(构造函数)constructor利用原型prototype产生
  • 生成js对象:
1. 类JSON的对象字面量:简单直观,但不适用于复杂的对象(类)
``` javascript
var Preson = {
    name: 'xiaoming',
    age: 15
};
```

2. 构造函数模式:存在内存浪费的问题,比如下面例子里的`this.city`,在内存里生成了多次
``` javascript
var Person = function(name, age) {
    // 全部标记为私有成员
    this.name = name;
    this.age = age;
    this.city = 'shen zhen';
};
var xm = new Person('xiaoming', 15);
var xl = new Person('xiaoli;, 20);
```

3. 原型`prototype`模式:每次实例化只增加私有的对象属性(或方法)到实例中,所有实例的公有属性(或方法)指向同一个内存地址
``` javascript
var Person = function(name, age) {
    // 对象的私有成员
    this.name = name;
    this.age = age;
};
Person.prototype.city = 'shen zhen';// 共有成员
```
  • 对象的继承
1. 非构造函数的继承:继承可以简单使用对象之间的深、浅拷贝

2. 构造函数的继承:大多是基于原型的继承,但是阅读性差,也不利于扩展

    1. 借调:依赖apply或者call实现
    ``` javascript
    function A(name) {
        this.name = name;
    }
    function B(name, age) {
        A.apply(this, arguments);
        this.age = age;
    }
    ```

    2. 子类prototype引用父类的prototype
    ``` javascript
    function A() {}
    A.prototype.propA = 'a';
    A.prototype.propB = 'b';
    function B() {}
    B.prototype = A.prototype; // 原型链引用,改成B.prototype = new A();可以解决引用的问题
    B.prototype.propB = 'B'; // 函数重载
    B.prototype.constructor = B;
    var b = new B();
    ```
    A、B的prototype引用同一个地址,实时上A的prototype.constructor已经被改成了B

    3. 借用空函数的prototype,类似YUI的实现:
    ``` javascript
    function extend(sub, sup) {
        var _f = function() {};
        _f.prototype = sup.prototype;
        sub.prototype = new _f();
        sub.prototype.constructor = sub;
        sub.super = sup.prototype;// 保存原构造函数
        _f = null;
    }
    A.prototype.propA = 'a';
    A.prototype.propB = 'b';
    function B() {}
    extend(B, A);
    ```

    构造函数的继承,重要的是理解原型链`prototype chain`,继承基本就是原型链的拷贝或者引用。

    理解原型链`prototype chain`:
    ``` javascript
    function A() {}
    function B() {}
    B.prototype = new A();
    function C(x, y) {}
    C.prototype = new B();
    var c = new C();
    c.__proto__ === C.prototype;// true
    B.prototype.__proto__ === A.prototype;// true
    B.__proto__ === B.prototype;// true
    A.__proto__ === Function.prototype;// true
    A.prototype.__proto__ === Object.prototype;// true
    ```
    ***__proto__属性***:对象的`__proto__`指向`Object.prototype`,Function对象的`__proto__`指向构造函数的prototype。

3. 类式继承:本质上还是使用构造函数的`prototype`,封装成类,典型的例子是jQuery之父*John Resig*的[Simple JavaScript Inheritance](http://ejohn.org/blog/simple-javascript-inheritance/),其他类库也有各自的实现

    * Simple Inheritance的用法
    ``` javascript
    var Person = Class.extend({
        init: function(gender) {
            this.gender = gender;
        }
    });
    var Teacher = Person.extend({
        init: funciton(gender, name) {
            this._super(gender);
            this.name = name;
        },
        role: 'teacher',
        speek: function() {
            console.log('Hello, i am a %s.', this.role);
        }
    });
    var Student = Person.extend({
        init: funciton(gender, name) {
            this._super(gender);
            this.name = name;
        },
        role: 'student',
        speek: function() {
            console.log('Hello, i am a %s.', this.role);
        }
    });
    ```
函数式编程、作用域、闭包、THIS
  • 实参、形参 javascript foo(1, 2); function foo(a, b, c) { console.log(arguments.length);//2 实际传入的参数 console.log(foo.length);//3 期望传入的参数 }
  • 函数申明与函数表达式 javascript function foo() {} // 函数申明 var foor = function foo() {};// 函数表达式 执行顺序:解析器会率先读取函数声明,所以在任何代码执行前函数申明可用 javascript fn(2); // 4 function fn(n) {console.log(n);} fn(2); // 4 function fn(n) {console.log(n*n);} //重载 fn(2); // 4 var fn = function(n) {console.log(++n);};// 函数表达式,按照申明的顺序执行 fn(2); // 3
  • arguments, callee, caller, apply, call
    • arguments,类数组,类似的还有NodeList、classList等对象。根据ECMA-262的标准,arguments属性是基于传入的参数来新建arguments,不是基于命名参数的数量。
    • arguments.callee,返回正在执行的Function对象的一个引用 javascript function foo(n) { console.log(arguments.callee.arguments.length); console.log(arguments.callee.length); } foo(1, 2, 3);// 分别打出3,1
    • arguments.caller,返回调用这个Function对象的Function对象的引用
    • applycall,传参不同,功能相同,都是把Function对象绑定到另外一个对象上去执行,其内的this指向这个对象
  • 作用域
    • 函数的局部变量:函数形参、函数内部var声明的变量
    • 变量的查找(作用域链):查找函数内部变量 -> 查找嵌套的外部函数 …-> 查找window对象 -> 未定义
    • js中没有块级作用域,可以用匿名函数模拟
    • 未用关键字var申明的变量,会自动升级为全局变量挂到window上
    • 顶级作用域内使用var申明的变量是window对象的一个属性
  • 闭包
    • 由于作用域的限制,函数外部不能访问函数内部的局部变量
    • 闭包就是能够读取其他函数内部变量的函数引自学习Javascript闭包 javascript function foo() { var x = 1; return function fn() { // closure return x; } } var bar = foo(); console.log(bar()); // get the local variables in foo
    • 闭包的另一个作用是在内存中保存函数的局部变量,这有可能导致内存泄露
  • this:函数中的this始终指向函数的调用者 javascript function foo(x) { this.x = x; } foo(1); // 调用者是window,也可以window.foo() console.log(window.x); // 1 var o = {}; o.foo = foo; o.foo(2); // 调用者是o console.log(o.x); // 2 console.log(window.x); // 1 这里有一篇详细的例子
AJAX(XMLHTTPREQUEST VS ACTIVEXOBJECT)
  • 请求过程
    • 建立到服务器的新请求:xhr.open()
    • 向服务器发送请求:xhr.send()
    • 退出当前请求:xhr.abort()
    • 查询当前HTML的就绪状态:xhr.readyState
    • 服务器返回的请求响应文本:xhr.responseText
  • REST API:POST, GET, PUT, DELETE
    • GET:更多的用于操作,参数暴露到url,(服务器端可能对)url长度有限制
    • POST:更多的用于操作
  • HTTP状态码
  • XHR2

跨域问题

  • 跨域的形成(同源限制):主域、子域、ip和域名、协议不同、端口不同
  • 常用解决方案
    • iframe+document.domain:适用于垮子域的情况 缺点是如果一个域名下存在安全问题,另一个域名下可能也会有问题,还有就是创建iframe的开销
    • 动态引入js脚本:适合所有的跨域场景 引入的脚本会立刻执行,存在安全风险 要与远端沟通约定变量,增加了开发和维护成本
    • iframe+location.hash:适合各种场景下跨域 iframe嵌套引用,开销更大 会产生历史记录,url中暴露传递的内容
    • iframe+window.name:使用iframe的window.name从外域传递数据到本地域,适合各种场景下跨域且数据安全 缺点是数据有大小限制
    • postMessage跨域通讯

jQuery

可阅读yuanyan同学的jQuery编程实践

安全问题

  • XSS
  • CSRF
  • SQL注入
  • 敏感信息采用安全传输(SSL/HTTPS)
  • 上传限制(大小、mime类型、可执行文件)
  • (服务器端)严格的路径限制,比如杜绝路径跳转

css

  • css盒子模型
  • css的继承规则
  • IE低版本的hacks
  • 浏览器的怪异模式与标准模式

性能优化(最佳实践)

HTML优化

  • 语意化html结构:SEO友好,利于维护
  • 精简html结构:嵌套过复杂的结构会导致浏览器构建DOM树缓慢
  • html最小化:html大小直接关系到下载速度,移除内联的css,javascript,甚至模板片,有条件的话尽可能压缩html,去除注释、空行等无用文本
  • 总是设置文档字符集:如果不设置,浏览器在渲染页面前会做一些查找,先搜索可进行解析的字符
  • 显式设置图片的宽高:减少页面重绘(参考【高性能前端1】高性能HTML
  • 去除空链接属性(imglinkscriptiframe元素的srchref属性被设置了,但是属性却为空):部分浏览器依然会去请求空地址
  • 正确的闭合标签:浏览器不一定会将它们修复成正确的格式
  • 避免@import引入样式表:IE低版本浏览器会再页面构建好之后再去加载import的样式表,会导致白屏
  • 样式表放head里,脚本延后引入
  • 未完待续。。。

CSS优化

  • 避免css表达式:css表达式会不断的重复计算,导致页面性能下降
  • 避免AlphaImageLoader滤镜:这个滤镜的问题在于浏览器加载图片时它会终止内容的呈现并且冻结浏览器(引自【高性能前端1】高性能CSS
  • 合并图片(css sprites)
  • 尽量避免通配符选择器:CSS选择器是从右到左进行规则匹配,基于这个机制,浏览器会查找所有同类节点然后逐级往上查找,知道根节点,这样效率很低
  • 尽量避免属性选择器(\*=, |=, ^=, $=, ~=):正则表达式匹配比基于类别的匹配慢
  • 移除无匹配的规则:缩减文档体积;浏览器会把所有的样式规则都解析后索引起来,即使是当前页面无匹配的规则
  • 合并多条可合并的规则,使用简写: css .box {margin-top: 10px; margin-left: 5px; margin-bottom: 15px;} /* bad */ .box {margin: 10px 0 15px 5px;} /* better */
  • 对IE浏览器单独使用hack:代码清晰易读,同时也减小样式体积
  • 模块化css,最好能够组件化:查找、维护方便,同时也利于代码复用
  • 完善注释
  • 未完待列。。

JavaScript优化

  • 尽量减少或最少化对DOM的操作(脱离文档流对DOM进行修改)
    • 隐藏元素,对其进行修改之后再显示
    • 使用文档片段DocumentFragement批量修改,最后再插入文档
    • 将元素拷贝一份,修改完之后再替换原有元素
  • 谨慎操作节点集合NodeList(images, links, forms, document.getElementsByTagName): 缓存NodeList以及NodeList.length的引用
  • 尽量操作元素节点(DOM节点如childNodes, firstChild不区分元素节点和其他类型节点,但大部分情况下只需要访问元素节点引自《高性能JavaScript》):
    • children代替childNodes
    • childElementCount代替childNodes.length
    • firstElementChild代替firstChild
  • 读写分离,减少layout: javascript x = box.offsetLeft; // read box.offsetLeft = '100px'; // write y = box.offsetTop; // read box.offsetTop = '100px'; // write 这个过程造成了两次的layout,可做如下改造:javascript x = box.offsetLeft; // read y = box.offsetTop; // read box.offsetLeft = '100px'; // write box.offsetTop = '100px'; // write
  • 最小化重排(repeat): javascript box.style.width = '100px'; box.style.heihgt = '50px;'; box.style.left = '200px'; 三个操作都会重新计算元素的几何结构,在部分浏览器可能会导致3次重排,可做如下改写:javascript var css = 'width: 100px; height: 50px; left: 200px;'; box.style.cssText += css;
  • 使用事件委托:充分利用冒泡机制,减少事件绑定
  • 无阻塞加载:脚本延后加载,合并加载,并行加载
  • 函数内部的变量尽可能使用局部变量,缩短变量作用域的查找时间
  • 缓存对象引用: javascript var a = $('#box .a'); var b = $('#box .b'); 可以缓存$('#box')到临时变量: javascript var box = $('#box'); var a = box.find('.a'); var b = box.find('.b');
  • 减少多级引用: javascript var $P = Jx().UI.Pager.create();// 同样可以先缓存结果
  • 缓存Ajax:
    • 缓存Ajax数据,利用本地存储或者临时变量,存储不需要实时更新的数据
    • 设置HTTP Expires信息
  • 复杂的计算考虑使用Web Worker

jQuery性能优化

合理使用选择器
  • id和标签选择器最快,因为是直接调用原生API javascript $('#box'); // document.getElementById | document.querySelector $('div'); // document.getElementsByTagName
  • 类选择器在低版本浏览器较慢,伪元素、属性选择器在不支持querySelector的浏览器很慢
  • 尽可能优先使用符合CSS语法规范的CSS选择器表达式,以此来避免使用jQuery自定义的选择器表达式,因为当jQuery遇到单个id, 标签名,类名,选择器就会快速调用浏览器支持的DOM方法查询 javascript $('input[checked="checked"]'); // 比较快 $('input:checked'); // 较慢
  • 优先选择$.fn.find查找子元素,因为find之前的选择器并没有使用 jQuery 自带的 Sizzle 选择器引擎,而是使用原生API查找元素 javascript $('#parent').find('.child'); // 最快 $('.child', $('#parent')); // 较快,内部会转换成第一条语句的形式,性能有一定损耗 $('#parent .child'); // 不如上一个语句块
  • 使用组合选择器时,尽可能让右端更明确,因为Sizzle引擎是从右到左进行匹配的 javascript $('div.foo .bar'); // slow $('.foo div.bar'); // faster
  • 避免过度具体,简洁的 DOM 结构也有助于提升选择器的性能 javascript $('.foo .bar .baz'); $('.foo div.baz'); // better
  • 尽量避免使用通配符选择器
尽可能的少创建JQUERY对象
  • document.getElementById('el')$('#el')
  • 如获取元素id: javascript $('div').click(function(e) { // 生成了个jQuery对象 var id = $(this).attr('id'); // 这样更直接 var id = this.id; });
  • 使用链式调用缓存jQuery对象 xml <div id="user" class="none"> <p class="name"></p> <p class="city"></p> </div> javascript $('#user') .find('.name').html('zhangsan').end() .find('.city').html('shenzhen').end() .removeClass('none');
  • 做好jQuery对象缓存 javascript var box = $('.box'); box.find('> .cls1'); box.find('> .cls2');
避免频繁操作DOM
  • 复杂操作把元素从DOM中移除再操作 javascript var $el = $('.box').detach(); var $p = $el.parent(); // do some stuff with $el... $p.append($el);
  • 在循环外执行DOM修改 javascript // 性能差 $.each(arr, function(i, el) { $('.box').prepend($(el)); }); // 较好的做法 var frag = document.createDocumentFragment(); $.each(arr, function(i, el) { flag.appendChild(el); }); $('.box')[0].appendChild(flag);
使用事件代理
$('ul li').on('click', fn);
// better
$('ul').on('click', 'li', fn);

 

使用事件代理(委托),当有新元素添加进来的时候,不需要再为它绑定事件,这里有demo可以查看效果。

整体优化

  • 雅虎34条:合并压缩文件和图片、gzip/deflate、CDN、HTTP头设置Cache-Control/Expires和Last-Modified/ETag、并行下载与DNS查询的平衡等
  • 缓存静态文件,尽可能采用CDN策略,并采用不带cookie的独立域名存放,并开启keep-alive
  • 动态与静态结合,服务器端拼凑页面片,最快展现给用户,缩短白屏时间和页面可用时间,非首屏数据懒加载
  • 内容分开存放,比如图片和ajax分别采用不用的服务器(域名下)
  • 保证单个html的http请求数最少
  • 确保网站有favicon.ico文件(浏览器会自动请求favicon.ico,如果不存在则会出现大量的404消耗带宽)
  • 未完待续。。。
By柏小白

html你好?

 

<!doctype html>
<html lang="zh-cn">
<head>
    <meta charset="UTF-8">
    <title>柏小白</title>
</head>
<body>

</body>
</html>
By柏小白

WebStorm 11.0.3 汉化包设置

WebStorm 10 汉化包 //链接:http://pan.baidu.com/s/1cghgPw 密码:noie
WebStorm 11 汉化包 //链接:http://pan.baidu.com/s/1kVdMWyb 密码:ap96

柏小白-教你汉化WebStorm 11.0.3

柏小白-教你汉化WebStorm 11.0.3

进入WebStorm 11.0.3 (我是安装后,帮助-关于-里面升级成功为11.0.4)
WebStorm 软件中 找到(lib)并进入,把你在百度里下载的 WebStorm_zh_CN-(resources_cn.jar)直接放进(lib)
完成了,重新启动 WebStorm 11.0.3 中文汉化完成。。。
传说:“IntelliJ IDEA Community Edition 15.0.4 也可以用这个(resources_cn.jar)”

翻译插件作者:Github

By柏小白

IIS部署 Web svg/woff/woff2字体 404错误

问题:最近在IIS上部署web项目的时候,发现浏览器总是报找不到woff、woff2字体的错误。导致浏览器加载字体报404错误。

原因:因为服务器IIS不认SVG,WOFF/WOFF2 这几个文件类型,只要在IIS上添加MIME 类型即可。

解决方法

1、打开服务器IIS管理器,找到MIME类型。

2222

 

 

2、添加MIME类型 添加三条:

文件扩展名      MIME类型

.svg             image/svg+xml
.woff            application/x-font-woff
.woff2          application/x-font-woff

1111

注:本文在win7环境下IIS7版本中填写的MIME类型,在IIS6、IIS8 MIME类型管理所处位置不一样,但是添加方式和参数均相同。

By柏小白

FTP版本发布搭建

Windws Server 2008 R2 WEB环境配置之FTP服务搭建
说来就搞笑之前都是,使用windows服务器 客户端-服务器端-安装百度云盘 做发布-来来回回好麻烦,一直想用以前使用过的FTP做静态版本发布,google了三篇有用的文章,现在做存档,方便下次查阅

没有FTP的伙伴狂点下载:

FTP下载链接:http://pan.baidu.com/s/1eREU63K 密码:qlxp

文章1:Windws Server 2008 R2 WEB环境配置之FTP服务搭建

FTP是一种文件传输协议,基于其可以使远距离的二台计算机之间复制文件变得更简单。所以今天我们来搭建一个简单、易用、安全的FTP服务环境。

市面上FTP软件不下2、3十款,最著名的就数SERV-U了,其功能强大,设置相对复杂,目前最新版本已经发布到15.0了,在其官网上可以下载到14.0的版本。

关于SERV-U的教程网上有很多,也有各种版本,但是今天我们不打算讲它。今天的主题讲二款FTP服务软件的搭建与设置,一款是Windows Server 2008 R2自带的FTP服务器软件,另一款就是开源且强大的Filezilla Server了。

 

IIS自带FTP搭建

1、先安装IIS FTP 角色服务。

打开“服务器管理器”,“角色”,如果是第一次安装IIS,则选择“添加角色”;如果你原先已经安装过 IIS ,则选择“添加角色服务”,然后选中“FTP服务器”即可。

我这里原先已经安装好了IIS,所以选择“添加角色服务”,

在选择角色服务窗口中,选中“FTP服务器”,

下一步,等待安装完毕。

2、新建FTP站点

FTP站点跟创建网站类似。

给站点起一个名称,指FTP站点的根目录,

填写ftp服务器的ip地址,端口,默认端口是21,

指定一个用户可以访问此FTP站点,你也可以选择所有用户。

然后再新建一个用户名为ftp的用户,

打开FTP客户端软件,填上IP地址,用户名,密码就可以连上了。

总结:因为IIS FTP的用户是系统用户,安全性也不是很高。在我的使用过程中,一直有连接不上的情况,就算是新建一个站点,一样的设置,一样的用户都有可能连接不上,研究了一下午,各种坑都有,所以我不推荐大家使用。

Filezilla Server FTP服务搭建

Filezilla Server是一款开源的FTP服务软件,占用资源小,设置简单。

目前官方最新版是0.9.48,可以在官网下载到。官网下载的是英文版,在安装时会安装一个myPCBackup的备份软件,这个软件我们一般不会用,可以在安装完后删除这个软件。

其实还有另一种安装方法。就是在本地安装过一次以后,可以把FileZilla Server目录拷贝出来,上传到服务器再使用。我用的就是这种安装方式。这是我拷贝出来的,提供FileZilla Server 0.9.48下载。

解压下载的FileZilla Server 0.9.48,把它放到c:\FileZilla Server目录下,右击FileZilla Server.exe以管理员身份运行安装,

安装,

加为系统服务,开机自动启动。

点是开启服务。

然后双击FileZilla Server Interface.exe,这个是FileZilla Server的管理工具,

Ip地址、端口默认即可,给管理员设置一个密码,点ok进行设置。

点击菜单栏上的“Edit”,“Users”,点击”Add”,新增一个用户,

我们没有建用户组,所以直接默认为<none>即可。

勾选“Password”,并设置一个密码。

点击左侧的”Shared folders”,点击“Add”添加一个FTP目录,

选中刚添加的目录,在右侧选中相应的权限,最后点OK即可。

这样就添加了一个用户名为user1,FTP目录为D:\FTP 的站点。

 

再在Windows 防火墙中添加一条入站规则,选择端口21。

FTP传输模式有被动和主动二种,所以我们需要在服务器上额外添加一些端口供被动模式使用。

打开FileZilla Server Interface.exe,点击菜单栏“Edit”,“Settings”,选中“Passive mode settings”,勾选右侧的“Use custom port range”,填入一组端口区间。

把上面的1700-1720端口添加到防火墙中,入站规则和出站规则都添加。

经过如此设置,不管是被动模式还是主动模式都能正常连接服务器了。

并且FileZilla的用户跟系统用户无关,所以安全性更高,故推荐。

 

最后用FTP 客户端软件测试。可以用FileZilla Client或FlashFXP,这二款客户端我用得最多。

原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。http://blog.postcha.com/read/9 Windws Server 2008 R2 WEB环境配置之FTP服务搭建

文章2.win7下简单FTP服务器搭建(试验成功)

    
本文介绍通过win7自带的IIS来搭建一个只能实现基本功能的FTP服务器,第一次装好WIN7后我愣是没整出来,后来查了一下网上资料经过试验后搭建成功,其实原理和步骤与windows前期的版本差不多,主要是对新的操作系统还不是很熟悉。相信用过WIN7一段时间的都能独立解决掉。

   
主要分为4个步骤
  
1.安装FTP服务

1

  2
2.在IIS控制面板里添加FTP站点
3
4

 

 

5
67

 

 

  8
3.配置FTP站点

  10

4.
测试站点是否正常工作
 ftp://192.168.10.13

11

文章3.Win7下的内置FTP组件的设置详解

  在局域网中共享文件,FTP是比较方便的方案之一。Win7内部集成了FTP,只是设置起来颇费一番功夫。着文以记之。

一、安装FTP组件

由于Win7默认没有安装FTP组件。故FTP的设置第一步就是安装FTP组件

点击:控制面板—》程序和功能—》打开或关闭Windows功能。勾选“FTP服务器”及“FTP服务”“FTP扩展性”,点击“确定”,安装FTP组件。如下图所示

二、添加FTP站点

点击:控制面板—》管理工具。选中“Internet信息服务(IIS)管理器”,如图

双击“Internet信息服务(IIS)管理器”。弹出管理器界面,如下图所示:

单击选中“网站”,并且在其上右击,选择“添加FTP站点”,出现“站点信息”界面,如下所示:

给FTP取名(本例是:zhu),以及设置FTP站点的物理路径(本例是:c:\ftp),点击“下一步”,出现“绑定和SSL设置”界面,如下图所示

IP设置为本机的IP地址,端口用FTP默认的21,SSL勾选“无”。点击“下一步”,出现“身份验证和授权信息”界面,如下图所示:

如果只是想设置简单的FTP,则“身份验证”和“授权”都勾选“匿名”,并且给匿名设置相应的权限。本例中,还要给FTP配置帐号,以及帐号的权限,故“身份验证”勾选“基本”,“授权”勾选“未选定”,点击“完成”,完成FTP站点的设置。

三、设置FTP帐号以及权限

由于Win7下的FTP帐号是Windows用户帐号。所以,先得添加两个用户帐号,一个是View,可以浏览、下载FTP内容;一个是Admin,完全控制FTP。

点击:控制面板—》管理工具—》计算机管理。在计算机管理的界面的左侧,点击:系统工具—》本地用户和组—》用户,右侧显示所有用户。如下图所示:

在“用户”上右击,出现“新用户”,如下所示:

在用户名中输入View,设置好密码,去掉勾选“用户下次登陆时须更改密码”,勾选“用户不能更改密码”和“密码永不过期”。点击“创建”,完成用户View的创建。同样的步骤,创建Admin用户。由于Windows默认将用户添加到Users组,你可以将刚才的两个用户从Users组中删除。方法是在“计算机管理”中点击“组”,在右侧的列表中找到Users,双击之,出现如下界面,点中用户View,点“删除”,点中用户Admin,点“删除”。将两个用户从Users组中删除。

接下来,在FTP站点中,给View和Admin添加权限。

点击:控制面板—》管理工具—》Internet信息服务(IIS)管理器。点中刚才新建的FTP站点。点中“FTP授权规则”。如下图所示:

点击右侧的“编辑权限”,对FTP站点文件夹添加用户权限。在弹出的窗口中,点击“安全”标签。,如下图所示:

点“编辑”,出现权限的窗口,如下:

点“添加”,在“输入对象名称来选择”中输入View,点“确定”,添加View用户。如下所示:

添加的View用户,默认是只有读取、列出的权限。在依法添加Admin用户,给Admin用户添加完全控制的权限。如下所示:

再回到“Internet信息服务(IIS)管理器”窗口,双击刚才选中的“FTP授权规则”,在FTP站点中对View和Admin授权。如下所示:

点击右侧的“添加允许规则”,在弹出的窗口中,勾选“指定的用户”,输入View,在下方的“权限”中,勾选“读取”。如下所示:

点“确定”,给FTP站点添加View用户,相应的权限是读取。再给FTP站点添加Admin用户,相应的权限是读取和写入。

至此,FTP的站点设置就完成了。站点文件夹是c:\ftp,View用户有读取(浏览和下载)的权限,Admin用户有读取和写入(上传和删除)的权限。当然,还可以根据实际的情况添加用户及相应的权限,也可以将用户添加进组,再给组设置权限。还可以添加匿名用户等等,不一而足了。

然而,事情远远没有结束。如果,你急于做测试的话。会发现,在本机上测试正常,但是用别的机器测试FTP的话,会发现连接不上。问题出在Win7下的防火墙。如果你把防火墙关掉,你会发现FTP恢复了正常,但你也不能因为要用FTP,就把Win7的防火墙关掉。要想在Win7开着防火墙的时候还要正常使用,还必须得在防火墙中进行一番设置

四、Win7的防火墙设置

点击:控制面板—》Windows防火墙。点击左侧的“允许程序或功能通过Windows防火墙”,选中“FTP服务器”,将后面的两个框都勾选,如下所示:

这是网上绝大多数介绍的防火墙设置。然而还不够,你做测试的话会发现,还是连接不上。还必须在防火墙中进一步做设置。

点击下方的“允许运行另一程序”,在弹出窗口里,点“浏览”,找到C:\Windows\System32\inetsrv\inetinfo.exe,点添加,也就是上图中的Internet Infomation Services。将后面的两个框也都选中。因为在Win7下,FTP是IIS的一个组件,因此也必须在防火墙中将IIS设置为允许。而IIS又不在默认的列表中,因此得手动添加。

遗憾的是,这样设置,FTP还是不能正常使用。由于FTP用的是21端口,因此在防火墙中还得添加出站和入站的端口规则。

在Windows防火墙窗口里,点击左侧的“高级设置”,弹出高级安全防火墙窗口,点击左侧的“入站规则”,如下图所示:

点击右侧的“新建规则”,出现向导界面,勾选“端口”,如图:

点击“下一步”,勾选TCP(FTP用的是TCP协议),再勾选特定本地端口,输入21(FTP用的是21端口)如图所示:

点击“下一步”,勾选“允许连接”,如图:

点击“下一步”,默认的都选上,如图:

点击“下一步”,在名称里输入名字,本例中是21,如图

点击“完成”,完成入站规则的设置,在用同样的方法,完成出站规则的设置,同样是21端口。

至此,在Win7的防火墙就已经设置好了。现在测试基本上就正常了。

 

不过,还有个小问题:

在用IE浏览FTP的时候,虽然可以登录,但是没法显示FTP内容。这个是IE的设置问题。在Internet选项中,将“使用被动FTP(用于防火墙和DSL调制解调器的兼容性)”勾掉就解决了不能浏览的问题。如下图所示:

 

后序。总体来说,Win7的内置FTP设置比一些第三方的FTP软件设置要繁琐一些。但是在某些场合下,还只能用Win7的内置FTP。以上的内容都是网上搜集来的,加上本人的亲测。如果谁在FTP设置上还有什么问题,欢迎交流。

作者:万仓一黍
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
By柏小白

jquery的checkbox,radio,select等方法总结

jquery的checkbox,radio,和select是jquery操作的一个难点和重点,很多前端新手对其了解不是很透彻。时间久了不用,我在写的时候有时也难免对某些操作支支吾吾,记不清楚,现在,对其做一些简单的总结!

1、checkbox日常jquery操作。

现在我们以下面的html为例进行checkbox的操作。

<input id="checkAll" type="checkbox" />全选
<input name="subBox" type="checkbox" />项1
<input name="subBox" type="checkbox" />项2
<input name="subBox" type="checkbox" />项3
<input name="subBox" type="checkbox" />项4

Read More

By柏小白

jquery编程的标准写法和最佳实践(jquery代码规范)

关于变量

1、jQuery类型的变量最好加个$前缀。

2、时常将jQuery选择器返回的内容存进变量以便重用

var $myDiv = $("#myDiv");
$myDiv.click(function(){...});

Read More