Author Archive 柏小白

By柏小白

apicloud实现短信验证功能

短信验证码SDK,为开发者提供全球通用的短信验证码工具,开发者可以用其在App植入短信验证码SDK、简单设置即可实现短信验证功能,集成快速便捷,且后期易于管理。

配置集成 开发者使用本模块之前需要先到Mob官网申请开发者账号,并在账号内填写相应信息创建自己的 APP,从而获取AppKeyAppSecret,然后添加SMSSDK功能,获取模板id。 详情参考:快速集成获取apppkey和appSecret

一. 准备工作

下载并安装开发工具:APICloud Studio 2

二. 创建应用

APICloud提供了两种创建应用的方式,方便开发者在云端或APICloud Studio中创建应用。 云端创建应用:

1) 注册并登录APICloud系统:https://www.apicloud.com/console 点击左上角“创建应用”, 如图:选择“Native”,填写“名称”及“说明”,应用创建完成。

1

APICloud Studio中创建应用:

1) 登录APICloud Studio,没有账号点击“注册账号”,已经注册,用之前注册的APICloud账号登录APICloud Studio

2

这2端可以相互同步信息:

同步本地应用到云端资源库,开发者在APICloud Studio创建的应用会和云端资源库建立连接。项目代码改动后,可以使用APICloud Studio的代码提交功能提交代码到云端资源库。

三. 添加模块

打开APICloud云端,同时添加SMSSDK模块、mobtools模块:

4

四. 模块使用攻略

Android: 使用此模块之前android需先配置config.xml文件,方法如下

<meta-data name="Mob-AppKey" value="moba6b6c6d6"/>
<meta-data name="Mob-AppSecret" value="b89d2427a3bc7ad1aea1e1e8c1d36bf3"/>

IOS: ios 需要将Info.plist 文件放入res目录下,文件内容内容:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>MOBAppKey</key>
<string>moba6b6c6d6</string>
<key>MOBAppSecret</key>
<string>b89d2427a3bc7ad1aea1e1e8c1d36bf3</string>
</dict>
</plist>

字段描述:

  • Mob-AppKey:(必须配置)从Mob官网获取的 AppKey。
  • Mob-AppSecret:(必须配置)从Mob官网获取的 AppSecret。 申请方法参考快速集成获取apppkey和appSecret

编译app时iOS 请配置访问联系人的权限

5

Demo实例widget下载地址

五. 模块接口说明

需要引入模块: var moduleSMSSDK = api.require('smssdk'); (1)获取文本验证码 getTextCode({params}, callback(ret,err)) params:

phoneNumber:

类型:字符串

默认值:无

描述:手机号

zone:

类型:字符串

默认值:无

描述:区域号,不要加"+"号

tempCode:

类型:字符串

默认值:无

描述:模板id

