小程序开发

  1. 小程序看起来和 html + CSS + javascript 但是实际上深入后就会发现他们有很多的不同,这里面的坑就比较多了,比如小程序对 wxss 对标准的 css 支持多少没有明确文档说明,有时候出了问题,需要多方面考虑,就像我刚刚遇到一个问题 (mpvue 开发小程序) :class="{action:isAce, unaction: !isAce}",在低版本测试中发现样式并没有出来,看到 dom 结构上 class=",unaction" 出现这样情况很无奈啊,但是 1.6 以上基础库就没有这问题。类似这样的坑还有好多,比如多次点击,事件跳转打开多个层
  2. 小程序中项目开发中有很多问题和难点,需要多方面的考虑,像 mpvue 中午生命周期没有触发等

vue 点击事件在UC浏览器下无效

今天早上朋友找我说遇到一个问题UC浏览器点击无效,听说折磨同事好久,我看看了,出了各种主意也没有解决,毕竟没有源代码无法根据问题判断原因所在,不过后来朋友告诉我解决了,用来一个方法 CSS3 新属性 pointer-events

一、问题

  1. 在 UC 浏览器点击事件无效(其他浏览器无问题)。
    附上朋友源码:

    <template>
            <div class="music" @click="playBtn">
                <div class="control"><-- 背景图片 --></control>
        </div>
    </template>
    <script>
        export default {
                data() {
                    return {
                        isPlay: true
                    }
                },
                methods: {
                    playBtn() {
                        if (this.isPlay) {
                            // 切换图片
                        }
                    }
                }
        }
    </script>

二、分析原因(个人理解,不喜勿喷,有错误请指出,感谢)

因为移动端部分浏览器点击图片放大,所以会在子元素默认给你绑定一个事件,就会影响你父级元素绑定的事件。
注意:子元素有背景图片或者子元素是img。
img 我添加默认事件可以理解,背景图片也影响是什么鬼,估计是检索url地址给元素绑定默认事件了。
我记得微信浏览器也可以点击放大图片,微信点击放大图片是通过微信API将图片传给微信,点击图片就可以放大了。但是 UC 这个就恶心了,你检索页面图片地址调用你自己的API,但是你绑定默认事件时别影响我正常事件啊。

三、解决方法 pointer-events

给子元素添加样式:

    .control {
        poninter-events: none;
    }

四、 pointer-events详解

简介

官方解释:

pointer-events CSS 属性指定在什么情况下 (如果有) 某个特定的图形元素可以成为鼠标事件的 target。

个人理解和使用:

pointer-event:none; 顾名思义是鼠标事件拜拜的意思,元素使用了该属性,链接啊,点击什么的都统统失效了。

pointer-events:none 的作用是让元素实体“虚化”。例如一个应用pointer-events:none的按钮元素,则我们在页面上看到的这个按钮,只是一个虚幻的影子而已,您可以理解为海市蜃楼,幽灵的躯体。当我们用手触碰它的时候可以轻易地没有任何感觉地从中穿过去。

按照公司要求,需要一个生成短信截图的程序,但是有些傻眼,是不是安排错了,作为一个有梦想前端当然不能为这点事情而难住。

程序应用自己不会写,重新学习成本太高,只能用 html 来写了。

在网上找了资料,发现 canvas  有个一 canvas.toDataURL("image/png")可以转换成 base64 编码,哈哈,这不就一半完成了!!!最大的难题已经解决。

市场上的一些js库,如:html2canvasdom-to-image,其本质也是通过toDataURL来转换成图片。

之后就是绘制 canvas 这里用到的一些简单的方法,然后用谷歌插件批量下载图片就搞定了!

1. oncontextmenu="window.event.returnValue=false" 将彻底屏蔽鼠标右键 

    < table border oncontextmenu=return(false)>< td>no< /table> 可用于 Table 

2. < body onselectstart="return false"> 取消选取、防止复制 
 
3. onpaste="return false" 不准粘贴 
 
4. oncopy="return false;" oncut="return false;" 防止复制 
 
5. < link rel="Shortcut Icon" href="favicon.ico"> IE 地址栏前换成自己的图标 
 
