iOS下webview中JS调用原生OC

因项目需要,需要在页面中传递值给ios客户端。经过联调最后使用 JavaScriptCore 这种方法完成。

过程中开始使用 WebViewJavascriptBridge 这种方法,最后出现os只能调用本地的页面时才生效,在群友推荐下,改用JavaScriptCore这种方法。经过各种调试才算调通。

JavaScriptCore是webkit的一个重要组成部分,主要是对JS进行解析和提供执行环境。iOS7后苹果在iPhone平台推出,极大的方便了我们对js的操作。我们可以脱离webview直接运行我们的js,推荐使用

先定义通讯类js方法,等加载好后。再进行业务js的执行。
定义:

function testResponse(obj){
    native.testResponse(obj);
}

调用:

    // 调用oc方法传递信息
    testResponse(iosSdkAuthResult);

参考文章:
iOS下JS与原生OC互相调用(总结)
JavaScriptCore 使用

gulp-rev-append 小记

使用gulp-rev-append给页面的引用添加版本号,清除页面引用缓存。简单配置如下:

var gulp = require('gulp');
var rev = require('gulp-rev-append');

gulp.task('rev', function() {
 gulp.src('./index.html')
 .pipe(rev())
 .pipe(gulp.dest('./dest'));
});

针对相对路径使用,对于简单的页面来说没问题,但使用后端模板文件后路径变化时就不太适用了。

这是也只用使用 gulp-rev-collector 了,复杂度提高了。

常用es6特性学习

ES6给我们提供了许多的新语法和代码特性来提高javascript的体验。

定义函数

我们先来看一个基本的新特性,在javascript中,定义函数需要关键字function,但是在es6中,还有更先进的写法,我们来看:

es6写法:

var human = {
    breathe(name) {   //不需要function也能定义breathe函数。
        console.log(name + ' is breathing...');
    }
};
human.breathe('jarson');   //输出 ‘jarson is breathing...’

转成以前的js代码:

var human = {
    breathe: function(name) {
        console.log(name + 'is breathing...');
    }
};
human.breathe('jarson');

创建类

我们知道,javascript不像java是面向对象编程的语言,而只可以说是基于对象编程的语言。所以在js中,我们通常都是用function和prototype来模拟类这个概念。

但是现在有了es6,我们可以像java那样‘明目张胆’的创建一个类了:

class Human {
    // 构造方法,实例化的时候将会被调用,如果不指定,那么会有一个不带参数的默认构造函数。
    constructor(name) {
    	this.name = name;
    }
    // 是原型对象上的属性
    breathe() {
        console.log(this.name + " is breathing");
    }
}
var man = new Human("jarson");
man.breathe();    // jarson is breathing

man.hasOwnProperty("name"); // true
man.__proto__.hasOwnProperty('breathe'); // true

hasOwnProperty() 方法用来判断某个对象是否含有指定的自身属性。和 in 运算符不同,该方法会忽略掉那些从原型链上继承到的属性。
__proto__属性的值就是它的原型。

上面代码转为js格式:

function Human(name) {
    this.name = name;
    this.breathe = function() {
        console.log(this.name + ' is breathing');
    }
}
var man = new Human('jarson');
man.breathe();    //jarson is breathing

所以我们看到,我们可以像java那样语义化的去创建一个类。另外,js中的继承父类,需要用prototype来实现。那么在es6中,又有什么新的方法来实现类的继承呢?

继续看:

假如我们要创建一个Man类继承上面的Human类,es6代码:

class Man extends Human {
    constructor(name, sex) {
        // 子类必须要在constructor中指定 super 方法,否则在新建实例的时候会报错
        // 如果没有置顶consructor,默认带 super 方法的constructor将会被添加
        super(name); // 即调用父类的构造函数
        this.sex = sex;
    }
    info(){
        console.log(this.name + ' is ' + this.sex);
    }
}
var xx = new Man('jarson', 'boy');
xx.breathe();   // jarson is breathing
xx.info();   // jarson is boy

console.log(xx instanceof Human); // true
console.log(xx instanceof Man); // true

代码很简单,不作赘述,可以使用文章里提到的在线工具去试试效果就能明白了。需要注意的是: super() 是父类的构造函数。