callback(ret,err) ret:

  • 类型:JSON 对象
  • 内部字段: { smart:0 //是否为智能验证 bool类型, ios 忽略此字段 }

err:

  • 类型:JSON 对象
  • 内部字段:
{
    code:0    //错误码(详见错误码常量)
    msg:""    //错误描述
};

示例代码

var param = {zone:'86', phoneNumber:'18500000000',tempCode:'1319972'};
moduleSMSSDK.getTextCode(param, function(ret, err){
    if (err !== null && err !== undefined && err !== '') {
     // 错误消息示例:{"msg":"Template not exist.","code":484}
    alert("Error:\n" + JSON.stringify(err));
    } else {
        // 正常消息示例:{"smart":false}
       alert("Success:\n" + JSON.stringify(ret));
    }
    });

(2)获取语音验证码 getVoiceCode({params}, callback(ret, err)) params:

phoneNumber:

类型:字符串

默认值:无

描述:手机号

zone:

类型:字符串

默认值:无

描述:区域号,不要加"+"号

callback(ret, err) ret:

  • 类型:JSON 对象 内部字段: { }

err:

  • 类型:JSON 对象
  • 内部字段:
{
    code:0    //错误码(详见错误码常量)
    msg:""    //错误描述
};

示例代码:

// param中的key命名不能改变
var param = {zone:'86', phoneNumber:'18500000000'};
moduleSMSSDK.getVoiceCode(param, function(ret, err){
  if (err !== null && err !== undefined && err !== '') {
   // 错误消息示例:{"msg":"Template not exist.","code":484}
   alert("Error:\n" + JSON.stringify(err));
  } else {
     // 正常消息示例:{}
    alert("Success:\n" + JSON.stringify(ret));
    }
   });

(3)提交验证码 commitCode({params}, callback(ret, err)) params:

phoneNumber:

类型:字符串

默认值:无

描述:手机号

zone:

类型:字符串

默认值:无

描述:区域号,不要加"+"号

code:

类型:字符串

默认值:无

描述:验证码

callback(ret, err) ret:

  • 类型:JSON 对象 内部字段: { }

err:

  • 类型:JSON 对象
  • 内部字段:
{
    code:0    //错误码(详见错误码常量)
    msg:""    //错误描述
};

示例代码:

// param中的key命名不能改变
var param = {zone:'86', phoneNumber:'18500000000', code:'4847'};
moduleSMSSDK.commitCode(param, function(ret, err){
if (err !== null && err !== undefined && err !== '') {
  // 错误消息示例:{"msg":"Template not exist.","code":484}
  alert("Error:\n" + JSON.stringify(err));
  } else {

  }
  });

(4)获取区号 getSupportedCountries(callback(ret, err)) callback(ret, err) ret:

  • 类型:JSON 对象
  • 内部字段:
{
    countries =
    (
        {
        rule = "^\\d+";
        zone = 1868;
        }
    )
}

err:

  • 类型:JSON 对象
  • 内部字段:
{
    code:0    //错误码(详见错误码常量)
    msg:""    //错误描述
};

示例代码:

// param中的key命名不能改变
moduleSMSSDK.getSupportedCountries(function(ret, err){
    if (err !== null && err !== undefined && err !== '') {
     // 错误消息示例:{"msg":"Template not exist.","code":484}
      alert("Error:\n" + JSON.stringify(err));
     } else {
      // 正常消息示例:{"countries":[{zone=590, rule=^\d+},{zone=680, rule=^\d+}]}
        alert("Success:\n" + JSON.stringify(ret));
    }
  });

(5)获取通讯里好友信息 getFriends(callback(ret, err)) callback(ret, err) ret:

  • 类型:JSON 对象
  • 内部字段:
{
    friends =
    (
     {
        lastname : "你好";
        others =     (
                {
                desc = "董浩";
                phone = 10101155;
                type = 1;
            }
        );
        phones =     (
                    {
                desc = "董浩";
                phone = 10101155;
                type = 1;
            }
        );
        recordid = 411;
        specialdate =     (
                    {
                desc = "生日";
                date = "1988-07-08";
                type = 1;
            }
        );
    }
    )
}

err:

  • 类型:JSON 对象
  • 内部字段:
{
    code:0    //错误码(详见错误码常量)
    msg:""    //错误描述
};

示例代码:

// param中的key命名不能改变
moduleSMSSDK.getFriends(function(ret, err){
   if (err !== null && err !== undefined && err !== '') {
    // 错误消息示例:{"msg":"Template not exist.","code":484}
    alert("Error:\n" + JSON.stringify(err));
   } else {
    // 正常消息示例:{"countries":[{zone=590, rule=^\d+}, {zone=680, rule=^\d+}]}
     alert("Success:\n" + JSON.stringify(ret));
    }
 });

(6)提交用户资料 submitUserInfo({params}, callback(ret, err)) params:

uid:

类型:字符串

默认值:无

描述:用户id

nickname:

类型:字符串

默认值:无

描述:用户昵称

avatar:

类型:字符串

默认值:无

描述:头像地址

phoneNumber:

类型:字符串

默认值:无

描述:手机号

zone:

类型:字符串

默认值:无

描述:区域号,不要加"+"号

callback(ret, err) ret:

  • 类型:JSON 对象
  • 内部字段: { }

err:

  • 类型:JSON 对象
  • 内部字段:
{
    code:0    //错误码(详见错误码常量)
    msg:""    //错误描述
};`

示例代码:

// param中的key命名不能改变
var uid = "3241241";
var nickname = "SmsSDK_Api_Cloud_User_" + uid;
var avatar = "http://download.sdk.mob.com/510/deb/0c0731ac543eb71311c482a2e2.png";
// param中的key命名不能改变
var param = {uid:uid, nickname:nickname, avatar:avatar, phoneNumber:'18500000000', zone:'86'};

moduleSMSSDK.submitUserInfo(param, function(ret, err){
if (err !== null && err !== undefined && err !== '') {
// 错误消息示例:{"msg":"Template not exist.","code":484}
alert("Error:\n" + JSON.stringify(err));
} else {
}
});

(7)获取版本号 getVersion(callback(ret, err)) callback(ret,err) ret

  • 类型:JSON 对象
  • 内部字段: { version: "1.0.0" }

err

  • 类型:JSON 对象
  • 内部字段: { }

示例代码:

// param中的key命名不能改变
moduleSMSSDK.getVersion(function(ret, err){
if (err !== null && err !== undefined && err !== '') {
// 错误消息示例:{"msg":"Template not exist.","code":484}
alert("Error:\n" + JSON.stringify(err));
} else {
// 正常消息示例:{"version":'3.2.2'}
}
});

(8)是否允许访问通讯录好友 enableWarn({params}) params:

isWarn:

类型:布尔

默认值:true

描述:YES 代表启用 NO 代表不启用 默认为启用

示例代码:

// param中的key命名不能改变
var isWarn = true;
// param中的key命名不能改变
var param = {isWarn:isWarn};
moduleSMSSDK.enableWarn(param);
By柏小白

Nginx配置一键生成

关于Nginx部署、配置的文章网上已经发布过很多,包括我自己也私藏了不少还发布过两篇:

整理出来为的就是需要的时候,复制、粘贴就能使用。

然而千奇百怪的实际开发中,你肯定需要增删Nginx配置。你就得上网搜一下,复制粘贴出bug了又得调一下…

搞定还得保存下来以备后患。多了不好找还得整理…就搞得很麻烦

后果

今天我给大家推荐一款”Nginx配置利器”,配配变量就能一键生成常用配置。和繁琐低效配置说再见👋


网站链接:

nginxconfig 目前支持:

  • Angular、React、Vue、Node.js
  • PHP、Python
  • wordpress、Magento、Drupal
  • 缓存、Https、日志等各种配置…

使用

实现用户访问*.myweb.com域名自动跳转到myweb.com配置,并且开启http强制跳转到https的配置。

图片描述
图片描述

配置完之后,下方还有安装步骤指导你配置生效。交互体验相当好

图片描述

生成配置 /etc/nginx/sites-available/myweb.com.conf 如下:

server {
	listen 443 ssl http2;
	listen [::]:443 ssl http2;

	server_name myweb.com;
	root /var/www/myweb.com/public;

	# SSL
	ssl_certificate /etc/letsencrypt/live/myweb.com/fullchain.pem;
	ssl_certificate_key /etc/letsencrypt/live/myweb.com/privkey.pem;
	ssl_trusted_certificate /etc/letsencrypt/live/myweb.com/chain.pem;

	# security
	include nginxconfig.io/security.conf;

	# index.html fallback
	location / {
		try_files $uri $uri/ /index.html;
	}

	# additional config
	include nginxconfig.io/general.conf;
}

# subdomains redirect
server {
	listen 443 ssl http2;
	listen [::]:443 ssl http2;

	server_name *.myweb.com;

	# SSL
	ssl_certificate /etc/letsencrypt/live/myweb.com/fullchain.pem;
	ssl_certificate_key /etc/letsencrypt/live/myweb.com/privkey.pem;
	ssl_trusted_certificate /etc/letsencrypt/live/myweb.com/chain.pem;

	return 301 https://myweb.com$request_uri;
}

# HTTP redirect
server {
	listen 80;
	listen [::]:80;

	server_name .myweb.com;

	include nginxconfig.io/letsencrypt.conf;

	location / {
		return 301 https://myweb.com$request_uri;
	}
}
复制代码

网站下方还罗列了推荐的nginx配置、安全配置…以作参考/etc/nginx/nginx.conf

# Generated by nginxconfig.io
# https://nginxconfig.io/?0.domain=myweb.com&0.php=false&0.index=index.html&0.fallback_html

user www-data;
pid /run/nginx.pid;
worker_processes auto;
worker_rlimit_nofile 65535;

events {
	multi_accept on;
	worker_connections 65535;
}

http {
	charset utf-8;
	sendfile on;
	tcp_nopush on;
	tcp_nodelay on;
	server_tokens off;
	log_not_found off;
	types_hash_max_size 2048;
	client_max_body_size 16M;

	# MIME
	include mime.types;
	default_type application/octet-stream;

	# logging
	access_log /var/log/nginx/access.log;
	error_log /var/log/nginx/error.log warn;

	# SSL
	ssl_session_timeout 1d;
	ssl_session_cache shared:SSL:10m;
	ssl_session_tickets off;

	# Diffie-Hellman parameter for DHE ciphersuites
	ssl_dhparam /etc/nginx/dhparam.pem;

	# Mozilla Intermediate configuration
	ssl_protocols TLSv1.2 TLSv1.3;
	ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;

	# OCSP Stapling
	ssl_stapling on;
	ssl_stapling_verify on;
	resolver 1.1.1.1 1.0.0.1 8.8.8.8 8.8.4.4 208.67.222.222 208.67.220.220 valid=60s;
	resolver_timeout 2s;

	# load configs
	include /etc/nginx/conf.d/*.conf;
	include /etc/nginx/sites-enabled/*;
}
复制代码

/etc/nginx/nginxconfig.io/security.conf

# security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;

# . files
location ~ /\.(?!well-known) {
	deny all;
}
复制代码

拓展

以上就满足日常开发需求啦。如果你压抑不住,想要展示你的高端操作。
你可以加入到项目本身开发中;nginxconfig项目本身是MIT开源协议,你也可以在此基础上迭代出自己的版本

作者:锐玩道
链接:https://juejin.im/post/5dbb88e56fb9a0208055c5fa
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

By柏小白

前端Nginx学习笔记

 前端Nginx学习笔记

nginx简介

1.nginx是一个高性能的Web服务器和反向代理服务器,也可作为电子邮件代理服务器。
2.在连接高并发的情况下,nginx是Apache服务不错的替代品,能够支持高达 50,000 个并发连接数的响应。

正向代理与反向代理

1.反向代理是指以代理服务器来接受Internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回到Internet上请求连接的客户端,此时代理服务器对外表现为一个反向代理服务器。
2.正向代理是指用户无法访问某网站,但是可以访问某代理服务器,而代理服务器可以访问该网站。于是用户通过访问代理服务器去访问该网站,代理服务器把响应信息返回给用户。
3.反向代理中用户访问的IP和端口是nginx服务器的,不知道提供服务的底层服务器,底层服务器在内网中,对外公开的是nginx服务器,nginx充当中间层。而正向代理中用户是知道目标服务器的域名信息的,知只是迫于网络的限制无法访问,如最常见的访问外网。

nginx安装与启动

nginx有windows版本和linux版本,一般针对项目需求是在Linux部署nginx服务器。

下载地址

nginx.org/en/download…

windows版本下载一个压缩包,解压即可
1.文件路径必须为英文,否则启动不成功。
2.查看端口占用,nginx服务器默认启动80端口。
cmd中

  • netstat -an  显示出电脑中所有被打开的端口列表
  • netstat -ano  显示出所有占用端口的列表
  • netstat -ano | findstr “80”  显示出80端口占用的详细情况
  • tasklist | findstr “80”    查询端口具体哪个应用占用

Netstat是在内核中访问网络连接状态及其相关信息的程序,它能提供TCP连接,TCP和UDP监听,进程内存管理的相关报告。

启动成功

  • 启动方式1:双击nginx.exe
  • 启动方式2:start nginx
  • 关闭方式1: 结束进程(两个进程)
  • 关闭方式2:nginx -s stop

nginx配置文件

nginx的核心配置文件nginx.conf主要由3个部分组成

  • 基本配置

#user  nobody; #配置worker进程运行用户
worker_processes  1; #配置工作进程数目,根据硬件调整,通常等于CPU数量或者2倍于CPU数量

#error_log  logs/error.log; #配置全局错误日志及类型 [debug|info|notice|warn|error|crit(致命错误)]默认error
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid; #配置进程pid文件

复制代码
  • events配置
#配置工作模式和连接数
events {
    # use epoll; #事件处理模型优化
    worker_connections  1024; #配置每个worker进程连接数上限,nginx支持的总连接数等于worker_connections*worker_processes
    # 我的本双核四线程,多任务运行弱,CPU主频2.4GHz,运行缓慢
}
复制代码
  • http配置,基本配置和多个server配置
http {
    include       mime.types;
    default_type  application/octet-stream;

    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';
    
    #配置access_log日志及存放路径,并使用上面定义的main日志格式
    #access_log  logs/access.log  main;

    sendfile        on; #开启高效文件传输模式
    #tcp_nopush     on; #防止网络阻塞

    #keepalive_timeout  0;
    keepalive_timeout  65; #长连接超时时间,单位是秒
    #gzip  on; #开启gzip压缩输出

    #可以配置多个server
    server {
        listen       80; #配置监听端口
        server_name  localhost; #配置服务名

        #charset koi8-r; #配置字符集(俄罗斯字符集)      
        #access_log  logs/host.access.log  main;

        #默认的匹配斜杠/的请求,当访问路径中有/,会被该localtion匹配到并进行处理
        #nginx根目录 /html/index.html
        location / {
            root   html; #root根目录,nginx安装主目录下的html目录
            index  index.html index.htm; #配置首页文件的名称
        }

        #error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html; #配置50x错误页面 html/50x.html
        #精确匹配
        location = /50x.html {
            root   html;
        }

        #PHP脚本请求全部转发道到Apache处理
        # proxy the PHP scripts to Apache listening on 127.0.0.1:80
        #
        #location ~ \.php$ {
        #    proxy_pass   http://127.0.0.1;
        #}

        #PHP脚本请求全部转发道到FastCGI处理
        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        #location ~ \.php$ {
        #    root           html;
        #    fastcgi_pass   127.0.0.1:9000;
        #    fastcgi_index  index.php;
        #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
        #    include        fastcgi_params;
        #}
        
        # 禁止访问.htaccess文件-通常是禁止外网访问的文件
        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        #location ~ /\.ht {
        #    deny  all;
        #}
    }

    # another virtual host using mix of IP-, name-, and port-based configuration
    #
    #server {
    #    listen       8000;
    #    listen       somename:8080;
    #    server_name  somename  alias  another.alias;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}

    #配置https服务,安全的网络传输协议,加密传输,端口443
    # HTTPS server
    #
    #server {
    #    listen       443 ssl;
    #    server_name  localhost;

    #    ssl_certificate      cert.pem; #证书
    #    ssl_certificate_key  cert.key; #秘钥

    #    ssl_session_cache    shared:SSL:1m;
    #    ssl_session_timeout  5m;

    #    ssl_ciphers  HIGH:!aNULL:!MD5;
    #    ssl_prefer_server_ciphers  on;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}

}
复制代码

nginx的主要应用

1.静态网站

nginx是一个http的web服务器,可以将服务器上的静态文件(html、图片等)通过http协议返回给浏览器客户端;若不配置location,nginx默认查找根目录html中的index.html文件。

    server {
        listen       8080;
        server_name  localhost;
        location / {
	    root   wangyi/static; #root= ip+端口 
            index  index.html index.htm;
        }
        #访问:localhost:8080,或如下配置
         location /static {  
	    root   wangyi;  #注意分号
            index  index.html index.htm;
        }
        #访问:localhost:8080或localhost:8080/static
        .......
    }
复制代码

2.负载均衡

网站服务器由多台服务器组成一个集群对外提供服务,当用户输入域名进行访问的时候,负载均衡负责将用户请求分发到集群中的不同服务器,从而提高并发处理能力。nginx作为访问的统一入口,分发请求,实现负载均衡。
负载均衡实现方式有硬件负载均衡和软件负载均衡。

nginx负载均衡

nginx通过在nginx.conf配置文件中配置实现负载均衡
1.首先在http模块配置

upstream network1{
    server 127.0.0.1:3000 weight=3; #权重
    server 127.0.0.1:5000 weight=1; 
}
复制代码

weight表示权重,用于后端服务器性能不均的情况,访问比率约等于权重之比,权重越大,被访问的几率越大。
upstream是配置nginx与后端服务器负载均衡非常重要的一个模块,他还能对后端服务器的健康状态进行检查,若后端服务器中有一台发生故障,则前端请求不会转发到该故障机器。
2.然后在server模块里配置

localtion /webname{
    proxy_pass http://network1; 
}
复制代码

参数‘http://’是固定的,network1字符串要和upstream后面的字符串相等。代理转发到network1下,然后去匹配upstream,再去匹配upstream下的server。

node.js创建http服务器实现负载均衡

node http服务创建好以后,nginx 配置好以后,node作为代理服务器就可以访问node服务了。

upstream network1 {
        server 127.0.0.1:3000 weight=3;
	server 127.0.0.1:5000 weight=1;
        server 127.0.0.1:6000 weight=1;
    }

    server {
        listen       8080;
        server_name  localhost;

        location / {
            # 访问不到服务器,做详细配置。
	    #proxy_redirect off; 
            #proxy_set_header X-Real-IP $remote_addr; 
            #proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
            #proxy_set_header X-Forwarded-Proto $scheme; 
            #proxy_set_header Host $http_host; 
            #proxy_set_header X-NginX-Proxy true; 
            #proxy_set_header Connection ""; 
            #proxy_http_version 1.1; 
           proxy_pass http://network1;
        }
复制代码
const http = require('http')
const fs = require('fs')
const url = require('url')
http
    .createServer((req, res) => {
        if(req.url == '/favicon.ico'){
            res.writeHead(200);
            res.end()   
            return;
        }
        res.writeHead(200);
        fs.createReadStream(__dirname + '/index.html') #不同的页面内容查看效果
        .pipe(res);
    })
    .listen(5000)  #3000、6000。。。
------------------------------------------
<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <title>node</title>
   <link rel="stylesheet" href="">
</head>
<body>
    <div>第 1 个node服务器</div>
    <!-- <div>第 2 个node服务器</div> -->	
    <!-- <div>第 3 个node服务器</div> -->				
</body>
</html>
复制代码

nginx可以成功访问服务器,访问比大约等于权重之比。



nginx常用负载均衡策略
  • 1.轮询(默认)

每个请求轮流分配到不同的后端服务器,如果后端服务器宕机,则自动剔除。具体轮询策略为第一次访问第一个,第二次访问第二个。。。。。

upstream network1 {
        server 127.0.0.1:3000;
	    server 127.0.0.1:5000;
        server 127.0.0.1:6000;
    }
复制代码
  • 2.权重

每个请求按照一定比例分发到不同的后端服务器,用于后端服务器性能不均的情况,访问比率约等于权重之比,权重越大,被访问的几率越大。

upstream network1 {
        server 127.0.0.1:3000 weight=3;
	    server 127.0.0.1:5000 weight=1;
        server 127.0.0.1:6000 weight=1;
    }
复制代码
  • 3.ip_hash

ip_hash也叫ip绑定,每个请求按照访问ip的哈希值分配,这样每个访问客户端会固定访问一个后端服务器,可以解决会话session丢失的问题,常见账号密码登录。
哈希函数hash(“192.168.0.164”)%2 = 0 / 1,ip不变的话访问的服务器不变。

upstream network1 {
       ip_hash;
       server 127.0.0.1:3000;
       server 127.0.0.1:5000;
       server 127.0.0.1:6000;
   }
复制代码

当使用ip_hash以后,会一直访问3000端口的第一台服务器。

  • 最少连接
    web请求会被转发到连接数最少的服务器上。
 upstream network1 {
        least_conn;
        server 127.0.0.1:3000;
	    server 127.0.0.1:5000;
        server 127.0.0.1:6000;
    }
复制代码
负载均衡其他配置
upstream network1 {
        least_conn;
        server 127.0.0.1:3000;
	server 127.0.0.1:5000 backup; #备份 当所有非backup机器宕机的时候才能请求backup机器。
    }
upstream network1 {
        least_conn;
        server 127.0.0.1:3000;
	server 127.0.0.1:5000 down;#当前机器是down状态,不参与负载均衡。
    } 
复制代码

3.静态代理

把所有静态资源的访问改为访问nginx,而不是后台服务器,nginx更擅长于静态资源的处理,性能更好,效率更高。在实际应用中将静态资源html,css,js,图片交给nginx处理。
nginx实现静态代理,在nginx.conf配置文件中添加静态资源的location。
1.基于请求资源的后缀

location ~ .*\.(js|css|htm|html|gif|jpg|jpeg|png|bmp|swf|ioc|rar|zip|txt|flv|mid|doc|ppt|pdf|xls|mp3|wma)${
    &emsp;root/html; #访问静态资源的路径,静态资源部署在nginx安装目录下,跟访问html/index.html一个道理。
}
复制代码

2.基于请求资源的存放目录

location ~ .*/(js|css|img|imgags)${
    &emsp;root/opt/static
}
复制代码

linux安装目录:/user/local/nginx,在linux作为nginx部署服务器时,请求linux中存放静态资源的某个目录,如/opt/static

4.动静分离

nginx的负载均衡和静态代理结合在一起,实现动静分离,服务器专注于动态资源,nginx专注于静态资源。


5.虚拟主机

虚拟主机就是把一台物理服务器划分成多个“虚拟”的服务器,这样我们的一台物理服务器就可以当做多个服务器来使用,从而可以配置多个网站。
Nginx下,一个server标签就是一个虚拟主机,设置多个虚拟主机,配置多个server即可。

基于端口的虚拟主机

根据nginx的不同端口即可访问到基于不同端口的服务器。

 server {
        listen       8080; #9090。。。
        server_name  localhost;
        location / {
		  proxy_pass http://network1;
        }
 }
 upstream network1 {
        server 127.0.0.1:3000;
    }
 upstream network2 {
        server 127.0.0.1:5000;
    }
复制代码
基于域名的虚拟主机

基于域名的虚拟主机访问时以域名的形式访问,这就涉及到DNS域名解析的知识,我们可以在windows的hosts文件给域名直接指定端口,windows C:\Windows\System32\drivers\etc有个hosts文件,如果在这里指定了一个域名对应的ip地址,那浏览器会首先使用这个ip地址。

 server {
        listen       8080;
        server_name  www.maanshan.com
        # server_name  www.laioyang.com
        location / {
		  proxy_pass http://network1;
          #proxy_pass http://network2;
        }
 }
复制代码
upstream network1 {
        server 127.0.0.1:3000;
    }
 upstream network2 {
        server 127.0.0.1:5000;
    }
复制代码
虚拟主机实例

www.meituan.com

  • www.liaoyang.meituan.com
  • www.maanshan.meituan.com



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

By柏小白

Web网站打包成APP

appcan是国内比较老牌的平台
apicloud是新起之秀
phonegap是国外的大牌。
长期来看,phonegap是开源的,理所当然是技术最好。但是中文资料较少,国内应用的也不多。
appcan近期被apicloud蹂躏得不行不行的,基本全方位被碾压了。渐渐处于apicloud下风,后力不继。
apicloud还提供了简单的后端api,用户系统,自定义字段什么的基本不用写后端代码了。
但是最后我要劝你一句,不要用这种混合打包平台,最终都是然并卵的。君不见淘宝技术有多牛,写出来的app(html5)还是卡到死。

这里以APICLOUD为例演示:

1、首先访问http://www.apicloud.com/进行用户注册

1

2、注册成功登陆页面,点击左上角–创建应用

2

3、选择中间的–Web–输入项目名字–在网址一栏要输入在线网址(一定要是在线项目),点击创建即可3

4、直接点击云编译

4

5、填写应用名称–选择平台–类型–调试模式–全局加密–渠道打包–版本信息–点击云编译

5

6、如果点击云编译发现没有Android证书,则重新选择类型为–测试版,也可以先去申请个证书。

7、出现编译完成和二维码,就可以扫码或者下载你的个人APP了

6
————————————————
版权声明:本文为CSDN博主「小小猪~」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/zyj_15067066062/article/details/78499410

By柏小白

webstorm 怎么打断点

  1. 打开Chrome软件的右上角 Jet插件,在下拉菜单中选择选项,如下图所示。

    1
  2. 在打开的Jet选项设置窗体,设置端口(要调试程序的访问端口)后并点击Apply。如下图所示。

    2
  3. 打开WebStorm项目工程,在软件首页的右上角位置打开Edit Configurations选项,添加一个JavaScript debug调试设置。

    3
  4. 在新增的JavaScript Debug调试设置,将URL设置为调试的路径,点击Apply,完成debug设置。

    4
  5. 在Terminal运行npm run dev命令,启动vue工程并设置断点,如下图所示。

    5
  6. 启动debug,自动打开chrome,可以看到成功命中断点。

    6

    7

 

By柏小白

手把手教你WebStorm+chrome实现时时调试刷新

  1. WebStorm 安装

    WebStorm是一款收费的IDE,即使你不购买也可以免费使用30天,个人认为非常靠谱。

    进入官网,点击Download即可下载最新版本,这里默认window版本;

    安装过程没有一般默认即可,安装之后打开页面如图

    1

    2

    3

  2. WebStorm设置

    WebStorm 是通过live edit功能与浏览器实现时时刷新,这里在页面中点击Configure然后选择Settings打开WebStore的设置对话框;

    在搜索框输入live edit回车找到live edit选项,选中Auto in(ms)然后设置时间。然后勾选Restart if hotswap fails.然后点击apply应用即可

    4
  3. Chrome插件安装

    打开Chrome在地址栏右侧最后面点击三杠,选择“更多工具”->”扩展程序”;

    打开已安装的扩展在页面底部点击“获取更多扩展程序”进入Chrome网上商店,搜索JetBrains IDE Suport扩展程序。点击“添加至Chrome“按钮,安装该扩展程序到Chrome。安装完成后会在地址栏后面看到对应的图标。

    5

    6

    7

    8ad4b31c8701a18bad38c40d992f07082938fea5

     

  4. 简单示例

    软件设置完毕,扩展也安装。这时候可以尝试一把了。

    创建一个项目,文件test.html。如图所示。然后右击文件选择“Debug

    ‘test.html’”设置默认打开浏览器为Chrome。然后就可以愉快的编写代码了。

    8
    9
    10
    11
    转载:https://jingyan.baidu.com/article/454316ab68ac03f7a7c03ae3.html

 

By柏小白

Nginx:TCP / 正向 / 反向代理 / 负载均衡

写在前面的话

 

在我们日常的工作中,不可能所有的服务都是简单的 HTML 静态网页,nginx 作为轻量级的 WEB 服务器,其实我们将它用于更多的地方还是作为我们网站的入口。不管你是后端接口,还是前端页面,我们让用户的请求都到这个服务。原因大致有以下几个:

1. 集中管理更便于管理。

2. 对外服务都是需要公网 IP 的,需要带宽,如果每台机器都专门配置公网 IP 和带宽,实在是太浪费,可以看看最近我整理的几个云服务商带宽收费情况:

带宽越高,费用越高,这种高还不是成几何式增长。

3. 我们的服务一般不会是单点服务,那么前后端如果需要通信,怎么配置地址,每个都配置?会不会太麻烦了点。

4. 在我们生成服务器中,类似 redis / 数据库这类的服务器一般是不允许联网的为了安全,但是我们是不是每次都必须要登录上服务器去查数据呢?

这还是一些简单的理由,接下来我们来聊聊几种代理,顺便说说他们的应用场景,当然这种设计对于中小型公司是足够了,毕竟没去过大厂,不知道他们的具体架构和实现方式。

 

 

TCP 代理

 

在说 TCP 代理之前我们肯定还是要先了解下代理是什么东西?

代理(proxy)其实就是一个网络信息的中转站,我们使用一个图来表示:

比如这样一个场景,用户在外边,能够通过公网能够访问到云服务商集群中的一台具有公网 IP 的服务器,但是集群内部其它服务器都是不具备公网 IP 的,所以通过公网,我们无法访问到,但是有公网 IP 的服务器恰好在集群中,它的内网网卡和这些没有公网 IP 的机器是可以通信的,这意味着这台机器既可以和用户通信,又可以和后端的集群通信。那我们就得想办法,用户要访问后面的集群,让这个有公网 IP 的服务器帮忙传达一下,那么这个,当个中间人,实现用户和后端集群之间互相传话,于是这个有公网 IP 机器就成为了代理服务器。

 

那啥又是 TCP 代理?

在我们日常访问 WEB 应用,我们都是使用 http://,https://。但是有些服务不是 http 的,比如连接 MySQL 这种,这种明显不是 WEB 服务,所以我们不能像代理 WEB 服务一样代理它。而这类服务,就是 TCP 服务,我们得专门使用 TCP 代理。

我们同时举例 TCP 代理 MySQL 来具体说说如何使用配置。

在我们编译得时候加入了 –with-stream 参数,该参数是我们使用代理不可或缺的。

同样,我们在主配置文件 nginx.conf 中通过 include 来配置单独的目录,用于放置 TCP 配置的配置文件:

值得注意是,TCP 代理不是 HTTP 服务,所有我们的 include 和之前的位置不一样,我们得放在 http 的外层:

复制代码
user  root;
...
http {
    ...
}
stream {
    include tcp/*.conf;
}
复制代码

我们新建 tcp 目录:我这里为了方便使用直接 nginx 使用 root 用户

mkdir /data/services/nginx/conf/tcp

在目录下增加 MySQL 代理配置文件:mysql-proxy-demo.conf

复制代码
upstream MYSQL-PROXY-DEMO {
    hash $remote_addr consistent;
    server 192.168.10.204:3306;
}

server {
    listen  5000;
    proxy_connect_timeout   10s;
    proxy_timeout   300s;
    proxy_pass  MYSQL-PROXY-DEMO;
}
复制代码

简单说明:

1. 在 nginx 中,如果需要对后端多个机器做代理,就需要使用到 upstream,MYSQL-PROXY-DEMO 是给这个 upstream 取的名称,要求唯一。

2. hash xxx 是一种调度模式,当然这里只写了一条 server 记录,所有不存在调度到其他节点问题。

3. server xxx 是一条需要代理的记录,每一条一个 server。

4. server 段和 http WEB 服务类似,但是不需要 server_name。

5. proxy_connect_timeout 为连接超时时间,proxy_timeout 代理超时时间。

6. proxy_pass,代理中最为关键的一句,指名了我们把这个端口代理到哪个服务或者哪个 upstream。后面还会用到。

 

重载 nginx 此时我们测试数据库连接:

可以看到,我们成功的使用代理服务器的 IP + 端口通过 Navict 连接到了其它主机的 MySQL 数据库。

 

 

正向代理

 

正向代理不是我们使用的重点,因为在日常的使用中用的并不多,但是在某些特殊的场景下很有用。

比如有个局域网用户,无法访问互联网,但是局域网中另外一台机器却能够访问到互联网,所有我们可以通过那台机器作为代理去访问互联网。

正向代理的好处在于能够对需要访问的网站隐藏用户的真实信息。

 

这是系统为我提供的解决方案,但是并不是很好用,如果你想直接使用,请直接跳到后面第三方模块搭建正向代理

我们在 vhosts 目录下新建配置:forward-proxy-demo.conf

复制代码
server {
    resolver 8.8.8.8;
    access_log off;
    listen 6080;
    location / {
        proxy_pass $scheme://$http_host$request_uri;
        proxy_set_header HOST $http_host;

        # 配置缓存大小,关闭磁盘缓存读写减少I/O,以及代理连接超时时间
        proxy_buffers 256 4k;
        proxy_max_temp_file_size 0;
        proxy_connect_timeout 30;

        # 配置代理服务器 Http 状态缓存时间
        proxy_cache_valid 200 302 10m;
        proxy_cache_valid 301 1h;
        proxy_cache_valid any 1m;
        proxy_next_upstream error timeout invalid_header http_502;
    }
}
复制代码

简单说明:

红色部分为核心配置,这里我们直到了,在 nginx 中我们是可以通过 proxy_set_header 来处理请求头的。

 

我们在另外一台不能上网的机器上增加配置:

重载 nginx 后我们在不能上网的机器上执行 curl 百度:

curl -I --proxy 192.168.100.111:6080 http://www.baidu.com

结果如下:

当然我们也可以将代理配置定义成环境变量:

export http_proxy=http://192.168.100.111:6080

这样就能直接执行:

 

 

第三方模块搭建正向代理

 

当然,上面的配置都是针对 HTTP 的,对于 HTTPS 代理或者说整个正向代理,我们推荐使用第三方模块:ngx_http_proxy_connect_module

GITHUB 地址:

https://github.com/chobits/ngx_http_proxy_connect_module

将下载的 zip 包上传到服务器,重新编译 nginx,具体方法参考前面的动态添加模块:

https://www.cnblogs.com/Dy1an/p/11227796.html

1. 安装依赖:

yum install -y patch

 

2. 解压打补丁,编译:

从 GITHUB 上面,我们可以看到各个版本的 nginx 对应的补丁版本:

cd /data/packages/nginx
unzip ngx_http_proxy_connect_module-master.zip
cd nginx-1.16.0/
patch -p1 < /data/packages/nginx/ngx_http_proxy_connect_module-master/patch/proxy_connect_rewrite_101504.patch

编译不安装:

复制代码
./configure --prefix=/data/services/nginx \
--user=nginx \
--group=nginx \--with-http_stub_status_module \
--with-http_gzip_static_module \
--with-http_secure_link_module \
--with-http_flv_module \
--with-http_ssl_module \
--with-http_mp4_module \
--with-stream \
--with-http_realip_module \
--with-http_v2_module \
--with-http_sub_module \
--with-http_image_filter_module \
--with-pcre=/data/packages/nginx/pcre-8.43 \
--with-openssl=/data/packages/nginx/openssl-1.1.1c \
--with-zlib=/data/packages/nginx/zlib-1.2.11 \
--add-module=/data/packages/nginx/nginx-upload-module-master \
--add-module=/data/packages/nginx/nginx-upstream-fair-master \
--add-module=/data/packages/nginx/ngx_cache_purge-master \
--add-module=/data/packages/nginx/ngx-fancyindex-master \
--add-module=/data/packages/nginx/echo-nginx-module-master \
--add-module=/data/packages/nginx/ngx_http_proxy_connect_module-master

# 编译
make
复制代码

 

3. 备份替换旧版:

复制代码
# 备份
mv /data/services/nginx/sbin/nginx  /data/backup/nginx/nginx_$(date +%F)

# 更新
cp /data/packages/nginx/nginx-1.16.0/objs/nginx /data/services/nginx/sbin/

# 查看
/data/services/nginx/sbin/nginx -V
复制代码

如图:

 

4. 添加 nginx 正向代理配置:

复制代码
server {
    listen       6080;
    resolver 202.96.128.166;
    resolver_timeout 30s;

    # 代理配置
    proxy_connect;
    proxy_connect_allow            443 563;
    proxy_connect_connect_timeout  10s;
    proxy_connect_read_timeout     10s;
    proxy_connect_send_timeout     10s;

    location / {
        proxy_pass http://$host;
        proxy_set_header Host $host;
    }
}
复制代码

重载配置访问测试:

curl -I --proxy 192.168.100.111:6080  http://www.baidu.com
curl -I --proxy 192.168.100.111:6080  https://www.alipay.com

HTTP 访问结果:

HTTPS 访问结果:

当然,我们也可以设置环境变量:

export http_proxy=http://192.168.100.111:6080
export https_proxy=http://192.168.100.111:6080
no_proxy="localhost,127.0.0.1,localaddress,.localdomain.com"

最后,小结一下:正向代理配置虽然能够满足我们的一定需求,但是有些时候不是很稳定,包括在配置过程中,有时候并不能一次就能访问成功,需要多测试几次。

 

 

反向代理 / 负载均衡

 

反向代理一直是我们 nginx 服务配置的重中之重,我们工作的项目中大部分其实都是围绕着反向代理展开的。如果你用 nginx,你说你没有配置过静态资源 WEB 我相信,但是你没有用过反向代理,那你一定不是做运维的。

那什么是反向代理?

这需要我们和正向代理结合起来理解,我们之前正向代理的时候是我们代理别人的服务让我们能够访问到。

那么反向代理就是代理我们的服务让别人能够访问到,是不是一下子就清晰了。

我们本次测试环境用到了三台机器,一台是我们的 nginx,另外两台是安装了 tomcat 服务的服务器。我们要实现以下图示:

用户访问 nginx 的 8090 端口调度到后端的 TOMCAT 8080 上面去。

至于 TOMCAT 怎么安装部署这里就不做过多说明,这里做了个小处理,在 TOMCAT webapps 下面默认 ROOT 项目的 index.jsp 文件增加了本机 IP 用于区分:

此时我们启动两个 TOMCAT 访问测试:

节点1结果:

 

节点2结果:

 

在 nginx 的 vhosts 目录下增加如下配置:reverse-proxy-demo.conf

复制代码
upstream REVERSE-PROXY-DEMO {
    ip_hash;
    server 192.168.100.112:8080 weight=1 max_fails=3 fail_timeout=10s;
    server 192.168.100.113:8080 weight=1 max_fails=3 fail_timeout=10s;
} 

server {
    listen      8090;
    server_name localhost;
    
    location / {
        proxy_redirect off;
        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_connect_timeout 30;
        proxy_send_timeout 30;
        proxy_read_timeout 30;
        proxy_pass http://REVERSE-PROXY-DEMO;
    }
}
复制代码

如 TCP 代理一般,TCP 代理其实也是反向代理的一种,我们定义的 upstream 的名称要求唯一。

重载 nginx 访问测试:

可以看到请求被分配到了 100.113 这台机器上面去了!

 

我们之前就在使用 upstream,但是 upstream 到底是啥我们一直没说,其实 upstream 就是负载均衡。

从字面上的意思就可以理解,负载均衡就是均衡的,按照特定的调度算法,将请求调度到指定的节点(upstream server)。

upstream 配置说明:

1. nginx 负载均衡调度算法加上我们安装的 fair 模块,大致有以下 4 种:

调度算法 说明
权重轮询(默认) 按照顺序逐一分配到不同的后端。自动剔除失败的机器,使访问不受影响。
ip_hash 每个请求按照 IP 的 Hash 结果分配,使来自同一 IP 的固定访问到同一后端。能解决部分程序 session 没共享的问题
fair 更智能的算法,可以根据页面大小和加载速度进行智能负载,响应快的优先分配。
url_hash 需要按照 nginx hash 模块,按照访问的 URL 定向到某个机器上,能提升后端缓存服务器的效率。

日常用到比较多的就是前三个。

 

2. server 后面的参数:

参数 说明
weight 分配到请求权重,权重比例多高分配到请求的机会越大。
max_fails 最大的失败连接次数。
fail_timeout 等待请求的目标服务器响应的时长。
backup 当所有机器都 down 掉才会调度到这台机器。
down 手动停用某台机器。

这其实就是一些健康检查参数,但是这些参数存在不足,在实际应用中,可以结合 keepalived 来完成,后面会单独说明。

 

server 段关于反向代理的一些配置:

参数 说明
proxy_redirect 重写应答头部的报文
proxy_connect_timeout nginx 将一个请求发送至 upstream server 之前等待的最大时长
proxy_set_header 将发送至 upsream server 的报文的某首部进行重写
proxy_cookie_domain 将 upstream server 通过 Set-Cookie 首部设定的 domain 修改为指定的值,可以为字符串、正则或变量
proxy_cookie_path 将 upstream server 通过 Set-Cookie 首部设定的 path 修改为指定的值,可以为字符串、正则或变量
proxy_hide_header 设定发送给客户端的报文中需要隐藏的首部
proxy_send_timeout 发送至 upstream server 的写操作的超时时长
proxy_read_timeout 发送至 upstream server 的读操作的超时时长
proxy_pass 指定将请求代理至 upstream server 的 URL 路径

其实上面的配置我们可以简单的做个调整就能变成我们反向代理的配置模板。

By柏小白

webstorm功能、操作技巧及快捷键索引

欲先善其事,必先利其器,如题。看到网上一篇介绍webstrom的文章,觉得功能确实强大,也知道为什么阿里巴巴的前端传到github上的文件为啥都有一个 .idea 文件,(传说淘宝内部推荐写js用webstrom)

我们可以理解 IDE 就是集成了很多你想要的功能,或者你不想要的功能。换句话说就是装了很多插件的 editor ,所以到目前为止,我还觉得没必要给它装什么插件。

那么接下来开始介绍webstrom的特色功能:

WebStorm 是 JetBrains 推出的一款商业的 JavaScript 开发工具

WebStorm 是 JetBrains 推出的一款商业的 JavaScript 开发工具
  1. 任何一个编辑器都需要保存(ctrl + s),这是所有win平台上编辑类软件的特点,但是webstorm编辑文件右上角是没有那个熟悉的 * 的。
    好处:省去了ctrl + s之后,在结合Firefox的vim,基本不动鼠标就可以看到结果页面了。
    坏处:没有以前的 * 标识,万一键盘误操作也会被立即存储。
  2. 任何一个编辑器只要文件关闭了就没有历史记录了,但是webstorm有。 vcs->Local History -> Show History(快捷键:ALT+~ -〉7)
    好处:只要webstorm不关闭,你的文件随时可以返回到之前的操作(这也是为啥在 webstorm 里ctrl+y是删除一行的原因了)。
    坏处:webstorm关闭重启后这些历史记录就没有了;还有一个坏处就是由此带来的内存消耗也必然比较大。
  3. 任何一个编辑器,除了服务器svn之外,没有本地版本,但是webstorm提供一个本地文件修改历史记录(快捷键:ALT+SHIFT+c)。也可以 Ctrl + E 弹出最近打开的文件。
    好处:相当于本地svn。
    坏处:内存消耗也必然比较大。
  4. 集成了zencoding,html5,ftp,即时编辑(chrome),自动完成,基于Mozilla的JavaScript调试器,JSLint、Less支持、CoffeeScript支持、Node.JS、单元测试、集成git和svn版本控制等特性。
  5. 在编写CSS中,会智能的提示各种文件以及图片的路径,就不用再去确认这个文件是否存在了。

其他的特性就介绍了,想了解更多可以去webstrom官网继续寻找。看完了这么介绍以及那么多给力的特性,是不是有种冲动马上试一试这款传说中的前端神器啊?嗯。

首先在官方下载页下载webstrom后,点击安装,然后一直下一步,最后会出现需要注册码界面,因为webstrom是商业的IDE,而天朝的屌丝前端当然没那么钱去买那么昂贵的神器了,不用担心,我们可以用WebStorm的密钥来学习使用这款前端神器。嘿嘿~~~~

安装成功后,肯定会有些不适,就像我一样觉得这配色真的太戳了。还有一些设置也不是我也要的。那么以下我就列出我习惯的设置。

webstorm安装后的一些设置技巧:

  • 如何更改主题(字体&配色):
    File -> settings -> Editor -> colors&fonts -> scheme name.主题下载地址
  • 如何让webstorm启动的时候不打开工程文件:
    File -> Settings->General去掉Reopen last project on startup.
  • 如何完美显示中文:
    File -> Settings->Appearance中勾选Override default fonts by (not recommended),设置Name:NSimSun,Size:12
  • 如何显示行号:
    File -> Settings->Editor,”Show line numbers”打上勾,就显示行号了
  • 如何代码自动换行:
    File -> settings -> Editor “Use Soft Wraps in editor” 打上钩,代码就自动换行了
  • 如何点击光标,显示在本行末尾:
    File -> Settings->Editor “Allow placement of caret after end of line”去掉勾就行了。
  • 如何修改快键键:
    File -> Settings->Keymap,然后双击要修改快捷的功能会有提示框出来,按提示操作
  • 换成自己熟悉编辑器的快键键:
    File ->Settings->Keymap,支持像Visual Studio、Eclipse、NetBeans这样的主流IDE。
  • javascript类库提示。
    File -> settings -> Javascript -> Libraries -> 然后在列表里选择自己经常用到的javascript类库,最后Download and Install就ok了.
  • 在开发js时发现,需要ctrl + return 才能选候选项:
    File -> Setting -> Editor -> Code Completion -> Preselect the first suggestion: “Smart” 改为 “Always”
  • js提示比较迟缓
    File -> Code Completion -> Autopopup in 下 1000改为0
  • git配置:
    File -> settings -> Editor -> github,进去改github的账户,如果没有git则不需要.
  • 插件安装:
    File ->plugins,然后就选择给力的插件们再安装.(“css-X-fire”插件,用于当使用firebug修改css属性时,编辑器内的css代码也会发生变化。)
  • 以后更新

webstorm使用心得

  • 收藏夹功能:
    当工程目录很庞大时,有些子目录很经常打开,但层级又很深,这时候可以把目录添加到收藏夹里面,添加成功后,左侧有个“Favorites”菜单
  • 面包屑导航:
    除了左侧的工程页面,可以选择目录之外,在顶部菜单下有一个类似网站面包屑导航一样的目录也可以实现相同功。点击每个目录就会有下拉菜单显示其下的子目录,很实用.
  • 构造器界面:
    注释符合格式的话就会出现。如果是js文件则是js类的函数和对象;css文件的话则是这个css文件的概括;html文件的话则是节点的结构图。话说这几个就是为了方便查看代码的结构性.
  • todo界面:
    给代码加todo注释就会出现这个界面
  • 双栏代码界面:
    右击代码选项卡上的文件,然后右键 -> spilt vertically(左右两屏)或者spilt horizontally(上下两屏)
  • 本地历史功能:
    找回代码的好办法

git使用

webstorm中只集成了git的常用操作,并不能完全替代命令行工具。在界面的右下角可以查看处于哪个git分支。也可以在上面点击切换或者新建分支。

  • 查看当前代码与版本库代码的差异:
    右击代码界面任意区域,选择git -> compare with然后选择要比较的版本库。

webstorm的快捷键说明:

Editing编辑相关快捷键

  • Ctrl + Space:
    Basic code completion (the name of any class, method or variable) 基本代码完成(任何类、函数或者变量名称),改为Alt+S
  • Ctrl + Shift + Enter:
    Complete statement 补全当前语句
  • Ctrl + P:
    Parameter info (within method call arguments) 参数信息 包括方法调用参数
  • Ctrl + mouse over code
    Brief Info 简单信息
  • Ctrl + F1
    Show description of error or warning at caret 显示光标所在位置的错误信息或者警告信息
  • Alt + Insert
    Generate code…(Getters, Setters, Constructors)新建一个文件或者生成代码,…构造函数,可以创建类里面任何字段的getter与setter方法
  • Ctrl + O
    Override methods 重载方法
  • Ctrl + I
    Implement methods 实现方法
  • Ctrl + Alt + T
    Surround with…(if, else, try, catch, for, etc)用 * 来围绕选中的代码行,( * 包括 if 、 while 、 try catch 等)
  • Ctrl + /
    Comment/uncomment with line comment 行注释/取消行注释
  • Ctrl + Shift + /
    Comment/uncomment with block comment 块注释/取消块注释
  • Ctrl + W
    Select successively increasing code blocks 选择代码块,一般是增量选择
  • Ctrl + Shift + W
    Decrease current selection to previous state 上个快捷键的回退,减量选择代码
  • Alt + Q
    Context info 上下文信息
  • Alt + Enter
    Show intention actions and quick-fixes 意图行动,快速见效
  • Ctrl + Alt + L
    Reformat code 根据模板格式对代码格式化
  • Tab/ Shift + Tab
    Indent/unindent selected lines 对所选行进行缩排处理/撤销缩排处理
  • Ctrl + X or Shift + Delete
    Cut current line or selected block to clipboard 剪切当前行或所选代码块到剪切板
  • Ctrl + C or Ctrl + Insert
    Copy current line or selected block to chipboard 拷贝当前行或者所选代码块到剪切板
  • Ctrl + V or Shift + Insert
    Paste from clipboard 粘贴剪切板上的内容
  • Ctrl + Shift + V
    Paste from recent buffers 粘贴缓冲器中最新的内容
  • Ctrl + D
    Duplicate current line or selected block 复制当前行或者所选代码块
  • Ctrl + Y
    Delete line at caret 删除光标所在位置行
  • Ctrl + Shift + J
    Smart line join(HTML and JavaScript only)加入智能行 (HTML 和JavaScript)
  • Ctrl + Enter
    Smart line split(HTML and JavaScript only)分离智能行 (HTML 和JavaScript)
  • Shift + Enter
    Start new line 另起一行
  • Ctrl + Shift + U
    Toggle case for word at caret or selected block 光标所在位置大小写转换
  • Ctrl + Shift + ]/[
    Select till code block end/start 选择直到代码块结束/开始
  • Ctrl + Delete
    Delete to word end 删除文字结束
  • Ctrl + Backspace
    Delete to word start 删除文字开始
  • Ctrl + NumPad+/-
    Expand/collapse code block 扩展/缩减代码块
  • Ctrl + Shift+ NumPad+
    Expand all 扩张所有
  • Ctrl + Shift+ NumPad-
    Collapse 缩减所有
  • Ctrl + F4
    Close active editor tab 关闭活跃编辑标签

Search/replace搜索/替代相关快捷键

  • Ctrl + F
    Find 当前文件内快速查找代码
  • Ctrl + Shift + F
    Find in path 指定文件内寻找路径
  • F3
    Find next 查找下一个
  • Shift + F3
    Find previous 查找上一个
  • Ctrl + R
    Replace 当前文件内代码替代
  • Ctrl + Shift + R
    Replace in path 指定文件内代码批量替代

Usage Search搜索相关快捷键

  • Alt + F7/Ctrl + F7
    Find usages/Find usages in file 找到使用/在文件找到使用
  • Ctrl + Shift + F7
    Highlight usages in file文件中精彩使用
  • Ctrl + Alt + F7
    Show usages 显示使用

Running运行

  • Alt + Shift + F10
    Select configuration and run 选择构架,运行
  • Alt + Shift + F9
    Select configuration and debug 选择构架,修补漏洞
  • Shift + F10
    Run 运行
  • Shift + F9
    Debug 修补漏洞
  • Ctrl + Shift + F10
    Run context configuration from editor 从编辑运行内容构架
  • Ctrl + Shift + X
    Run command line 运行命令行

Debugging Debugging相关快捷键

  • F8
    Step over 不进入函数
  • F7
    Step into 单步执行
  • Shift + F7
    Smart step into 智能单步执行
  • Shift + F8
    Step out 跳出
  • Alt + F9
    Run to cursor 运行到光标处
  • Alt+ F8
    Evaluate expression 评估表达
  • F9
    Resume program 重新开始程序
  • Ctrl + F8
    Toggle breakpoint 切换断点
  • Ctrl + Shift + F8
    View breakpoints 查看断点

Navigation 定位相关快捷键

  • Ctrl + N
    Go to class跳转到指定类
  • Ctrl + Shift + N
    Go to file 通过文件名快速查找工程内的文件
  • Ctrl + Alt +Shift + N
    Go to symbol 通过一个字符查找函数位置
  • Alt + Right/ left
    Go to next/ previous editor tab 进入下一个/ 上一个编辑器选项
  • F12
    Go back to previous tool window 进入上一个工具窗口
  • Esc
    Go to editor(from tool window) 从工具窗口进入编辑器
  • Shift + Esc
    Hide active or last active window 隐藏活动窗口
  • Ctrl + Shift + F4
    Close active run/message/find/…tab 关闭活动….标签
  • Ctrl + G
    Go to line 跳转到第几行
  • Ctrl + E
    Recent files popup 弹出最近打开的文件
  • Ctrl + Alt + Left/Right
    Navigate back/forward 导航前进/后退
  • Ctrl + Shift + Backspace
    Navigate to last edit location 向最近编辑定位导航
  • Alt + F1
    Select current file or symbol in any view 查找当前选中的代码或文件在其他界面模块的位置
  • Ctrl + B or Ctrl + Click
    Go to declaration跳转到定义处
  • Ctrl + Alt + B
    Go to implementation(s) 跳转方法实现处
  • Ctrl + Shift + B
    Go to type declaration 跳转方法定义处
  • Ctrl + Shift + I
    Open quick definition lookup 打开定义快速查找
  • Ctrl + U
    Go to super-method/super-class 跳转方法/超阶级
  • Alt + Up/Down
    Go to previous/next method 在方法间快速移动定位
  • Ctrl + ]/[
    Move to code block end/start 跳转到编码块结束/开始
  • Ctrl + F12
    File structure popup 文件结构弹出
  • Ctrl + H
    Type hierarchy 类型层次
  • Ctrl + Alt + H
    Call hierarchy 调用层次结构
  • F2/ Shift + F2
    Next/previous highlighted error 跳转到后一个/前一个错误,高亮错误或警告快速定位,使用这个快捷键可以快捷在出错的语句之间进行跳转。
  • F4/Ctrl + Enter
    Edit source/ View source 编辑源代码/查看源代码
  • Alt + Home
    Show navigation bar 显示导航栏
  • F11
    Toggle bookmark 切换标记
  • Ctrl + F11
    Toggle bookmark with mnemonic 采用记忆切换标记
  • Ctrl + #[0-9]
    Go to numbered bookmark 跳转到带编号的标记
  • Shift + F11
    Show bookmark 显示标记

Refactoring 重构相关快捷键

  • F5
    Copy 拷贝
  • F6
    Move 移动
  • Alt + Delete
    Safe Delete 安全删除
  • Shift + F6
    Rename 重新命名
  • Ctrl + Alt + N
    Inline Variable 嵌入变量
  • Ctrl + Alt + M
    Extract Method( Javascript only) 提取函数
  • Ctrl + Alt + V
    Introduce Variable 引入变量
  • Ctrl + Alt + F
    Introduce Field 引入域
  • Ctrl + Alt + C
    Introduce Constant 引入常量

VCS/Local History 版本控制系统/ 本地历史相关快捷键

  • Alt + BackQuote( )
    ‘VCS’quick popup 快速弹出 VCS
  • Ctrl + K
    Commit project to VCS 提交项目至VCS
  • Ctrl + T
    Update project from VCS 从VCS 更新项目
  • Alt + Shift + C
    View recent changes 查看最新改变

General 常用的相关快捷键

  • Ctrl + Shift +A
    Find action 查找并调用编辑器的功能
  • Alt + #[0-9]
    Open corresponding tool window 快速切换打开界面模块
  • Ctrl + Alt + F11
    Toggle full screen mode 切换全屏模式
  • Ctrl + Shift + F12
    Toggle maximizing editor 切换最大化编辑器
  • Alt + Shift + F
    Add to Favorites 将当前文件添至收藏夹
  • Alt + Shift + I
    Inspect current file with current profile 使用当前属性检查当前文件
  • Ctrl + BackQuote( )
    Quick switch current scheme 快速转换现有组合
  • Ctrl + Alt + S
    Open setting dialog 打开设置对话框
  • Ctrl + Tab
    Switch between tabs and tool window 标签和工具窗的转换(与windows快捷键冲突)

我把以上快捷做成pdf了,大家可以点击WebStorm.快捷键pdf分享

文章内容转载于http://www.html5jscss.com/ide-webstrom.html

By柏小白

九种跨域方式实现原理(完整版)

前言

前后端数据交互经常会碰到请求跨域,什么是跨域,以及有哪几种跨域方式,这是本文要探讨的内容。

本文完整的源代码请猛戳github博客,纸上得来终觉浅,建议大家动手敲敲代码。

一、什么是跨域?

1.什么是同源策略及其限制内容?

同源策略是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS、CSRF等攻击。所谓同源是指”协议+域名+端口”三者相同,即便两个不同的域名指向同一个ip地址,也非同源。

url的组成

同源策略限制内容有:

  • Cookie、LocalStorage、IndexedDB 等存储性内容
  • DOM 节点
  • AJAX 请求发送后,结果被浏览器拦截了

但是有三个标签是允许跨域加载资源:

  • <img src=XXX>
  • <link href=XXX>
  • <script src=XXX>

2.常见跨域场景

当协议、子域名、主域名、端口号中任意一个不相同时,都算作不同域。不同域之间相互请求资源,就算作“跨域”。常见跨域场景如下图所示:

特别说明两点:

第一:如果是协议和端口造成的跨域问题“前台”是无能为力的。

第二:在跨域问题上,仅仅是通过“URL的首部”来识别而不会根据域名对应的IP地址是否相同来判断。“URL的首部”可以理解为“协议, 域名和端口必须匹配”

这里你或许有个疑问:请求跨域了,那么请求到底发出去没有?

跨域并不是请求发不出去,请求能发出去,服务端能收到请求并正常返回结果,只是结果被浏览器拦截了。你可能会疑问明明通过表单的方式可以发起跨域请求,为什么 Ajax 就不会?因为归根结底,跨域是为了阻止用户读取到另一个域名下的内容,Ajax 可以获取响应,浏览器认为这不安全,所以拦截了响应。但是表单并不会获取新的内容,所以可以发起跨域请求。同时也说明了跨域并不能完全阻止 CSRF,因为请求毕竟是发出去了。

二、跨域解决方案

1.jsonp

1) JSONP原理

利用 <script> 标签没有跨域限制的漏洞,网页可以得到从其他来源动态产生的 JSON 数据。JSONP请求一定需要对方的服务器做支持才可以。

2) JSONP和AJAX对比

JSONP和AJAX相同,都是客户端向服务器端发送请求,从服务器端获取数据的方式。但AJAX属于同源策略,JSONP属于非同源策略(跨域请求)

3) JSONP优缺点

JSONP优点是简单兼容性好,可用于解决主流浏览器的跨域数据访问的问题。缺点是仅支持get方法具有局限性,不安全可能会遭受XSS攻击。

4) JSONP的实现流程

  • 声明一个回调函数,其函数名(如show)当做参数值,要传递给跨域请求数据的服务器,函数形参为要获取目标数据(服务器返回的data)。
  • 创建一个<script>标签,把那个跨域的API数据接口地址,赋值给script的src,还要在这个地址中向服务器传递该函数名(可以通过问号传参:?callback=show)。
  • 服务器接收到请求后,需要进行特殊的处理:把传递进来的函数名和它需要给你的数据拼接成一个字符串,例如:传递进去的函数名是show,它准备好的数据是show('我不爱你')
  • 最后服务器把准备的数据通过HTTP协议返回给客户端,客户端再调用执行之前声明的回调函数(show),对返回的数据进行操作。

在开发中可能会遇到多个 JSONP 请求的回调函数名是相同的,这时候就需要自己封装一个 JSONP函数。

// index.html
function jsonp({ url, params, callback }) {
  return new Promise((resolve, reject) => {
    let script = document.createElement('script')
    window[callback] = function(data) {
      resolve(data)
      document.body.removeChild(script)
    }
    params = { ...params, callback } // wd=b&callback=show
    let arrs = []
    for (let key in params) {
      arrs.push(`${key}=${params[key]}`)
    }
    script.src = `${url}?${arrs.join('&')}`
    document.body.appendChild(script)
  })
}
jsonp({
  url: 'http://localhost:3000/say',
  params: { wd: 'Iloveyou' },
  callback: 'show'
}).then(data => {
  console.log(data)
})
复制代码

上面这段代码相当于向http://localhost:3000/say?wd=Iloveyou&callback=show这个地址请求数据,然后后台返回show('我不爱你'),最后会运行show()这个函数,打印出’我不爱你’

// server.js
let express = require('express')
let app = express()
app.get('/say', function(req, res) {
  let { wd, callback } = req.query
  console.log(wd) // Iloveyou
  console.log(callback) // show
  res.end(`${callback}('我不爱你')`)
})
app.listen(3000)
复制代码

5) jQuery的jsonp形式

JSONP都是GET和异步请求的,不存在其他的请求方式和同步请求,且jQuery默认就会给JSONP的请求清除缓存。

$.ajax({
url:"http://crossdomain.com/jsonServerResponse",
dataType:"jsonp",
type:"get",//可以省略
jsonpCallback:"show",//->自定义传递给服务器的函数名,而不是使用jQuery自动生成的,可省略
jsonp:"callback",//->把传递函数名的那个形参callback,可省略
success:function (data){
console.log(data);}
});
复制代码

2.cors

CORS 需要浏览器和后端同时支持。IE 8 和 9 需要通过 XDomainRequest 来实现

浏览器会自动进行 CORS 通信,实现 CORS 通信的关键是后端。只要后端实现了 CORS,就实现了跨域。

服务端设置 Access-Control-Allow-Origin 就可以开启 CORS。 该属性表示哪些域名可以访问资源,如果设置通配符则表示所有网站都可以访问资源。

虽然设置 CORS 和前端没什么关系,但是通过这种方式解决跨域问题的话,会在发送请求时出现两种情况,分别为简单请求复杂请求

1) 简单请求

只要同时满足以下两大条件,就属于简单请求

条件1:使用下列方法之一:

  • GET
  • HEAD
  • POST

条件2:Content-Type 的值仅限于下列三者之一:

  • text/plain
  • multipart/form-data
  • application/x-www-form-urlencoded

请求中的任意 XMLHttpRequestUpload 对象均没有注册任何事件监听器; XMLHttpRequestUpload 对象可以使用 XMLHttpRequest.upload 属性访问。

2) 复杂请求

不符合以上条件的请求就肯定是复杂请求了。 复杂请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为”预检”请求,该请求是 option 方法的,通过该请求来知道服务端是否允许跨域请求。

我们用PUT向后台请求时,属于复杂请求,后台需做如下配置:

// 允许哪个方法访问我
res.setHeader('Access-Control-Allow-Methods', 'PUT')
// 预检的存活时间
res.setHeader('Access-Control-Max-Age', 6)
// OPTIONS请求不做任何处理
if (req.method === 'OPTIONS') {
  res.end() 
}
// 定义后台返回的内容
app.put('/getData', function(req, res) {
  console.log(req.headers)
  res.end('我不爱你')
})
复制代码

接下来我们看下一个完整复杂请求的例子,并且介绍下CORS请求相关的字段

// index.html
let xhr = new XMLHttpRequest()
document.cookie = 'name=xiamen' // cookie不能跨域
xhr.withCredentials = true // 前端设置是否带cookie
xhr.open('PUT', 'http://localhost:4000/getData', true)
xhr.setRequestHeader('name', 'xiamen')
xhr.onreadystatechange = function() {
  if (xhr.readyState === 4) {
    if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
      console.log(xhr.response)
      //得到响应头,后台需设置Access-Control-Expose-Headers
      console.log(xhr.getResponseHeader('name'))
    }
  }
}
xhr.send()
复制代码
//server1.js
let express = require('express');
let app = express();
app.use(express.static(__dirname));
app.listen(3000);
复制代码
//server2.js
let express = require('express')
let app = express()
let whitList = ['http://localhost:3000'] //设置白名单
app.use(function(req, res, next) {
  let origin = req.headers.origin
  if (whitList.includes(origin)) {
    // 设置哪个源可以访问我
    res.setHeader('Access-Control-Allow-Origin', origin)
    // 允许携带哪个头访问我
    res.setHeader('Access-Control-Allow-Headers', 'name')
    // 允许哪个方法访问我
    res.setHeader('Access-Control-Allow-Methods', 'PUT')
    // 允许携带cookie
    res.setHeader('Access-Control-Allow-Credentials', true)
    // 预检的存活时间
    res.setHeader('Access-Control-Max-Age', 6)
    // 允许返回的头
    res.setHeader('Access-Control-Expose-Headers', 'name')
    if (req.method === 'OPTIONS') {
      res.end() // OPTIONS请求不做任何处理
    }
  }
  next()
})
app.put('/getData', function(req, res) {
  console.log(req.headers)
  res.setHeader('name', 'jw') //返回一个响应头,后台需设置
  res.end('我不爱你')
})
app.get('/getData', function(req, res) {
  console.log(req.headers)
  res.end('我不爱你')
})
app.use(express.static(__dirname))
app.listen(4000)
复制代码

上述代码由http://localhost:3000/index.htmlhttp://localhost:4000/跨域请求,正如我们上面所说的,后端是实现 CORS 通信的关键。

3.postMessage

postMessage是HTML5 XMLHttpRequest Level 2中的API,且是为数不多可以跨域操作的window属性之一,它可用于解决以下方面的问题:

  • 页面和其打开的新窗口的数据传递
  • 多窗口之间消息传递
  • 页面与嵌套的iframe消息传递
  • 上面三个场景的跨域数据传递

postMessage()方法允许来自不同源的脚本采用异步方式进行有限的通信,可以实现跨文本档、多窗口、跨域消息传递

otherWindow.postMessage(message, targetOrigin, [transfer]);

  • message: 将要发送到其他 window的数据。
  • targetOrigin:通过窗口的origin属性来指定哪些窗口能接收到消息事件,其值可以是字符串”*”(表示无限制)或者一个URI。在发送消息的时候,如果目标窗口的协议、主机地址或端口这三者的任意一项不匹配targetOrigin提供的值,那么消息就不会被发送;只有三者完全匹配,消息才会被发送。
  • transfer(可选):是一串和message 同时传递的 Transferable 对象. 这些对象的所有权将被转移给消息的接收方,而发送一方将不再保有所有权。

接下来我们看个例子: http://localhost:3000/a.html页面向http://localhost:4000/b.html传递“我爱你”,然后后者传回”我不爱你”。

// a.html
  <iframe src="http://localhost:4000/b.html" frameborder="0" id="frame" onload="load()"></iframe> //等它加载完触发一个事件
  //内嵌在http://localhost:3000/a.html
    <script>
      function load() {
        let frame = document.getElementById('frame')
        frame.contentWindow.postMessage('我爱你', 'http://localhost:4000') //发送数据
        window.onmessage = function(e) { //接受返回数据
          console.log(e.data) //我不爱你
        }
      }
    </script>
复制代码
// b.html
  window.onmessage = function(e) {
    console.log(e.data) //我爱你
    e.source.postMessage('我不爱你', e.origin)
 }
复制代码

4.websocket

Websocket是HTML5的一个持久化的协议,它实现了浏览器与服务器的全双工通信,同时也是跨域的一种解决方案。WebSocket和HTTP都是应用层协议,都基于 TCP 协议。但是 WebSocket 是一种双向通信协议,在建立连接之后,WebSocket 的 server 与 client 都能主动向对方发送或接收数据。同时,WebSocket 在建立连接时需要借助 HTTP 协议,连接建立好了之后 client 与 server 之间的双向通信就与 HTTP 无关了。

原生WebSocket API使用起来不太方便,我们使用Socket.io,它很好地封装了webSocket接口,提供了更简单、灵活的接口,也对不支持webSocket的浏览器提供了向下兼容。

我们先来看个例子:本地文件socket.html向localhost:3000发生数据和接受数据

// socket.html
<script>
    let socket = new WebSocket('ws://localhost:3000');
    socket.onopen = function () {
      socket.send('我爱你');//向服务器发送数据
    }
    socket.onmessage = function (e) {
      console.log(e.data);//接收服务器返回的数据
    }
</script>
复制代码
// server.js
let express = require('express');
let app = express();
let WebSocket = require('ws');//记得安装ws
let wss = new WebSocket.Server({port:3000});
wss.on('connection',function(ws) {
  ws.on('message', function (data) {
    console.log(data);
    ws.send('我不爱你')
  });
})
复制代码

5. Node中间件代理(两次跨域)

实现原理:同源策略是浏览器需要遵循的标准,而如果是服务器向服务器请求就无需遵循同源策略。 代理服务器,需要做以下几个步骤:

  • 接受客户端请求 。
  • 将请求 转发给服务器。
  • 拿到服务器 响应 数据。
  • 将 响应 转发给客户端。
    ” alt=”” data-src=”https://user-gold-cdn.xitu.io/2019/1/17/1685c5bed77e7788?imageView2/0/w/1280/h/960/format/webp/ignore-error/1″ data-width=”600″ data-height=”237″ />

我们先来看个例子:本地文件index.html文件,通过代理服务器http://localhost:3000向目标服务器http://localhost:4000请求数据。

// index.html(http://127.0.0.1:5500)
 <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
    <script>
      $.ajax({
        url: 'http://localhost:3000',
        type: 'post',
        data: { name: 'xiamen', password: '123456' },
        contentType: 'application/json;charset=utf-8',
        success: function(result) {
          console.log(result) // {"title":"fontend","password":"123456"}
        },
        error: function(msg) {
          console.log(msg)
        }
      })
     </script>
复制代码
// server1.js 代理服务器(http://localhost:3000)
const http = require('http')
// 第一步:接受客户端请求
const server = http.createServer((request, response) => {
  // 代理服务器,直接和浏览器直接交互,需要设置CORS 的首部字段
  response.writeHead(200, {
    'Access-Control-Allow-Origin': '*',
    'Access-Control-Allow-Methods': '*',
    'Access-Control-Allow-Headers': 'Content-Type'
  })
  // 第二步:将请求转发给服务器
  const proxyRequest = http
    .request(
      {
        host: '127.0.0.1',
        port: 4000,
        url: '/',
        method: request.method,
        headers: request.headers
      },
      serverResponse => {
        // 第三步:收到服务器的响应
        var body = ''
        serverResponse.on('data', chunk => {
          body += chunk
        })
        serverResponse.on('end', () => {
          console.log('The data is ' + body)
          // 第四步:将响应结果转发给浏览器
          response.end(body)
        })
      }
    )
    .end()
})
server.listen(3000, () => {
  console.log('The proxyServer is running at http://localhost:3000')
})
复制代码
// server2.js(http://localhost:4000)
const http = require('http')
const data = { title: 'fontend', password: '123456' }
const server = http.createServer((request, response) => {
  if (request.url === '/') {
    response.end(JSON.stringify(data))
  }
})
server.listen(4000, () => {
  console.log('The server is running at http://localhost:4000')
})
复制代码

上述代码经过两次跨域,值得注意的是浏览器向代理服务器发送请求,也遵循同源策略,最后在index.html文件打印出{"title":"fontend","password":"123456"}

6.nginx反向代理

实现原理类似于Node中间件代理,需要你搭建一个中转nginx服务器,用于转发请求。

使用nginx反向代理实现跨域,是最简单的跨域方式。只需要修改nginx的配置即可解决跨域问题,支持所有浏览器,支持session,不需要修改任何代码,并且不会影响服务器性能。

实现思路:通过nginx配置一个代理服务器(域名与domain1相同,端口不同)做跳板机,反向代理访问domain2接口,并且可以顺便修改cookie中domain信息,方便当前域cookie写入,实现跨域登录。

先下载nginx,然后将nginx目录下的nginx.conf修改如下:

// proxy服务器
server {
    listen       81;
    server_name  www.domain1.com;
    location / {
        proxy_pass   http://www.domain2.com:8080;  #反向代理
        proxy_cookie_domain www.domain2.com www.domain1.com; #修改cookie里域名
        index  index.html index.htm;

        # 当用webpack-dev-server等中间件代理接口访问nignx时,此时无浏览器参与,故没有同源限制,下面的跨域配置可不启用
        add_header Access-Control-Allow-Origin http://www.domain1.com;  #当前端只跨域不带cookie时,可为*
        add_header Access-Control-Allow-Credentials true;
    }
}
复制代码

最后通过命令行nginx -s reload启动nginx

// index.html
var xhr = new XMLHttpRequest();
// 前端开关:浏览器是否读写cookie
xhr.withCredentials = true;
// 访问nginx中的代理服务器
xhr.open('get', 'http://www.domain1.com:81/?user=admin', true);
xhr.send();
复制代码
// server.js
var http = require('http');
var server = http.createServer();
var qs = require('querystring');
server.on('request', function(req, res) {
    var params = qs.parse(req.url.substring(2));
    // 向前台写cookie
    res.writeHead(200, {
        'Set-Cookie': 'l=a123456;Path=/;Domain=www.domain2.com;HttpOnly'   // HttpOnly:脚本无法读取
    });
    res.write(JSON.stringify(params));
    res.end();
});
server.listen('8080');
console.log('Server is running at port 8080...');
复制代码

7.window.name + iframe

window.name属性的独特之处:name值在不同的页面(甚至不同域名)加载后依旧存在,并且可以支持非常长的 name 值(2MB)。

其中a.html和b.html是同域的,都是http://localhost:3000;而c.html是http://localhost:4000

 // a.html(http://localhost:3000/b.html)
  <iframe src="http://localhost:4000/c.html" frameborder="0" onload="load()" id="iframe"></iframe>
  <script>
    let first = true
    // onload事件会触发2次,第1次加载跨域页,并留存数据于window.name
    function load() {
      if(first){
      // 第1次onload(跨域页)成功后,切换到同域代理页面
        let iframe = document.getElementById('iframe');
        iframe.src = 'http://localhost:3000/b.html';
        first = false;
      }else{
      // 第2次onload(同域b.html页)成功后,读取同域window.name中数据
        console.log(iframe.contentWindow.name);
      }
    }
  </script>
复制代码

b.html为中间代理页,与a.html同域,内容为空。

 // c.html(http://localhost:4000/c.html)
  <script>
    window.name = '我不爱你'  
  </script>
复制代码

总结:通过iframe的src属性由外域转向本地域,跨域数据即由iframe的window.name从外域传递到本地域。这个就巧妙地绕过了浏览器的跨域访问限制,但同时它又是安全操作。

8.location.hash + iframe

实现原理: a.html欲与c.html跨域相互通信,通过中间页b.html来实现。 三个页面,不同域之间利用iframe的location.hash传值,相同域之间直接js访问来通信。

具体实现步骤:一开始a.html给c.html传一个hash值,然后c.html收到hash值后,再把hash值传递给b.html,最后b.html将结果放到a.html的hash值中。 同样的,a.html和b.html是同域的,都是http://localhost:3000;而c.html是http://localhost:4000

 // a.html
  <iframe src="http://localhost:4000/c.html#iloveyou"></iframe>
  <script>
    window.onhashchange = function () { //检测hash的变化
      console.log(location.hash);
    }
  </script>
复制代码
 // b.html
  <script>
    window.parent.parent.location.hash = location.hash 
    //b.html将结果放到a.html的hash值中,b.html可通过parent.parent访问a.html页面
  </script>
复制代码
 // c.html
 console.log(location.hash);
  let iframe = document.createElement('iframe');
  iframe.src = 'http://localhost:3000/b.html#idontloveyou';
  document.body.appendChild(iframe);
复制代码

9.document.domain + iframe

该方式只能用于二级域名相同的情况下,比如 a.test.comb.test.com 适用于该方式。 只需要给页面添加 document.domain ='test.com' 表示二级域名都相同就可以实现跨域。

实现原理:两个页面都通过js强制设置document.domain为基础主域,就实现了同域。

我们看个例子:页面a.zf1.cn:3000/a.html获取页面b.zf1.cn:3000/b.html中a的值

// a.html
<body>
 helloa
  <iframe src="http://b.zf1.cn:3000/b.html" frameborder="0" onload="load()" id="frame"></iframe>
  <script>
    document.domain = 'zf1.cn'
    function load() {
      console.log(frame.contentWindow.a);
    }
  </script>
</body>
复制代码
// b.html
<body>
   hellob
   <script>
     document.domain = 'zf1.cn'
     var a = 100;
   </script>
</body>
复制代码

三、总结

  • CORS支持所有类型的HTTP请求,是跨域HTTP请求的根本解决方案
  • JSONP只支持GET请求,JSONP的优势在于支持老式浏览器,以及可以向不支持CORS的网站请求数据。
  • 不管是Node中间件代理还是nginx反向代理,主要是通过同源策略对服务器不加限制。
  • 日常工作中,用得比较多的跨域方案是cors和nginx反向代理

给大家推荐一个好用的BUG监控工具Fundebug,欢迎免费试用!

作者:浪里行舟
链接:https://juejin.im/post/5c23993de51d457b8c1f4ee1
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

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搭建

已购买服务器后:
1.安装常用软件
yum install yum install lrzsz tree wget vim gcc gcc-c++ openssl-devel rpm ntpdate nc net-tools iotop cmake -y

2.关闭selinux
sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config
grep SELINUX=disabled /etc/selinux/config
setenforce 0
getenforce

3.精简开机自启动服务
chkconfig |egrep -v "ssh|crond|network|rsyslog|sysstat|iptables" |awk '{print "chkconfig" ,$1,"off"}'|bash
chkconfig --list |grep 3:on


7.0 调整字符集,支持中文显示 ###最好不用
\cp /etc/sysconfig/i18n /etc/sysconfig/i18n.bak.v1
echo 'LANG=zh_CN.UTF-8' >/etc/sysconfig/i18n
source /etc/sysconfig/i18n
echo $LANG



10.加大文件描述符

echo '* - nofile 65535' >>/etc/security/limits.conf
tail -1 /etc/security/limits.conf


11.内核优化

cat >>/etc/sysctl.conf<<EOF
net.ipv4.tcp_fin_timeout=2
net.ipv4.tcp_tw_reuse=1
net.ipv4.tcp_tw_recycle=1
net.ipv4.tcp_syncookies=1
net.ipv4.tcp_keepalive_time=600
net.ipv4.ip_local_port_range = 4000 65000
net.ipv4.tcp_max_syn_backlog= 16384
net.ipv4.tcp_max_tw_buckets=36000
net.ipv4.route.gc_timeout=100
net.ipv4.tcp_syn_retries=1
net.ipv4.tcp_synack_retries=1
net.core.somaxconn=16384
net.core.netdev_max_backlog=16384
net.ipv4.tcp_max_orphans=16384
#以下参数是对iptables防火墙的优化,防火墙不开会提示,可以忽略不理。
net.nf_conntrack_max=25000000
net.netfilter.nf_conntrack_max=25000000
net.netfilter.nf_conntrack_tcp_timeout_established=180
net.netfilter.nf_conntrack_tcp_timeout_time_wait=120
net.netfilter.nf_conntrack_tcp_timeout_close_wait=60
net.netfilter.nf_conntrack_tcp_timeout_fin_wait=120
EOF

sysctl -p


15.禁止主机被ping
echo "echo 1 >/proc/sys/net/ipv4/icmp_echo_ignore_all" >> /etc/rc.d/rc.local



一键安装部署:https://github.com/ToyoDAdoubi/doubi#ssrmush 脚本

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


客户端下载
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服务器教程

Vultr(VPS)搭建SS服务器图文指导教程 最新完整版

对于怎么利用VPS搭建SS网上有很多这方面的教程,百度搜索其实也很好用,只要善于搜索,答案其实都会有的。网上那些搭建SS的教程基本上我也看了个大概,但都不是很详细,本文将从零开始教大家VPS搭建SS,初学者们都能够成功配置SS服务器。

本文搭建SS教程共有三步,只要大家按照教程操作,都能够搭建成功。

一、购买VPS(需国外服务器)

对于国外VPS服务器的选择,目前在国内知名的国外主机商也就两家,分别是搬瓦工和Vultr,搬瓦工搭建SS教程我在前面也详细的介绍过,共有两篇文章讲解搬瓦工搭建SS教程,一篇是自动搭建SS,一篇是手动搭建SS,详情:

今天给大家带来的是利用Vultr(VPS)搭建SS教程,首先我们需要先购买VPS:

Vultr官网:点击进入

如下图,然后在下图处填写注册邮箱和密码(密码第一位要大写,必须包含字母大小写+数字,而且密码不能少于10位,然后点击 “Create Account” 创建账号

Vultr(VPS)搭建SS服务器图文指导教程 最新完整版

账号创建完成系统会发送邮件到你的注册邮箱,点击验证

Vultr(VPS)搭建SS服务器图文指导教程 最新完整版

验证完成,进行登录

Vultr(VPS)搭建SS服务器图文指导教程 最新完整版

登录后如下图

Vultr(VPS)搭建SS服务器图文指导教程 最新完整版

在上图服务器一栏选择机房、系统、配置等信息,下图这些非必选项,可以留空不选

Vultr(VPS)搭建SS服务器图文指导教程 最新完整版

选择完毕后点击右下角的“Deploy Now”

Vultr(VPS)搭建SS服务器图文指导教程 最新完整版

下面是账户充值,支持支付宝充值和微信付款,最低充值10美元

Vultr(VPS)搭建SS服务器图文指导教程 最新完整版

充值完毕,VPS基本也就购买完成,点击OS下面的图标就能看到服务器的详细配置信息了

Vultr(VPS)搭建SS服务器图文指导教程 最新完整版

下面就是VPS的机房位置、IP、用户名、root密码,这些信息我们搭建SS要用到,所以这个页面暂时不要关闭

Vultr(VPS)搭建SS服务器图文指导教程 最新完整版

二、Vultr搭建SS服务器(shadowsocks server)

本文的这一步才是最重要的一步,请大家仔细阅读。

我们先要下载一个远程连接软件:Putty

下载地址:百度网盘

下载、解压、安装,运行Putty,然后填写刚刚购买的Vultr VPS的IP地址,端口默认22,然后点击“Open”

Vultr(VPS)搭建SS服务器图文指导教程 最新完整版

下面直接选择“是”

Vultr(VPS)搭建SS服务器图文指导教程 最新完整版

在弹出的命令窗口输入用户名 root ,回车,然后输入root密码(注意:输入密码后窗口不会显示出来,但是密码是已经输入了。如果需要粘贴,Putty的快捷粘贴方式为右键单击一次

Vultr(VPS)搭建SS服务器图文指导教程 最新完整版

输入密码后回车,直到等到下面出现[root@host ~]#或者[root@vultr ~]#后,全部复制以下代码粘贴回车(Putty的快捷粘贴方式为右键单击一次

wgetno-check-certificate  https://raw.githubusercontent.com/teddysun/shadowsocks_install/master/shadowsocks.sh
Vultr(VPS)搭建SS服务器图文指导教程 最新完整版

当出现上图时,请全部复制第二条代码,粘贴回车(Putty的快捷粘贴方式为右键单击一次

chmod +x shadowsocks.sh
Vultr(VPS)搭建SS服务器图文指导教程 最新完整版

出现上图时,继续全部复制第三条代码粘贴回车(Putty的快捷粘贴方式为右键单击一次

./shadowsocks.sh 2>&1 | tee shadowsocks.log
Vultr(VPS)搭建SS服务器图文指导教程 最新完整版

出现下图后输入SS密码-确认SS密码-输入SS端口-确认SS端口

Vultr(VPS)搭建SS服务器图文指导教程 最新完整版

下面将选择SS的加密方式,选择“7”回车,或者任意键回车

Vultr(VPS)搭建SS服务器图文指导教程 最新完整版

安装SS需要时间,等待几分钟后将会出现下图

Vultr(VPS)搭建SS服务器图文指导教程 最新完整版

当出现上图信息时说明SS已经搭建成功,上图被红色涂去的是SS服务器的IP、端口、密码和加密方式。

三、各平台SS本地客户端的使用方法

1、Windows用户SS使用方法

下载Windows版本的SS客户端-shadowsocks-win:百度网盘

下载解压后,打开shadowsocks.exe文件,把上面搭建好的SS信息按照对应的地方填写进去后确定保存

Vultr(VPS)搭建SS服务器图文指导教程 最新完整版

然后单击右键-启用系统代理

Vultr(VPS)搭建SS服务器图文指导教程 最新完整版

这时打开谷歌看看,是不是已经可以访问了。

2、安卓(Android)手机用户使用方法

shadowsocks安卓(Android)版本下载地址:百度网盘

下载、安装好软件后打开APP,点击右上角+号,选择手动设置。然后填写SS信息,同电脑端一样。

Vultr(VPS)搭建SS服务器图文指导教程 最新完整版

c、iPhone苹果手机用户使用方

苹果(iPhone)用户需要在苹果商店下载相应的APP,国区苹果账号不能够下载,需要美国苹果ID才能下载,美国ID可以自己注册,也可以找万能的TB购买个临时的使用。

好了本次Vultr搭建SS教程已经结束,大家如有不明白的地方可以留言相告。

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中

 

2019-以上最新版本已经失效——以下为2019年版本

添加:路径根据自己文件目录存放

-javaagent:D:\IDE\JetbrainsCrack.jar

JetbrainsCrack.jar 下载地址:

链接:https://pan.baidu.com/s/1bqzfmXtDF4sjRVysGLuXiw
提取码:cvx6

如没有自动注入需要填写:http://jetbrains-license-server

选择 Test Connection

OK

注:爱前端 || 爱老婆

 

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

从小变大

上下跳动

顺时针转圈

逆时针转圈