6. < link rel="Bookmark" href="favicon.ico"> 可以在收藏夹中显示出你的图标 
 
7. < input style="ime-mode:disabled"> 关闭输入法 
 
8. 永远都会带着框架 < script language="JavaScript">< !-- if (window == top)top.location.href = "frames.htm"; //frames.htm 为框架网页 // -->< /script> 
 
9. 防止被人 frame < SCRIPT LANGUAGE=JAVASCRIPT>< !--  if (top.location != self.location)top.location=self.location; // -->< /SCRIPT> 
 
10. 网页将不能被另存为 

<noscript>< iframe src=*.html>< /iframe></noscript>  

11.  查看网页源代码

<input type=button value=查看网页源代码 onclick="window.location='view-source:' + window.location.href">

12.删除时确认 

 <a href="javascript:if(confirm('确实要删除吗?'))location='boos.asp?&areyou=删除&page=1'">删除</a>

13. 取得控件的绝对位置  // Javascript

    function getIE(e) {
        var t = e.offsetTop; var l = e.offsetLeft; while (e = e.offsetParent) {
            t += e.offsetTop; l += e.offsetLeft;  } alert("top=" + t + "/nleft=" + l);
    } 

//VBScript < script language="VBScript">< !-- function getIE() dim t,l,a,b set a=document.all.img1 t=document.all.img1.offsetTop l=document.all.img1.offsetLeft while a.tagName< >"BODY" set a = a.offsetParent t=t+a.offsetTop l=l+a.offsetLeft wend msgbox "top="&t&chr(13)&"left="&l,64,"得到控件的位置" end function -->< /script> 
 

14. 光标是停在文本框文字的最后

    <input type=text name=text1 value=”123″ onfocus="cc()">
    <script language=”javascript”>
        function cc() {
            var e = event.srcElement;
            var r = e.createTextRange();
            r.moveStart("character", e.value.length);
            r.collapse(true);
            r.select();
        }
    </script>

15. 判断上一页的来源 

 document.referrer 

16. 最小化、最大化、关闭窗口 < object id=hh1 classid="clsid:ADB880A6-D8FF-11CF-9377-00AA003B7A11">  < param name="Command" value="Minimize">< /object> < object id=hh2 classid="clsid:ADB880A6-D8FF-11CF-9377-00AA003B7A11">  < param name="Command" value="Maximize">< /object> < OBJECT id=hh3 classid="clsid:adb880a6-d8ff-11cf-9377-00aa003b7a11"> 
< PARAM NAME="Command" VALUE="Close">< /OBJECT> < input type=button value=最小化 onclick=hh1.Click()> < input type=button value=最大化 onclick=hh2.Click()> < input type=button value=关闭 onclick=hh3.Click()> 本例适用于 IE 
 

17.屏蔽功能键 

 function look() {
      if (event.shiftKey) alert("禁止按 Shift 键!"); //可以换成 ALT CTRL 
 }
document.onkeydown = look;

 

18. 网页不会被缓存 

<META HTTP-EQUIV="pragma" CONTENT="no-cache"> <META HTTP-EQUIV="Cache-Control" CONTENT="no-cache, must-revalidate"> <META HTTP-EQUIV="expires" CONTENT="Wed, 26 Feb 1997 08:21:57 GMT"> 或者<META HTTP-EQUIV="expires" CONTENT="0"> 

19.怎样让表单没有凹凸感? 

<input type=text style="border:1 solid #000000">  
或 
<input type=text style="border-left:none; border-right:none; border-top:none; border-bottom: 1px solid #000000">< /textarea> 

 
20.< div>< span>&< layer>的区别?  < div>(division)用来定义大段的页面元素,会产生转行  < span>用来定义同一行内的元素,跟< div>的唯一区别是不产生转行  < layer>是 ns 的标记,ie 不支持,相当于< div> 
 

21.让弹出窗口总是在最上面: 

<body onblur="this.focus();"> 

22.不要滚动条?

//  让竖条没有:  
<body style="overflow:scroll;overflow-y:hidden">  </body> 
// 让横条没有: 
 <body style="overflow:scroll;overflow-x:hidden">  </body>  