instanceof 运算符用来测试一个对象在其原型链中是否存在一个构造函数的 prototype 属性。

let与const

在我看来,在es6新特性中,在定义变量的时候统统使用 let 来代替 var 就好了, const 则很直观,用来定义常量,即无法被更改值的变量。

for (let i=0;i<2;i++) {
    console.log(i);  //输出: 0,1
}

箭头函数

ES6中新增的箭头操作符 => 简化了函数的书写。操作符左边为输入的参数,而右边则是进行的操作以及返回的值,这样的写法可以为我们减少大量的代码,看下面的实例:

let arr = [6, 8, 10, 20, 15, 9];
arr.forEach((item, i) => console.log(item, i));
let newArr = arr.filter((item) => (item<10));
console.log(newArr); //[6, 8, 9];

上面的 (item, i) 就是参数,后面的 console.log(item, i) 就是回到函数要执行的操作逻辑。

上面代码转为js格式:

var arr = [6, 8, 10, 20, 15, 9];
arr.forEach(function(item, i) {
	return console.log(item, i);
});
var newArr = arr.filter(function(item) {
    return (item < 10);
});
console.log(newArr);

字符串模版

ES6中允许使用反引号 ` 来创建字符串,此种方法创建的字符串里面可以包含由美元符号加花括号包裹的变量${vraible}。看一下实例就会明白了:

//产生一个随机数
let num = Math.random();
//将这个数字输出到console
console.log(`your num is ${num}`);

 

摘录自:
http://www.open-open.com/lib/view/open1462951574598.html
https://segmentfault.com/a/1190000002904199

在JavaScript中创建命名空间的几种写法(转)

在JavaScript中全局变量经常会引起命名冲突,甚至有时侯重写变量也不是按照你想像中的顺序来的,可以看看下面的例子:
var sayHello = function() {
  return 'Hello var';
};

function sayHello(name) {
  return 'Hello function';
};

sayHello();
最终的输出为
> "Hello var"

为什么会这样,根据 StackOverFlow 的解释,实际上JavaScript的是按如下顺序解析的。

function sayHello(name) {
  return 'Hello function';
};

var sayHello = function() {
  return 'Hello var';
};

sayHello();
不带var的function声明被提前解析了,因此现代的JS写法建议你始终使用前置var声明所有变量;
避免全局变量名冲突的最好办法还是创建命名空间,下面是在JS中合建命名空间的几种常用方法。
通过函数(function)创建
这是一种比较常见的写法,通过声明一个function实现,函数里设置初始变量,公共方法写入prototype,如:
var NameSpace = window.NameSpace || {};
/*
Function
*/
NameSpace.Hello = function() {
  this.name = 'world';
};
NameSpace.Hello.prototype.sayHello = function(_name) {
  return 'Hello ' + (_name || this.name);
};
var hello = new NameSpace.Hello();
hello.sayHello();
这种写法比较冗长,不利于压缩代码(jQuery使用fn代替prototype),而且调用前需要先实例化(new)。使用Object写成JSON形式可以写得紧凑些:
通过JSON对象创建Object
/*
Object
*/
var NameSpace = window.NameSpace || {};
NameSpace.Hello = {
    name: 'world'
  , sayHello: function(_name) {
    return 'Hello ' + (_name || this.name);
  }
};
调用
NameSpace.Hello.sayHello('JS');
> Hello JS;
这种写法比较紧凑,缺点是所有变量都必须声明为公有(public)的,导致所有对这些变量的引用都需要加this指示作用域,写法也略有冗余。

通过闭包(Closure)和Object实现

在闭包中声明好所有变量和方法,并通过一个JSON Object返回公有接口:
var NameSpace = window.NameSpace || {};
NameSpace.Hello = (function() {
  //待返回的公有对象
  var self = {};
  //私有变量或方法
  var name = 'world';
  //公有方法或变量
  self.sayHello = function(_name) {
    return 'Hello ' + (_name || name);
  };
  //返回的公有对象
  return self;
}());
Object和闭包的改进型写法
上个例子在内部对公有方法的调用也需要添加self,如:self.sayHello(); 这里可以最后再返回所有公有接口(方法/变量)的JSON对象。
var NameSpace = window.NameSpace || {};
NameSpace.Hello = (function() {
  var name = 'world';
  var sayHello = function(_name) {
    return 'Hello ' + (_name || name);
  };
  return {
    sayHello: sayHello
  };
}());
Function的简洁写法
这是一种比较简洁的实现,结构紧凑,通过function实例,且调用时无需实例化(new),方案来自stackoverflow
var NameSpace = window.NameSpace || {};
NameSpace.Hello = new function() {
  var self = this;
  var name = 'world';
  self.sayHello = function(_name) {
    return 'Hello ' + (_name || name);
  };
};

调用

NameSpace.Hello.sayHello();
我喜欢的写法
var yourNamespace = {

    foo: function() {
    },

    bar: function() {
    }
};

...

yourNamespace.foo();

转自:http://ourjs.com/detail/538d8d024929582e6200000c

webpack基本配置

var webpack = require('webpack')
module.exports = {
    entry: {
        index: './src/app.js'
    },
    output: {
        path: './dist/',
        filename: '[name].js',
        publicPath: '/dist'
    },
    scripts: {
      "build": "webpack",
      "dev": "webpack-dev-server --devtool eval --progress --colors --content-base build"
    },
    module: {
        loaders: [{
            test: /\.js$/,
            exclude: /node_modules/,
            loader: 'babel',
            query: {
                presets: ['es2015', 'stage-0', 'react']
            }
        }]
    }
}

dev里各属性值的意思是:

  1. webpack-dev-server: 在 localhost:8080 建立一个 Web 服务器
  2. --devtool eval:为你的代码创建源地址。当有任何报错的时候可以让你更加精确地定位到文件和行号
  3. --progress: 显示合并代码进度
  4. --colors: 在命令行中显示颜色
  5. --content-base build:指向设置的输出目录

注:
publicPath: ‘/dist’
// webpack-dev-server 启动目录是 `/`, `/dist` 目录是打包的目标目录相对于启动目录的路径

webpack-dev-server 还提供了自动刷新功能,有两种模式。

Iframe 模式

修改访问的路径: http://localhost:8080/index.html -> http://localhost:8080/webpack-dev-server/index.html 。这个时候每次修改代码,打包完成过后都会自动刷新页面。

不需要额外配置,只用修改路径
应用被嵌入了一个 iframe 内部,页面顶部可以展示打包进度信息
因为 iframe 的关系,如果应用有多个页面,无法看到当前应用的 url 信息

inline 模式

启动 webpack-dev-server 的时候添加 –inline 参数

需要添加 –inline 配置参数
没有顶部信息提示条,提示信息在控制台中展现

参考:
React+Webpack快速上手指南
精益react-webpack

querySelector和querySelectorAll的功能及区别

HTML5向Web API新引入了document.querySelector以及document.querySelectorAll两个方法用来更方便地从DOM选取元素,功能类似于jQuery的选择器。这使得在编写原生JavaScript代码时方便了许多。

用法:

两个方法使用差不多的语法,都是接收一个字符串参数,这个参数需要是合法的CSS选择语法。

element = document.querySelector('selectors');
elementList = document.querySelectorAll('selectors');

其中参数selectors 可以包含多个CSS选择器,用逗号隔开。

element = document.querySelector('selector1,selector2,...');
elementList = document.querySelectorAll('selector1,selector2,...');

使用这两个方法无法查找带伪类状态的元素,比如querySelector(‘:hover’)不会得到预期结果。

querySelector

该方法返回满足条件的单个元素。按照深度优先和先序遍历的原则使用参数提供的CSS选择器在DOM进行查找,返回第一个满足条件的元素。

querySelectorAll

该方法返回所有满足条件的元素,结果是个nodeList集合。查找规则与前面所述一样。

摘自:http://www.cnblogs.com/Wayou/p/html5_web_api_queryselector.html#undefined

获取触摸事件坐标

	function findCoordinates(e) {
		// 如果需要用 pageX/Y 代替 clinetX/Y
		var x,y;
		if(e.changedTouches){
			x = e.changedTouches[0].clientX;
			y = e.changedTouches[0].clientY;
		}else{
			x = e.clientX;
			y = e.clientY;
		}
		console.log(e);
		$('#test').text("x:"+x+",y:"+y);
		return [x,y];
	}
    
    var el = document.getElementsByClassName('content')[0];
    console.log(el);

    el.addEventListener('touchstart', findCoordinates, false);

触摸事件对象有事件类型、时间目标对象、可以阻止默认行为。

其中 touchList 数组包含了每个触摸点的信息。
changedTouches 数组中第一个对象就是导致事件触发的那个触摸点对象。

clientX/Y 和 pageX/Y 的区别是,前者相对于视觉视口的左上角,后者相对于布局视口的左上角。

注:
关于视口的介绍

Swiper 循环切换回调实例

Swiper 是一款优秀的滑动插件,支持手机端和pc端。现为3.x版本,2.x版本兼容ie8浏览器。
插件原版地址:
http://idangero.us/swiper/
中文版地址为:
http://www.swiper.com.cn/

实例地址:
15-infinite-loop-2

核心代码:

    var swiper = new Swiper('.swiper-container', {
        pagination: '.swiper-pagination',
        slidesPerView: 1,
        paginationClickable: true,
        spaceBetween: 30,
        loop: true,
        onSlideChangeEnd: function(swiper){
          console.log(swiper.activeIndex) //每次切换时,提示现在是第几个slide
          changeBg((swiper.activeIndex) % 5);
        }
    });

    // 回调切换背景
    function changeBg(index){
        $('#main').removeClass().addClass(function(){
            switch (index) {
                case 0:
                    return 'bg-5';
                    break;
                case 6:
                    return 'bg-1';
                    break;
                default:
                    return 'bg-'+index;
                    break
            }
        });
    }

loop模式:
会在wrapper前后生成若干个slides让slides看起来是衔接的,用于无限循环切换。
loop模式下会在slides前后复制若干个slide,,前后复制的个数不会大于原总个数。
默认为0,前后各复制1个。

例:
0,1,2 --> 2,0,1,2,0
实例中index为0和6时,做相应处理。

注:
activeIndex
返回当前活动块的索引。loop模式下注意该值会被加上复制的slide数。

paginationClickable
此参数设置为true时,点击分页器的指示点分页器会控制Swiper切换。

autoplayDisableOnInteraction
用户操作swiper之后,是否禁止autoplay。默认为true:停止。
如果设置为false,用户操作swiper之后自动切换不会停止,每次都会重新启动autoplay。
操作包括触碰,拖动,点击pagination等。

scrollIntoView的用法

scrollIntoView
作用(功能),将一个对象显示在当前window窗口的可视范围之内。
这个是W3C定义的DOM方法,各浏览器均支持,包括:IE5.5+、FF2.0+….

可以到PPK的博客中查看更详细的介绍:http://www.quirksmode.org/dom/w3c_cssom.html

可以点击链接查看Demo:http://www.quirksmode.org/dom/tests/scrollintoview.html

不过上面并未介绍它的参数,具体参数说明可以看这里:

http://msdn.microsoft.com/en-us/library/ms536730(VS.85).aspx

语法:

object.scrollIntoView( [bAlignToTop])

参数:

bAlignToTop 布尔型:true/false,默认参数不传则为true

它们分别代表不同的含义。

true:如果滚动条足够长,则将对象的顶端与当前窗口的顶部对齐

false:对象的底端与当前窗口的顶端对齐

参考:http://www.cnblogs.com/meteoric_cry/archive/2011/10/01/2197172.html

说说focus /focusin /focusout /blur 事件

事件触发时间:

focus:当focusable元素获得焦点时,不支持冒泡;
focusin:和focus一样,只是此事件支持冒泡;
blur:当focusable元素失去焦点时,不支持冒泡;
focusout:和blur一样,只是此事件支持冒泡;

以前一直以为所有事件都是支持冒泡的,都是可以cancel的,查阅了[MDN上相关资料](https://developer.mozilla.org/en-US/docs/Web/Events)后,才发现有些事件支持冒泡,有些事件并不支持冒泡;有些事件有默认行为(这类事件可以cancel),有些事件压根儿就没有默认行为(这类事件就不能 cancel )。

从 MDN 上可以清楚的看到 focus和blur这2种事件不支持冒泡,支持冒泡的事件是focusin和focusout。

事件触发顺序:

对于同时支持这4个事件的浏览器,事件执行顺序为focusin > focus > focusout > blur

转自:
https://segmentfault.com/a/1190000003942014