// 两个都去掉?更简单了  
<body scroll="no">  </body>  

23.怎样去掉图片链接点击后,图片周围的虚线?

 <a href="#" onFocus="this.blur()"><img src="logo.jpg" border=0></a> 

24.电子邮件处理提交表单 

<form name="form1" method="post" action="mailto:****@***.com" enctype="text/plain">  
   <input type=submit> 
</form> 

 
25.在打开的子窗口刷新父窗口的代码里如何写? window.opener.location.reload()  
 
26.如何设定打开页面的大小 < body onload="top.resizeTo(300,200);"> 打开页面的位置< body onload="top.moveBy(300,200);"> 
 
27.在页面中如何加入不是满铺的背景图片,拉动页面时背景图不动  < STYLE>  body  {background-image:url(logo.gif); background-repeat:no-repeat;  background-position:center;background-attachment: fixed}  < /STYLE>  
 
28. 检查一段字符串是否全由数字组成 < script language="Javascript">< !-- function checkNum(str){return str.match(//D/)==null} alert(checkNum("1232142141")) alert(checkNum("123214214a1")) // -->< /script> 
 
29. 获得一个窗口的大小 document.body.clientWidth; document.body.clientHeight 
 
30. 怎么判断是否是字符 if (/[^/x00-/xff]/g.test(s)) alert("含有汉字"); else alert("全是字符"); 
 
31.TEXTAREA 自适应文字行数的多少 < textarea rows=1 name=s1 cols=27 onpropertychange="this.style.posHeight=this.scrollHeight"> < /textarea> 
 
32. 日期减去天数等于第二个日期 
< script language=Javascript> function cc(dd,dadd) { //可以加上错误处理 var a = new Date(dd) a = a.valueOf() a = a - dadd * 24 * 60 * 60 * 1000 a = new Date(a) alert(a.getFullYear() + "年" + (a.getMonth() + 1) + "月" + a.getDate() + "日") } cc("12/23/2002",2) < /script> 
 
33. 选择了哪一个 Radio < HTML>< script language="vbscript"> function checkme() for each ob in radio1 if ob.checked then window.alert ob.value next end function < /script>< BODY> < INPUT name="radio1" type="radio" value="style" checked>Style < INPUT name="radio1" type="radio" value="barcode">Barcode < INPUT type="button" value="check" onclick="checkme()"> < /BODY>< /HTML> 
 
34.脚本永不出错 < SCRIPT LANGUAGE="JavaScript">  < !-- Hide  function killErrors() {  return true;  }  window.onerror = killErrors;  // -->  < /SCRIPT> 
 
35.ENTER 键可以让光标移到下一个输入框 <input onkeydown="if(event.keyCode==13)event.keyCode=9"> 
 
36. 检测某个网站的链接速度: 把如下代码加入< body>区域中: < script language=Javascript> tim=1 setInterval("tim++",100) 
b=1 var autourl=new Array() autourl[1]="www.njcatv.net" autourl[2]="javacool.3322.net" autourl[3]="www.sina.com.cn" autourl[4]="www.nuaa.edu.cn" autourl[5]="www.cctv.com" function butt(){ document.write("< form name=autof>") for(var i=1;i< autourl.length;i++) document.write("< input type=text name=txt"+i+" size=10 value=测试中……> =》< input type=text  name=url"+i+" size=40> =》< input type=button value=GO  
onclick=window.open(this.form.url"+i+".value)> ") document.write("< input type=submit value=刷新>< /form>") } butt() function auto(url){ document.forms[0]["url"+b].value=url if(tim>200) {document.forms[0]["txt"+b].value="链接超时"} else {document.forms[0]["txt"+b].value="时间"+tim/10+"秒"} b++ } function run(){for(var i=1;i< autourl.length;i++)document.write("< img src=http://"+autourl+"/"+Math.random()+"  
 
width=1 height=1  
 
onerror=auto("http://"+autourl+"")>")} run()< /script> 
 
37. 各种样式的光标 auto :标准光标 default :标准箭头 hand :手形光标 wait :等待光标 text :I 形光标 vertical-text :水平 I 形光标 no-drop :不可拖动光标 not-allowed :无效光标 
help :?帮助光标 all-scroll :三角方向标 move :移动标 crosshair :十字标 e-resize n-resize nw-resize w-resize s-resize se-resize sw-resize 
 
38.页面进入和退出的特效 进入页面< meta http-equiv="Page-Enter" content="revealTrans(duration=x, transition=y)"> 推出页面< meta http-equiv="Page-Exit" content="revealTrans(duration=x, transition=y)">   这个是页面被载入和调出时的一些特效。duration 表示特效的持续时间,以秒为单位。 transition 表示使用哪种特效,取值为 
 
1-23:   0 矩形缩小    1 矩形扩大    2 圆形缩小   3 圆形扩大    4 下到上刷新    5 上到下刷新   6 左到右刷新    7 右到左刷新    8 竖百叶窗   9 横百叶窗    10 错位横百叶窗    11 错位竖百叶窗   12 点扩散    13 左右到中间刷新    14 中间到左右刷新   15 中间到上下   16 上下到中间    17 右下到左上   18 右上到左下    19 左上到右下    20 左下到右上   21 横条    22 竖条    23 以上22 种随机选择一种 
 
39.在规定时间内跳转 < META http-equiv=V="REFRESH" content="5;URL=http://www.51js.com">  
 
40.网页是否被检索 < meta name="ROBOTS" content="属性值">   其中属性值有以下一些:   属性值为"all": 文件将被检索,且页上链接可被查询;   属性值为"none": 文件不被检索,而且不查询页上的链接;   属性值为"index": 文件将被检索;   属性值为"follow": 查询页上的链接;   属性值为"noindex": 文件不检索,但可被查询链接;   属性值为"nofollow": 文件不被检索,但可查询页上的链接。 
 
41.回车 用客户端脚本在页面添加document的onkeydown事件,让页面在接受到回车事件后,进行Tab 键的功能,即只要把 event 的 keyCode 由 13 变为 9 Javascript 代码如下: 
 
<script language="javascript" for="document" event="onkeydown"> <!--   if(event.keyCode==13)      event.keyCode=9; --> </script> 这样的处理方式,可以实现焦点往下移动,但对于按钮也起同样的作用,一般的客户在输入完 资料以后,跳到按钮后,最好能直接按"回车"进行数据的提交.因此,对上面的方法要进行一下 修改,应该对于"提交"按钮不进行焦点转移.而直接激活提交. 因此我对上面的代码进行了一个修改,即判断事件的"源",是否为提交按钮,代码如下: <script language="javascript" for="document" event="onkeydown"> <!--   if(event.keyCode==13 && event.srcElement.type!='button' && event.srcElement.type!='submit' && event.srcElement.type!='reset' && event.srcElement.type!='textarea' && event.srcElement.type!='')      event.keyCode=9; --> </script> 判断是否为 button, 是因为在 HTML 上会有 type="button" 判断是否为 submit,是因为 HTML 上会有 type="submit" 判断是否为reset,是因为 HTML 上的"重置"应该要被执行 判断是否为空,是因为对于 HTML 上的"<a>链接"也应该被执行,这种情况发生的情况不多,可 以使用"tabindex=-1"的方式来取消链接获得焦点. 

在 css 样式上 -webkit-box-orient:vertical;  加上注释, 

如下:

/* autoprefixer: off */
 -webkit-box-orient: vertical; 
 /* autoprefixer: on */

打包时必须使用这种方法打包,否则打包后  -webkit-box-orient: vertical 便会消失

网上解决方案是这样的,但是我在我的项目中发现不起作用,

解决方案

optimize-css-assets-webpack-plugin这个插件的问题
注释掉webpack.prod.conf.js中下面的代码

new OptimizeCSSPlugin({
  cssProcessorOptions: config.build.productionSourceMap
    ? { safe: true, map: { inline: false } }
    : { safe: true }
}),

最近学习了 angular 表单。

1. 表单绑定数据,目前有两种方法:

    1. [(ngModel)]="name";  // 双向绑定属性值

    2. formControlNam="name";  // 按名称FormControl将现有FormGroup的a 同步到表单控件元素。

例如:

import {Component} from '@angular/core';
import {FormControl, FormGroup, Validators} from '@angular/forms';
 
@Component({
  selector: 'example-app',
  template: `
    <form [formGroup]="form" (ngSubmit)="onSubmit()"> <!-- 这里必须写 [formGroup]="form" 绑定下方 new FormGroup()  -->
      <div *ngIf="first.invalid"> Name is too short. </div>
 
      <input formControlName="first" placeholder="First name"> <!-- formControlName 绑定的是下方 new FormGroup() 中 first -->
      <input formControlName="last" placeholder="Last name">
 
      <button type="submit">Submit</button>
   </form>
   <button (click)="setValue()">Set preset value</button>
  `,
})
export class SimpleFormGroup {
  form = new FormGroup({
    first: new FormControl('Nancy', Validators.minLength(2)),  last: new FormControl('Drew'), // 'Nancy' 是 值, validators.minLength(2) 是angular默认表单验证,也可以自定义验证
  });
 
  get first(): any { return this.form.get('first'); } // 必须写 这个方法,之后才可以获取到表单的值
 
  onSubmit(): void {
    console.log(this.form.value);  // {first: 'Nancy', last: 'Drew'} // 获取 值
  }
 
  setValue() { this.form.setValue({first: 'Carson', last: 'Drew'}); } // 改变 first 与 last 表单的值
}

app.module.ts 引入必须 

import { FormsModule, ReactiveFormsModule } from "@angular/forms";

否者 不可以用 formControlName

注:formControlName 与 ngModel 使用

在Angular v6中不支持将ngModel输入属性和ngModelChange事件与反应式表单指令一起使用,并且将在Angular v7中删除。

现已弃用:

content_copy<form [formGroup]="form"> <input formControlName="first" [(ngModel)]="value"> </form> <!-- 不要一起用了 -->
content_copythis.value = 'some value';

由于一些原因,这已被弃用。首先,开发人员发现这种模式令人困惑。看起来似乎ngModel正在使用实际的指令,但实际上它是ngModel在反应式表单指令上命名的输入/输出属性,它简单地近似(某些)其行为。具体来说,它允许获取/设置值和拦截值事件。然而,ngModel其他一些功能 - 比如延迟更新ngModelOptions或导出指令 - 根本不起作用,这可以理解地引起一些混乱。

此外,这种模式混合了模板驱动和反应形式策略,我们通常不建议这样做,因为它没有利用这两种策略的全部好处。在模板中设置值违反了反应形式背后的模板无关原则,而在类中添加FormControlFormGroup层则消除了在模板中定义表单的便利性。

类型

var a = 1; 隐式; var a:number = 1; 显示声明

var arr = []

类型:

基本类型:

联合类型:----- 选择

函数签名:

success:(a, b)=>void;

复合类型(Object Type):

var a:{x:xx, y:xx};

number, string, boolean, null, undefined, enum, any;

函数类型:

  1. 参数

    • 函数签名
  2. 返回值

function show(a:number, b:number)


外部变量

declare var $;


接口-interface

  • 和 java 不同
  • 接口:约定、限制;

真面向对象

class 写法, extend, 多继承

访问修饰符:

  1. public 共有 任何人可以访问
  2. private 私有 只有类内部可以访问
  3. protected 受保护-友元 只有子类可以访问

泛型-- 别跟 “any” 搞混了 泛-- 宽泛

class Calc<T> {
    a:T;
    b:T;
    show (c  :T) {
        alert(a + b + c)
    }
} var obj = new Calc<number>();

obj.a = 12;
obj.b = 'abc'; // 报错 }

Array --- 泛型

interface Array<T> { 

    reverse() : T[]; 

    sort(compare?: a(a:T, b:T) =>number):T[];

    ...

}

// 泛型:类型当参数传入

数组完成写法:var arr:Array<number> = new Array<number>();

layout 响应式布局工具

  • Breakpoints 屏幕尺寸
  • BreakpointObserver 观察器
  • MediaMatcher 媒体查询匹配

import { Component, OnInit } from "@angular/core";
import {
  BreakpointObserver,
  BreakpointState,
  MediaMatcher,
  Breakpoints
} from "@angular/cdk/layout";
import { Observable } from "rxjs/Observable";
@Component({
  selector: "layout",
  templateUrl: "./layout.component.html",
  styleUrls: ["./layout.component.scss"]
})
export class LayoutComponent implements OnInit {
  isHandset: Observable<BreakpointState>;
  constructor(public breakpointObserver: BreakpointObserver, public media: MediaMatcher) {}

  ngOnInit() {
    // 手持设备
    let Handset = Breakpoints.Handset;
    // 手持landscape屏
    let HandsetLandscape = Breakpoints.HandsetLandscape;
    //手持portrait屏
    let HandsetPortrait = Breakpoints.HandsetPortrait;
    // 多媒体
    let Medium = Breakpoints.Medium;
    // 平板电脑
    let Tablet = Breakpoints.Tablet;
    // 平板电脑 Landscape
    let TabletLandscape = Breakpoints.TabletLandscape;
    // 平板电脑 Portrait
    let TabletPortrait = Breakpoints.TabletPortrait;
    // web
    let Web = Breakpoints.Web;
    // web landscape
    let WebLandscape = Breakpoints.WebLandscape;
    // web portrait
    let WebPortrait = Breakpoints.WebPortrait;
    // 大屏幕
    let Large = Breakpoints.Large;
    // 更大屏幕
    let XLarge = Breakpoints.XLarge;
    // 更小屏幕
    let XSmall = Breakpoints.XSmall;
    // 小屏幕
    let Small = Breakpoints.Small;

    // 是否满足多个条件
    this.breakpointObserver
      .observe([
        Handset,
        HandsetLandscape,
        Handset,
        Medium,
        Tablet,
        TabletLandscape,
        TabletPortrait,
        Web,
        WebLandscape,
        WebPortrait,
        Large,
        XLarge,
        Small,
        XSmall
      ])
      .subscribe(res => {
        console.log(res);
      });
      this.breakpointObserver
      .observe(Breakpoints.Handset)
        .subscribe((state: BreakpointState) => {
        if (state.matches) {
          console.log('手机设备尺寸内');
        } else {
          console.log('非手机设备尺寸内');
        }
      });

  }
}

今天看到 一个 PHP 疯狂的吐槽,JavaScript 面试人员 JS 写的不如 PHP 连 AMD 与 CMD 都不会,我心里默默的想了一下,自己脑海里只是有个浅薄的概念,吓的我赶紧查查资料。

参考资料

     AMD 规范

     CMD 规范

    SeaJS 与 RequestJS 差异可以参考 https://github.com/seajs/seajs/issues/277

AMD 是 RequireJS 在推广过程中对模块定义的规范化产出。
CMD 是 SeaJS 在推广过程中对模块定义的规范化产出。
类似的还有 CommonJS Modules/2.0 规范,是 BravoJS 在推广过程中对模块定义的规范化产出。

这些规范的目的都是为了 JavaScript 的模块化开发,特别是在浏览器端的。
目前这些规范的实现都能达成浏览器端模块化开发的目的

区别:

1. 对于依赖的模块,AMD 是提前执行,CMD 是延迟执行。不过 RequireJS 从 2.0 开始,也改成可以延迟执行(根据写法不同,处理方式不同)。CMD 推崇 as lazy as possible.

2. CMD 推崇依赖就近,AMD 推崇依赖前置。看代码:

// CMD
define(function(require, exports, module) {
var a = require('./a')
a.doSomething()
// 此处略去 100 行
var b = require('./b') // 依赖可以就近书写
b.doSomething()
// ... 
})

// AMD 默认推荐的是
define(['./a', './b'], function(a, b) { // 依赖必须一开始就写好
a.doSomething()
// 此处略去 100 行
b.doSomething()
...
})

虽然 AMD 也支持 CMD 的写法,同时还支持将 require 作为依赖项传递,但 RequireJS 的作者默认是最喜欢上面的写法,也是官方文档里默认的模块定义写法。

3. AMD 的 API 默认是一个当多个用,CMD 的 API 严格区分,推崇职责单一。比如 AMD 里,require 分全局 require 和局部 require,都叫 require。CMD 里,没有全局 require,而是根据模块系统的完备性,提供 seajs.use 来实现模块系统的加载启动。CMD 里,每个 API 都简单纯粹

微信网页样式经常跑偏一大部分是网页字体问题
;(function () {  
 if (typeof WeixinJSBridge == "object" && typeof WeixinJSBridge.invoke == "function") {
  handleFontSize(); 
 } else { 
 if (document.addEventListener) { 
 document.addEventListener("WeixinJSBridgeReady", handleFontSize, false); 
 } else if (document.attachEvent) {  
document.attachEvent("WeixinJSBridgeReady", handleFontSize); 
 document.attachEvent("onWeixinJSBridgeReady", handleFontSize);  
}  }   function handleFontSize() { 
 // 设置网页字体为默认大小 
 WeixinJSBridge.invoke('setFontSizeCallback', {'fontSize': 0}); 
 // 重写设置网页字体大小的事件  
WeixinJSBridge.on('menu:setfont', function () {  WeixinJSBridge.invoke('setFontSizeCallback', {'fontSize': 0});  });  }
 })()

在Web开发的时候经常会遇到浏览器不响应事件进入假死状态,甚至弹出“脚本运行时间过长“的提示框,如果出现这种情况说明你的脚本已经失控了,必须进行优化。
浏览器内核是多线程的,它们在内核控制下相互配合以保持同步,一个浏览器至少实现三个常驻线程, GUI 渲染线程, 浏览器事件触发线程。

  1. JavaScript 引擎是基于事件驱动的单线程执行的, JS 线程一直等待着任务队列中任务的到来然后加以处理, 浏览器无论再什么时候都只是一个 JS 线程在运行 JS 程序。
  2. GUI 渲染线程负责渲染浏览器界面,当界面需要重绘(Repaint)或由于某种操作引发回流(reflow)时,该线程就会执行。但需要注意 GUI渲染线程与JS引擎是互斥的,当JS引擎执行时GUI线程会被挂起,GUI更新会被保存在一个队列中等到JS引擎空闲时立即被执行.
  3. 事件触发线程,当一个事件被触发时该线程会把事件添加到待处理队列的队尾,等待JS引擎的处理。这些事件可来自JavaScript引擎当前执行的代码块如setTimeOut、也可来自浏览器内核的其他线程如鼠标点击、AJAX异步请求等,但由于JS的单线程关系所有这些事件都得排队等待JS引擎处理。

    了解了浏览器的内核处理方式就不难理解浏览器为什么会进入假死状态了,当一段JS脚本长时间占用着处理机就会挂起浏览器的GUI更新,而后面的事件响应也被排在队列中得不到处理,从而造成了浏览器被锁定进入假死状态。另外JS脚本中进行了DOM操作,一旦JS调用结束就会马上进行一次GUI渲染,然后才开始执行下一个任务,所以JS中大量的DOM操作也会导致事件响应缓慢甚至真正卡死浏览器,如在IE6下一次插入大量的HTML。而如果真的弹出了“脚本运行时间过长“的提示框则说明你的JS脚本肯定有死循环或者进行过深的递归操作了。

       Nicholas C. Zakas认为不论什么脚本,在任何时间、任何浏览器上执行都不应该超过100毫秒,否则一定要将脚本分解成若干更小的代码段。那么我们该如何来做呢: 

        第一步,优化你的循环,循环体中包含太多的操作和循环的次数过多都会导致循环执行时间过长,并直接导致锁死浏览器。如果循环之后没有其他操作,每次循环只处理一个数值,而且不依赖于上一次循环的结果则可以对循环进行拆解,看下面的chunk的函数:

function chunk (array, process, context) { 
    setTimeout(function() {
         var item = array.shift()
         process.call(context, item) 
        if(array.length > 0) {
             setTimeout(arguments.callee, 100) 
        }
     }, 100) 
}

        chunk() 函数的用途就是将一个数组分成小块处理,它接受三个参数:要处理的数组,处理函数以及可选的上下文环境。每次函数都会将数组中第一个对象取出交给 process 函数处理,如果数组中还有对象没有被处理则启动下一个 timer,直到数组处理完。这样可保证脚本不会长时间占用处理机,使浏览器出一个高响应的流畅状态。

        借助JS强大的闭包机制任何循环都是可拆分的,下面的版本增加了 callback 机制,使可再循环处理完毕之后进行其他的操作。

function chunk ( array,  process,  cbfun ) { 
      var i  = 0, len = array.length  // 这里是要注意在执行过程中数组最好是不变的
      setTimeout(function () {  // 循环体要做的操作 
      process(array[i], i++)
         if( i < len ) { 
            setTimeout(farguments.callee, 100)
         }else { 
        cbfun()     // 循环结束之后要做的操作
         }
     }, 100} 
} 

    第二步, 优化你的函数,如果函数体内有太多不相干但又要在一起执行的操作则可以进行拆分,考虑下面的函数:

function dosomething () { 
    dosomething1() 
    dosomething2()
 }

    第三步,优化递归操作,函数递归虽然简单直接但是过深的递归操作不但影响性能而且稍不注意就会导致浏览器弹出脚本失控对话框,必须小心处理。

    看以下斐波那契数列的递归算法:

 function fibonacci (n) {
    return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2)
}

   fibonacci(40) 这条语句将重复调用自身331160280次,在浏览器中执行必然导致脚本失控,而采用下面的算法则只需要调用40次

fibonacci = function (n) {
    var memo = {0 : 0, 1 : 0}                            // 计算结果缓存
        var shell = function (n) {
            if ( typeof result != 'number' )         //  如果只没有被计算则进行计算
                memo[n] = shell (n - 1) + shell(n - 2) 
                return memo[n]
        }
    return shell(n)
}

这项技术被称为memoization,他的原理很简单就是同样的结果你没必要计算两次。另一种消除递归的办法就是利用迭代,递归和迭代经常会被作为互相弥补的方法。

第四步,减少DOM操作,DOM操作的代价是相当昂贵的,大多数DOM操作都会触发浏览器的回流(reflow)操作。例如添加删除节点,修改元素样式,获取需要经过计算的元素样式等。我们要做的就是尽量少的触发回流操作。

 

el.style.width = '300px' el.style.height = '300px'
el.style.backgroundColor = 'red'

上面的操作会触发浏览器的三次回流操作,再看下面的方式:

el.className = 'newStyle'

通过设置改元素的className一次设置多个样式属性,将样式写再CSS文件中,只触发一次回流,达到了同样是效果而且效率更高。因为浏览器最擅长的就是根据class设置样式。

还有很多可以减少DOM操作的方法,在此就不多说了,但是一个基本的原则就是让浏览器去做它自己擅长的事情,例如通过class来改变元素的属性。


weex 是阿里开发的一款 将 JavaScript 集成与 android 的一块框架(初步个人认为),但是里面的坑却又很多,官网第一板块开发环境搭建就有一个坑(报错 index 文件找不到,之后发现 "

weex-vue-render" 这个包的问题,将 weex-vue-render 包的版本改成 "^0.10.4",否则跑不通);
   我们用的是 集成到 android 开发项目里, android 集成也有一个坑就是 weex 版本的问题,低版本不支持 vue 语法注意,因为根据 官方文档生成项目是 src 文件下面 .vue 结尾的文件,可以新建 .we 文件写 weex 语法,【不支持】 ,
这里有几个坑就是 插件包,如何集成到 android 项目下 使用 weex-toolkit 工具可以生成的 js 文件 放到 android 项目下得 main 文件下就OK了!

一个很 Low 的程序员自述,因为机缘巧合的我无意间,接触到了计算机,这里我要感谢我的哥哥,也是我的启蒙老师。

首先作为一个程序员,要学会去总结,已经很长时间没有去停下来思考了,感觉有很多不足,到现在我还不了解 JavaScript 的底层原理,所以我还没有入门,在这里我希望可以记录下来工作与学习中的点点滴滴。