Code Monkey home page Code Monkey logo

wumi_blog's Introduction

Hi there I’m kaiyou 👋

😐 a silent observer & front-end developer

Teck Stack

HTML5 CSS3 JavaScript Vue.js Sass

Webpack ESlint Git VS Code

GitHub Stats

5Mi's GitHub stats

wumi_blog's People

Contributors

5mi avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

wumi_blog's Issues

process.cwd() ,__filename,__dirname,module.filenameNODE_ENV

app.js

 1 //执行 node E:\node_study\file_path_study\app.js
 2 
 3 console.log('*** app start ***');
 4 
 5 console.log('***      module.filename = ' + module.filename + ' ***');
 6 console.log('***           __filename = ' + __filename + ' ***');
 7 console.log('***            __dirname = ' + __dirname + ' ***');
 8 console.log('***        process.cwd() = ' + process.cwd() + ' ***');
 9 console.log('*** require.main.filename= ' + require.main.filename + ' ***');
10 
11 console.log('*** app end ***');
12 
13 console.log('');
14 
15 require('./lib/test');

test.js

1 console.log('*** app start ***');
2 
3 console.log('***      module.filename = ' + module.filename + ' ***');
4 console.log('***           __filename = ' + __filename + ' ***');
5 console.log('***            __dirname = ' + __dirname + ' ***');
6 console.log('***        process.cwd() = ' + process.cwd() + ' ***');
7 console.log('*** require.main.filename= ' + require.main.filename + ' ***');
8 
9 console.log('*** app end ***');

node__filename

结论

  • module.filename:开发期间,该行代码所在的文件。
  • __filename:始终等于 module.filename。
  • __dirname:开发期间,该行代码所在的目录。
  • process.cwd():运行node的工作目录,可以使用 cd /d 修改工作目录。
  • require.main.filename:用node命令启动的module的filename, 如 node xxx,这里的filename就是这个xxx。
    require()方法的坐标路径是:module.filename;fs.readFile()的坐标路径是:process.cwd()。

vue select

  • vue select

    <template id="vueselect">
          <div>
              <select @change="handleChange" v-model="selected">
                  <!--活用  selected  disabled 属性-->
                  <option value="">choose</option>
                  <option v-for="item in items" v-text="item.name" :value="item.name"></option>
              </select>
              <div>{{selected}}</div>
              <button @click="handleClick">click</button>
          </div>
      </template>
    
      //js中
      Vue.component("vueselect",{
              template:'#vueselect',
              data(){
                  return {
                      //双向绑定 option value是什么 select v-model的值就(选中的)是什么,反之亦然
                      selected:"aaa",
                      items:[
                      {name:'aaa',val:1},
                      {name:'bbb',val:2},
                      {name:'ccc',val:3},
                      {name:'ddd',val:4},
                      {name:'eee',val:5}
                  ]
                  }
              },
              methods:{
                  handleChange(e){
                      console.log("change")
                  },
                  // 通过v-model改变选中不会触发select onchange方法
                  handleClick(e){
                      //selected的值为空则选中option中value为空的项,在这里是choose那一项,selected的值在所有option的value中都不存在,则不显示选中内容
                      this.selected="",
                      this.items = [
                      {name:'123',val:1},
                      {name:'321',val:2},
                      {name:'231',val:3},
                      {name:'213',val:4},
                      {name:'132',val:5}
                  ]
                  }
              }
          });
  • select标签中v-model双向绑定option中的value,展示选中的option,改变v-model的值展示的option也会改变,option中都不存在该值时,页面不展示

  • 通过改变select的v-model,不会触发select的onchange方法

js splice方法split方法,slice方法 img没有src属性时就没有那个默认的图片图标(图挂了的那个)

js splice

splice() 方法向/从数组中添加/删除项目,然后返回被删除的项目。

语法:arrayObject.splice(index,howmany,item1,.....,itemX)

参数 描述
index 必需。整数,规定添加/删除项目的位置,使用负数可从数组结尾处规定位置。
howmany 必需。要删除的项目数量。如果设置为 0,则不会删除项目。
item1, ..., itemX 可选。向数组添加的新项目。

返回值

类型 描述
Array 包含被删除项目的新数组,如果有的话。

注意:该方法会改变原始数组。

如果从 arrayObject 中删除了元素,则返回的是含有被删除的元素的数组。

  //subAddresses变为 addressList从index位置删掉的项组成的数组(这里就删了一个,所以subAddresses为只有一项的数组)  
  //addressList被修改了
  let subAddresses=addressList.splice(index,1);

Examples

var myFish = ['angel', 'clown', 'mandarin', 'surgeon'];

// removes 0 elements from index 2, and inserts 'drum'
var removed = myFish.splice(2, 0, 'drum');
// myFish is ['angel', 'clown', 'drum', 'mandarin', 'surgeon']
// removed is [], no elements removed

// myFish is ['angel', 'clown', 'drum', 'mandarin', 'surgeon'] 
// removes 1 element from index 3
removed = myFish.splice(3, 1);
// myFish is ['angel', 'clown', 'drum', 'surgeon']
// removed is ['mandarin']

// myFish is ['angel', 'clown', 'drum', 'surgeon'] 
// removes 1 element from index 2, and inserts 'trumpet'
removed = myFish.splice(2, 1, 'trumpet');
// myFish is ['angel', 'clown', 'trumpet', 'surgeon']
// removed is ['drum']

// myFish is ['angel', 'clown', 'trumpet', 'surgeon'] 
// removes 2 elements from index 0, and inserts 'parrot', 'anemone' and 'blue'
removed = myFish.splice(0, 2, 'parrot', 'anemone', 'blue');
// myFish is ['parrot', 'anemone', 'blue', 'trumpet', 'surgeon']
// removed is ['angel', 'clown']

// myFish is ['parrot', 'anemone', 'blue', 'trumpet', 'surgeon'] 
// removes 2 elements from index 2
removed = myFish.splice(myFish.length -3, 2);
// myFish is ['parrot', 'anemone', 'surgeon']
// removed is ['blue', 'trumpet']

js split方法

split() 方法用于把一个字符串分割成字符串数组。
stringObject.split(separator,howmany)

参数 描述
separator 必需。字符串或正则表达式,从该参数指定的地方分割 stringObject。
howmany 可选。该参数可指定返回的数组的最大长度。如果设置了该参数,返回的子串不会多于这个参数指定的数组。如果没有设置该参数,整个字符串都会被分割,不考虑它的长度。

注意:如果把空字符串 ("") 用作 separator,那么 stringObject 中的每个字符之间都会被分割。""与" "是不同的

注释:String.split() 执行的操作与 Array.join 执行的操作是相反的。


此外

  • img没有src属性时就没有那个默认的图片图标(图挂了的那个) a标签没有href时(没有默认链接的样式)

  • => 箭头函数没有自己的this

    在写Promise的.then()回调时 总想着let that = this;一下,好把this转存一下方便使用,其实then(function(resp){})换成then((resp)=>{})这种箭头函数就不需要使用that了 可以直接使用this(吐槽一下webstorm,js也设置成了es6了不知为何有时候写箭头函数就会报错...)

注释判断浏览器为IE

注释判断浏览器为IE

来自

<!--[if !IE]><!--> 除IE外都可识别 <!--<![endif]-->
<!--[if IE]> 所有的IE可识别 <![endif]-->
<!--[if IE 6]> 仅IE6可识别 <![endif]-->
<!--[if lt IE 6]> IE6以及IE6以下版本可识别 <![endif]-->
<!--[if gte IE 6]> IE6以及IE6以上版本可识别 <![endif]-->
<!--[if IE 7]> 仅IE7可识别 <![endif]-->
<!--[if lt IE 7]> IE7以及IE7以下版本可识别 <![endif]-->
<!--[if gte IE 7]> IE7以及IE7以上版本可识别 <![endif]-->
<!--[if IE 8]> 仅IE8可识别 <![endif]-->
<!--[if IE 9]> 仅IE9可识别 <![endif]-->

注释判断浏览器

<!--[if lt IE 9]>
加载CSS1
<!--[else]>
加载CSS2
<![endif]-->

这样有效是有效,但是用HTML VALIDATOR里,报错,因为这个不符合XHTML 1.1的规范,
如果把ELSE语句去掉,则正确.

加载CSS2
<!--[if lt IE 9]>
加载CSS1(可以把要重写的写在这里).
<![endif]-->

NODE_ENV

通过NODE_ENV可以来设置环境变量(默认值为development)。 一般我们通过检查这个值来分别对开发环境和生产环境下做不同的处理。可以在命令行中通过下面的方式设置这个值:

    linux & mac: export NODE_ENV=production
    windows:set NODE_ENV=production

比方说如果代码中要对生产环境下做一些处理,可以这样写:

if (process.env.NODE_ENV === 'production') {
 // just for production code
}

(以前看到的某个答案)

vue filterBy 切换展示

  • vue filterBy

返回过滤后的数组。第一个参数可以是字符串或函数。

如果第一个参数是字符串,则在每个数组元素中搜索它:

<div v-for="item in items | filterBy 'hello'">

在上例中,只显示包含字符串 "hello" 的元素。

如果 item 是一个对象,过滤器将递归地在它所有属性中搜索。为了缩小搜索范围,可以指定一个搜索字段:

<div v-for="user in users | filterBy 'Jack' in 'name'">

在上例中,过滤器只在用户对象的 name 属性中搜索 "Jack"。为了更好的性能,最好始终限制搜索范围。

  • vue v-for

    v-for中用$index可传入索引,此外
    你可以为索引指定一个别名(如果 v-for 用于一个对象,则可以为对象的键指定一个别名):

<div v-for="(index, item) in items">
  {{ index }} {{ item.message }}
</div>
  • 切换展示 (展示一个其他关闭)

    1.可定义一个属性为 nowitem(或actitem表示当前展示的那个) 为-1 (index id不能为-1)

    2.在模板中 设置 v-show="nowitem == id" 此处可以id index 等等

    3.切换方法中传入id 调用

    //打开当前id
    if(!this.nowitem == id){
      this.nowitem = id
    }
    //否则关闭当前id
    else{
      this.nowitem = -1
    }
    
    //整合一下此切换方法大概像这样
    toggle(index){
          this.nowItem = this.nowItem == index ? -1 : index;
      }
    

    4.如果切换展示为每一项都可以独立展开收齐 那么每项应该都有一个表示是否展开的属性 如可定义show:false,那么切换时则传入每一项自己的show属性即可

阿里rap接口管理 了解下

项目里使用了这个接口管理插件,有利于前后端分离,在我们自己尝试写接口管理平台,使用mock数据接口服务器时,大厂们已经将这种方式实践完善了,网易好像内部就使用了这种方式,接口平台好像还没开源出来,这次也是经前辈介绍,使用了这个rap.后台接口怎么管理维护平台我就不了解了,简单说下前端插件的使用.
rap
登录平台页面选择团队后点击项目右上的这个图标就会生成有插件地址的script标签.
在紧接jq之后引入生成的插件地址,在发送请求时,大概之后插件就会拦截到你的请求,然后返回给你平台上的mock数据.注意的是插件地址后可追加mode参数<script type="text/javascript" src="http://{{domainName}}/rap.plugin.js?projectId={{projectId}}&mode={{mode}}"></script>

mode不同值的具体含义如下:
0 - 不拦截
1 - 拦截全部
2 - 黑名单中的项不拦截
3 - 仅拦截白名单中的项

默认是3推荐设置为2;再贴一份打印mock数据的模板页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Document</title>
    <script src="http://cdn.bootcss.com/jquery/2.2.1/jquery.min.js"></script>
    <--!引入插件-->
    <script src='http://rap.qdum.com/rap.plugin.js?projectId=7&mode=2'></script>
    <script type="text/javascript">

        $(document).ready(function(){
            RAP.setBlackList([
                //设置黑名单
                // "/api/v1.0/account/login"
            ]);
            //RAP.setMode(1);
            $.ajax({

                url:"/product/getProduct",
                type:'get',
                cache:false,
                //dataType:'jsonp',
                success:function(data){
                    console.log(data)
                },
                error:function(){
                    console.log(data.message);
                }
            });

        });
    </script>   
</head> 
    <body>
        fdsfds
    </body>
</html>

用户手册

杂七杂八

ATOM 试用

在看完那个狂拽酷炫的插件activate-power-mode之后心中久久不能平复,回到家就立刻下了atom来尝试一下,听说atom大有赶超sublime的势头,就是稍微略慢性能上稍欠缺一些,占内存大,打开st内存占用250m左右,而atom打开后内存占用380m左右,但开启速度还可以没有传闻中的那么慢,而且这款ide好像完全是用node通过html+js+css打造的webapp,cmd+option+i都能打开自身的chrome开发者模式,真是太神奇了,他的主题也很多很漂亮而且都能用less之类自己修改,快捷键和st也很相似,是一个和st看起来像但本质完全不同的一个编辑器。

出了核心拓展和activate-power-mode和汉化包以外我又装了几个安装包,退程序内存占用已达1G。

安装包大多都是照着我st上packagelist上安过的在atom上安装类似的,emmet什么的,出了额外装的minimap在滚屏时小卡以外,整体来说体验还是不错的,给我的感觉就是内存占用有点儿高,听说打开大体积文件可能使程序崩溃,我倒没太尝试,毕竟还是更习惯st,但如果等将来atom更稳定性能更好的话感觉或许比sublime用起来还要更酷~还能和本家github无缝链接(打开atom一只没使用内存占用一直是380名左右),可以算是st的一个强力的竞争对手,弄不好是宿敌的存在,真么一想感觉时间过的真快,st好像也不在年轻了呢

entries() for...in for...of

//解构赋值   数组arr.entries()转化后返回每项为键值对的数组
for(let [index,charge] of this.charges.entries()){
    //chargesType数组中是否含有 partType 没有就添加
    if(this.chargesType.indexOf(charge.partType) == -1){
        this.chargesType.push(charge.partType);
    }
}

The entries() method returns a new Array Iterator object that contains the key/value pairs for each index in the array.

数组entries()转化后返回一个Array Iterator对象,是一个每项为原素组键值对的数组 [index,value]

var arr = ['a', 'b', 'c'];
var eArr = arr.entries();

console.log(eArr.next().value); // [0, 'a']
console.log(eArr.next().value); // [1, 'b']
console.log(eArr.next().value); // [2, 'c']

Same as above, using a for…of loop:

var arr = ['a', 'b', 'c'];
var eArr = arr.entries();

for (let e of eArr) {
  console.log(e);
}

JavaScript原有的for...in循环,只能获得对象的键名,不能直接获取键值。ES6提供for...of循环,允许遍历获得键值。

var arr = ['a', 'b', 'c', 'd'];

for (let a in arr) {
  console.log(a); // 0 1 2 3
}

for (let a of arr) {
  console.log(a); // a b c d
}

上面代码表明,for...in循环读取键名,for...of循环读取键值。如果要通过for...of循环,获取数组的索引,可以借助数组实例的entries方法和keys方法,参见《数组的扩展》章节。

for...of循环调用遍历器接口,数组的遍历器接口只返回具有数字索引的属性。这一点跟for...in循环也不一样。

let arr = [3, 5, 7];
arr.foo = 'hello';

for (let i in arr) {
  console.log(i); // "0", "1", "2", "foo"
}

for (let i of arr) {
  console.log(i); //  "3", "5", "7"
}

上面代码中,for...of循环不会返回数组arr的foo属性。

vue prop验证

vue Prop验证

组件可以为 props 指定验证要求。当组件给其他人使用时这很有用,因为这些验证要求构成了组件的 API,确保其他人正确地使用组件。此时 props 的值是一个对象,包含验证要求:

Vue.component('example', {
  props: {
    // 基础类型检测 (`null` 意思是任何类型都可以)
    propA: Number,
    // 多种类型 (1.0.21+)
    propM: [String, Number],
    // 必需且是字符串
    propB: {
      type: String,
      required: true
    },
    // 数字,有默认值
    propC: {
      type: Number,
      default: 100
    },
    // 对象/数组的默认值应当由一个函数返回
    propD: {
      type: Object,
      default: function () {
        return { msg: 'hello' }
      }
    },
    // 指定这个 prop 为双向绑定
    // 如果绑定类型不对将抛出一条警告
    propE: {
      twoWay: true
    },
    // 自定义验证函数
    propF: {
      validator: function (value) {
        return value > 10
      }
    },
    // 转换函数(1.0.12 新增)
    // 在设置值之前转换值
    propG: {
      coerce: function (val) {
        return val + '' // 将值转换为字符串
      }
    },
    propH: {
      coerce: function (val) {
        return JSON.parse(val) // 将 JSON 字符串转换为对象
      }
    }
  }
})

type可以是下面原生构造器:

  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array

type 也可以是一个自定义构造器,使用 instanceof 检测。

注意:当 prop 验证失败了,Vue 将拒绝在子组件上设置此值,如果使用的是开发版本会抛出一条警告。

项目中有用到:

export default{
        props:{
            title: {
                type: String,
                required: true
            },
            hasbackbtn:{
                //验证类型是布尔值
                type: Boolean,
                //默认值为true 即子组件标签上可以不设定此prop(这里是hasbackbtn) 默认为true
                default: true
            }
        },
        ...
{{extend ('./base.xtpl')}}

{{#block ('body')}}

<div id="emc-app">
    <header-bar :hasbackbtn="false" title={{title}}></header-bar>
    {{{block ('content')}}}
</div>

{{/block}}

这里注意 由于是布尔值 所以需要使用v-bind:hasbackbtn="false"否者会将此false视为字符串,导致prop验证不通过当 prop 验证失败了,Vue 将拒绝在子组件上设置此值,并且控制台将抛出一条报错警告

fis3 使用记录

又重新尝试用fis3 之前弄明白没明白的地方都忘了这次好好记录下,希望能坚持住= =!

开启同名依赖

fis.match('/widget/**', {
    release: '${project.static}/$&',
    //开启同名依赖后 会自动依赖同名文件,即使没显式声明依赖   postpackager-loader 依然会自动在页面通过script 或link 加载依赖的资源
    useSameNameRequire: true
});

isMod: true标记文件为组件化文件。被标记成组件化的文件会入map.json表。并且会对js文件进行组件化包装。

isMod: true声明为模块,设置

fis.hook('commonjs', { baseUrl: '.', extList: ['.js', '.es'] });
插件hook-commonjs会自动添加define包裹 所以即使因为同名依赖packager-loader通过script标签引入配置了isMod:true的js文件也应该 require()一下,有modjs 才能在浏览器环境中运行define中具体的源码

模块导出

module.exports =exports. //export function someFunction(){} export const

fis3-postpackager-loader相关

给 loader 插件配置 allInOne 属性,即可对散列的引用链接进行合并,而不需要进行配置 packTo 指定合并包名 即packTo的文件不会进行 allInOne打包

注意data-loader属性 <!--ignore--><!--RESOURCEMAP_PLACEHOLDER--> 注释块 异步请求会需要生成的resourcemap
注意 构建出的script标签顺序

启用 allinone 打包,把队列中,挨一起的资源合并。如果是内联内容,直接合并即可,如果是外链文件,则合并文件内容,生成新内容。

packager-loader相关更多参见

css实现一段不够一行时居中显示,多于一行时两端对齐

可以让p text-align:justify;display:inline-block;给p加一个外层的框div,这个外层的框text-align:center;
这样p随着文字的宽度变化,并且p在div中居中,当p宽度不够一行的时候就看起来是居中的

from

此外 css 伪元素 :first-line属性

:first-line 选择器用于选取指定选择器的首行。
以下属性可与 :first-line 使用:
字体属性
颜色属性
背景属性
word-spacing
letter-spacing
text-decoration
vertical-align
text-transform
line-height
clear

参考

判断非空 Date , dom是否含有某属性 , ~~运算 , 使用一元加(+)模拟Number()函数

  • 判断非空
/*判断非空*/
export function isEmpty(val) {
    if (val == null)
        return true;
    if (val == undefined || val == 'undefined')
        return true;
    if (val == "")
        return true;
    if (val.length == 0)
        return true;
    // !    \s 匹配空白   *零个或若干
    return !/[^(^\s*)|(\s*$)]/.test(val);
}
  • Date
    //今天
let date = new Date();
//月份0-11 需加1
let [yy,mm,dd] = [date.getFullYear(), date.getMonth() + 1, date.getDate()];
  • 是否含有某属性
//是否含有属性
    function hasAttr(dom, attr) {
        let str = dom.getAttribute(attr);
        return typeof str != "undefined" && str != "false" && str !== null;
    }

Style相关

字体使用相关

  • @font-face

    首先语法规则为

@font-face {
      font-family: <YourWebFontName>;
      src: <source> [<format>][,<source> [<format>]]*;
      [font-weight: <weight>];
      [font-style: <style>];
    }

详情参考这里

里面提到的fontsquirrel这个工具还是挺好用的将ttf格式转化成其他web字体格式(.eot,.woff,.svg)

  • 抽出ttf中想要的字

    使用win上的FontCreator 7.5还是挺简单的,把要使用的到的字体对应复制一下应该就没问题了,当时参考的这里

  • font icon

    首先应该就是font awesome,然后淘宝的iconfont
    可以生成好字体文件和相应的样式

都是姿势

记录下

  • 用js 获取url参数
function getQueryString(name)
{
     var reg = new RegExp("(^|&)"+ name +"=([^&]*)(&|$)");
     // window.location.search 方法是截取当前url中“?”后面的字符串
     var r = window.location.search.substr(1).match(reg);
     if(r!=null)return  unescape(r[2]); return null;
}
  • 拼接url
    第一个参数用 ?index.html?type=pic 接下来的参数用**&** 如index.html?type=pic&id=1
    参数如果含有非英文的字符在页面用到时可能会出现乱码,这时需要用js中的encodeURI(str_arg)来编码成一堆百分号的形式,获取时就要用decodeURI()来解码

    如获取参数后用在handlebars中时 {{参数值}} 此参数值渲染出来就会乱码,就需要获取后用decodeURI()来解码也可以写个helper块

Handlebars.registerHelper("decodeURI",function(uri,options){
            return decodeURI(uri);
        });

handlebars中 {{#decodeURI 参数}}{{/decodeURI}}
当然如果传参数用到了 bandlebars 可以换成

Handlebars.registerHelper("encodeURI",function(uri,options){
           //好像浏览器会帮你解一次码  这里一般都会编两次码
            return encodeURI(encodeURI(uri));
        });

handlebars中 {{#encodeURI 参数}}{{/encodeURI}}


  • cookie 相关
 var getCookie = function(cookie_name)
{
    var allcookies = document.cookie;
    var cookie_pos = allcookies.indexOf(cookie_name);   //索引的长度

    // 如果找到了索引,就代表cookie存在,
    // 反之,就说明不存在。
    if (cookie_pos != -1)
    {
        // 把cookie_pos放在值的开始,只要给值加1即可。
        cookie_pos += cookie_name.length + 1;      //这里容易出问题,所以请大家参考的时候自己好好研究一下
        var cookie_end = allcookies.indexOf(";", cookie_pos);

        if (cookie_end == -1)
        {
            cookie_end = allcookies.length;
        }

        var value = unescape(allcookies.substring(cookie_pos, cookie_end));         //这里就可以得到你想要的cookie的值了。。。
    }
    return value;
}
exports.cookie = getCookie;

...

js Date

JS Date 对象用于处理日期和时间。

var myDate=new Date()

new Date("January 12,2006 22:19:35");

new Date("January 12,2006");

new Date(2006,0,12,22,19,35);

new Date(2006,0,12);

new Date(1137075575000);

ios中 new Date() 不支持类似1990-12-1这种格式 需转换为类似1990/12/1
项目中

//this.order.orderCompletedTime 为类似'2016-09-11 12:03:12'
new Date(this.order.orderCompletedTime.replace(/-/g, "/"))

获取某个月的天数

function getDays(year, month) {
  return new Date(year, month + 1, 0).getDate();
}

利用toLocaleString格式化日期

var date = new Date();
var result = date.toLocaleString('zh-CN', { hour12: false })
  .replace(/\//g, '-').replace(/\b\d\b/g, '0$&');

和这里
参考

正则

语法参考
1.正则表达式基本语法
正则表达式中常用的模式修正符有i、g、m、s、x、e等。它们之间可以组合搭配使用。

它们的作用如下:

//修正符:i 不区分大小写的匹配;

//如:"/abc/i"可以与abc或aBC或ABc等匹配;

//修正符:g表示全局匹配

//修正符:m 将字符串视为多行,不管是那行都能匹配;

例://模式为:$mode="/abc/m";
//要匹配的字符串为:$str="bcefg5e\nabcdfe"
//注意其中\n,换行了;abc换到了下一行;
//$str和$mode仍可以匹配,修正符m使得多行也可匹配;
//修正符:s 将字符串视为单行,换行符作为普通字符;

例://模式为:$mode="/pr.y/";
//要匹配字符串为:$str="pr\ny";
//两者不可匹配; . 是除了换行以外的字符可匹配;
//修改下模式为:$mode="/pr.y/s";
//其中修正符s将\n视为普通字符,即不是换行;
//最后两者可以匹配;
//修正符:x 将模式中的空白忽略;
//修正符:A 强制从目标字符串开头匹配;

例://$mode="/abc/A";
//可以与$str="abcsdfi"匹配,
//不可以与$str2="sdsdabc"匹配;
//因为$str2不是以abc开头;
//修正符:D 如果使用$限制结尾字符,则不允许结尾有换行;

例://模式为:$mode="/abc$/";
//可以与最后有换行的$str="adshabc\n"匹配;
//元子符$会忽略最后的换行\n;
//如果模式为:$mode="/abc/D",
//则不能与$str="adshabc\n"匹配,
//修正符D限制其不可有换行;必需以abc结尾;
//修正符:U 只匹配最近的一个字符串;不重复匹配;

例:
如模式为:
$mode="/a.*c/";
$str="abcabbbcabbbbbc" ;
preg_match($mode,$str,$content);
echo $content[0]; //输出:abcabbbcabbbbbc;

//如果$mode="/a._c/";变成$mode="/a._c/U";
// 则只匹配最近一个字符串,输出:abc;

//修正符:e 配合函数preg_replace()使用,

可以把匹配来的字符串当作正则表达式执行;

两个特殊的符号**'^'和'$'。他们的作用是分别指出一个字符串的开始和结束。例子如下:
"^The":表示所有以"The"开始的字符串("There","The cat"等);
"of despair$":表示所以以"of despair"结尾的字符串;
"^abc$":表示开始和结尾都是"abc"的字符串——呵呵,只有"abc"自己了;
"notice":表示任何包含"notice"的字符串。
象最后那个例子,如果你不使用两个特殊字符,你就在表示要查找的串在被查找串的任意部分——你并
不把它定位在某一个顶端。
其它还有
' * ','+'和'?'**这三个符号,表示一个或一序列字符重复出现的次数。它们分别表示“没有或
更多”,“一次或更多”还有“没有或一次”。下面是几个例子:
"ab_":表示一个字符串有一个a后面跟着零个或若干个b。("a", "ab", "abbb",……);
"ab+":表示一个字符串有一个a后面跟着至少一个b或者更多;
"ab?":表示一个字符串有一个a后面跟着零个或者一个b;
"a?b+$":表示在字符串的末尾有零个或一个a跟着一个或几个b。
你也可以使用范围,用{}大括号括起,用以表示重复次数的范围。
"ab{2}":表示一个字符串有一个a跟着2个b("abb");
"ab{2,}":表示一个字符串有一个a跟着至少2个b;
"ab{3,5}":表示一个字符串有一个a跟着3到5个b。
请注意,你必须指定范围的下限(如:"{0,2}"而不是"{,2}")。还有,你可能注意到了,'_','+'和
'?'相当于"{0,}","{1,}"和"{0,1}"。
还有一个'¦',表示“或”操作:
"hi¦hello":表示一个字符串里有"hi"或者"hello";
"(b¦cd)ef":表示"bef"或"cdef";
"(a¦b)c":表示一串"a""b"混合的字符串后面跟一个"c";
'.'可以替代任何字符:
"a.[0-9]":表示一个字符串有一个"a"后面跟着一个任意字符和一个数字;
"^.{3}$":表示有任意三个字符的字符串(长度为3个字符);
方括号表示某些字符允许在一个字符串中的某一特定位置出现:
"[ab]":表示一个字符串有一个"a"或"b"(相当于"a¦b");
"[a-d]":表示一个字符串包含小写的'a'到'd'中的一个(相当于"a¦b¦c¦d"或者"[abcd]");
"^[a-zA-Z]":表示一个以字母开头的字符串;
"[0-9]%":表示一个百分号前有一位的数字;
",[a-zA-Z0-9]$":表示一个字符串以一个逗号后面跟着一个字母或数字结束。
你也可以在方括号里用'^'表示不希望出现的字符,'^'应在方括号里的第一位。(如:"%[^a-zA-Z]%"表
示两个百分号中不应该出现字母)。
为了逐字表达,你必须在"^.$()¦
+?{"这些字符前加上转移字符''。
请注意在方括号中,不需要转义字符。

2.正则表达式验证控制文本框的输入字符类型
1.只能输入数字和英文的:
<input onkeyup="value=value.replace(/[\W]/g,'') " onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^\d]/g,''))" ID="Text1" NAME="Text1">

2.只能输入数字的:
<input onkeyup="value=value.replace(/[^\d]/g,'') " onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^\d]/g,''))" ID="Text2" NAME="Text2">

3.只能输入全角的:
<input onkeyup="value=value.replace(/[^\uFF00-\uFFFF]/g,'')" onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^\uFF00-\uFFFF]/g,''))" ID="Text3" NAME="Text3">

4.只能输入汉字的:
<input onkeyup="value=value.replace(/[^\u4E00-\u9FA5]/g,'')" onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^\u4E00-\u9FA5]/g,''))" ID="Text4" NAME="Text4">

3.正则表达式的应用实例通俗说明


//校验是否全由数字组成
/^[0-9]{1,20}$/

^ 表示打头的字符要匹配紧跟^后面的规则
$ 表示打头的字符要匹配紧靠$前面的规则
[ ] 中的内容是可选字符集
[0-9] 表示要求字符范围在0-9之间
{1,20}表示数字字符串长度合法为1到20,即为[0-9]中的字符出现次数的范围是1到20次。

/^ 和 $/成对使用应该是表示要求整个字符串完全匹配定义的规则,而不是只匹配字符串中的一个子串。


//校验登录名:只能输入5-20个以字母开头、可带数字、“”、“.”的字串
/^[a-zA-Z]{1}([a-zA-Z0-9]|[.
]){4,19}$/

^[a-zA-Z]{1} 表示第一个字符要求是字母。
([a-zA-Z0-9]|[.]){4,19} 表示从第二位开始(因为它紧跟在上个表达式后面)的一个长度为4到9位的字符串,它要求是由大小写字母、数字或者特殊字符集[.]组成。


//校验用户姓名:只能输入1-30个以字母开头的字串
/^[a-zA-Z]{1,30}$/


//校验密码:只能输入6-20个字母、数字、下划线
/^(\w){6,20}$/

\w:用于匹配字母,数字或下划线字符


//校验普通电话、传真号码:可以“+”或数字开头,可含有“-” 和 “ ”
/^[+]{0,1}(\d){1,3}[ ]?([-]?((\d)|[ ]){1,12})+$/

\d:用于匹配从0到9的数字;
“?”元字符规定其前导对象必须在目标对象中连续出现零次或一次

可以匹配的字符串如:+123 -999 999 ; +123-999 999 ;123 999 999 ;+123 999999等


//校验URL
/^http[s]{0,1}://.+$/ 或 /^http[s]{0,1}://.{1,n}$/ (表示url串的长度为length(“https://”) + n )

\ / :表示字符“/”。
. 表示所有字符的集

  • 等同于{1,},就是1到正无穷吧。

//校验纯中文字符
/^[\u4E00-\u9FA5]+$/

[\u4E00-\u9FA5] :估计是中文字符集的范围吧

以上表达式均在下面的javascript中测试通过

<script language="JavaScript"> </script> 规则表达式 : (填写/ /之间的表达式)
校验字符串 :
   <input type="button" name="match" value="匹配" onClick="alert(regx(regxStr.value,str.value));">

4.正則表達式應用

"^\d+$"  //非负整数(正整数 + 0)
"^[0-9][1-9][0-9]$"  //正整数
"^((-\d+)|(0+))$"  //非正整数(负整数 + 0)
"^-[0-9][1-9][0-9]$"  //负整数
"^-?\d+$"    //整数
"^\d+(.\d+)?$"  //非负浮点数(正浮点数 + 0)
"^(([0-9]+.[0-9][1-9][0-9])|([0-9][1-9][0-9].[0-9]+)|([0-9][1-9][0-9]))$"  //正浮点数
"^((-\d+(.\d+)?)|(0+(.0+)?))$"  //非正浮点数(负浮点数 + 0)
"^(-(([0-9]+.[0-9][1-9][0-9])|([0-9][1-9][0-9].[0-9]+)|([0-9][1-9][0-9])))$"  //负浮点数
"^(-?\d+)(.\d+)?$"  //浮点数
"^[A-Za-z]+$"  //由26个英文字母组成的字符串
"^[A-Z]+$"  //由26个英文字母的大写组成的字符串
"^[a-z]+$"  //由26个英文字母的小写组成的字符串
"^[A-Za-z0-9]+$"  //由数字和26个英文字母组成的字符串
"^\w+$"  //由数字、26个英文字母或者下划线组成的字符串
"^[\w-]+(.[\w-]+)@[\w-]+(.[\w-]+)+$"    //email地址
"^[a-zA-z]+://(\w+(-\w+)
)(.(\w+(-\w+)))(?\S*)?$"  //url
/^(d{2}|d{4})-((0([1-9]{1}))|(1[1|2]))-((0-2)|(3[0|1]))$/ // 年-月-日
/^((0([1-9]{1}))|(1[1|2]))/((0-2)|(3[0|1]))/(d{2}|d{4})$/ // 月/日/年
"^([w-.]+)@(([[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.)|(([w-]+.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(]?)$" //Emil
"(d+-)?(d{4}-?d{7}|d{3}-?d{8}|^d{7,8})(-d+)?" //电话号码
"^(d{1,2}|1dd|2[0-4]d|25[0-5]).(d{1,2}|1dd|2[0-4]d|25[0-5]).(d{1,2}|1dd|2[0-4]d|25[0-5]).(d{1,2}|1dd|2[0-4]d|25[0-5])$" //IP地址
^([0-9A-F]{2})(-[0-9A-F]{2}){5}$ //MAC地址的正则表达式
^[-+]?\d+(.\d+)?$ //值类型正则表达式

5.javascript正则表达式检验
//校验是否全由数字组成
function isDigit(s)
{
var patrn=/^[0-9]{1,20}$/;
if (!patrn.exec(s)) return false
return true
}
//校验登录名:只能输入5-20个以字母开头、可带数字、“”、“.”的字串
function isRegisterUserName(s)
{
var patrn=/^[a-zA-Z]{1}([a-zA-Z0-9]|[.
]){4,19}$/;
if (!patrn.exec(s)) return false
return true
}
//校验用户姓名:只能输入1-30个以字母开头的字串
function isTrueName(s)
{
var patrn=/^[a-zA-Z]{1,30}$/;
if (!patrn.exec(s)) return false
return true
}
//校验密码:只能输入6-20个字母、数字、下划线
function isPasswd(s)
{
var patrn=/^(\w){6,20}$/;
if (!patrn.exec(s)) return false
return true
}
//校验普通电话、传真号码:可以“+”开头,除数字外,可含有“-”
function isTel(s)
{
//var patrn=/^[+]{0,1}(\d){1,3}[ ]?([-]?(\d){1,12})+$/;
var patrn=/^[+]{0,1}(\d){1,3}[ ]?([-]?((\d)|[ ]){1,12})+$/;
if (!patrn.exec(s)) return false
return true
}
//校验手机号码:必须以数字开头,除数字外,可含有“-”
function isMobil(s)
{
var patrn=/^[+]{0,1}(\d){1,3}[ ]?([-]?((\d)|[ ]){1,12})+$/;
if (!patrn.exec(s)) return false
return true
}
//校验邮政编码
function isPostalCode(s)
{
//var patrn=/^[a-zA-Z0-9]{3,12}$/;
var patrn=/^[a-zA-Z0-9 ]{3,12}$/;
if (!patrn.exec(s)) return false
return true
}
//校验搜索关键字
function isSearch(s)
{
var patrn=/^[^`~!@#$%^&*()+=|\\\][\]\{\}:;\'\,.<>/?]{1}[^`~!@$%^&()+=|\][]{}:;\'\,.<>?]{0,19}$/;
if (!patrn.exec(s)) return false
return true
}
function isIP(s) //by zergling
{
var patrn=/^[0-9.]{1,20}$/;
if (!patrn.exec(s)) return false
return true
}

/*********************************************************************************

  • FUNCTION: isBetween
  • PARAMETERS: val AS any value
  • lo AS Lower limit to check
  • hi AS Higher limit to check
  • CALLS: NOTHING
  • RETURNS: TRUE if val is between lo and hi both inclusive, otherwise false.
    *_/
    function isBetween (val, lo, hi) {
    if ((val < lo) || (val > hi)) { return(false); }
    else { return(true); }
    }
    /_
  • FUNCTION: isDate checks a valid date
  • PARAMETERS: theStr AS String
  • CALLS: isBetween, isInt
  • RETURNS: TRUE if theStr is a valid date otherwise false.
    *_/
    function isDate (theStr) {
    var the1st = theStr.indexOf('-');
    var the2nd = theStr.lastIndexOf('-');
    if (the1st == the2nd) { return(false); }
    else {
    var y = theStr.substring(0,the1st);
    var m = theStr.substring(the1st+1,the2nd);
    var d = theStr.substring(the2nd+1,theStr.length);
    var maxDays = 31;
    if (isInt(m)==false || isInt(d)==false || isInt(y)==false) {
    return(false); }
    else if (y.length < 4) { return(false); }
    else if (!isBetween (m, 1, 12)) { return(false); }
    else if (m==4 || m==6 || m==9 || m==11) maxDays = 30;
    else if (m==2) {
    if (y % 4 > 0) maxDays = 28;
    else if (y % 100 == 0 && y % 400 > 0) maxDays = 28;
    else maxDays = 29;
    }
    if (isBetween(d, 1, maxDays) == false) { return(false); }
    else { return(true); }
    }
    }
    /_
  • FUNCTION: isEuDate checks a valid date in British format
  • PARAMETERS: theStr AS String
  • CALLS: isBetween, isInt
  • RETURNS: TRUE if theStr is a valid date otherwise false.
    **_/
    function isEuDate (theStr) {
    if (isBetween(theStr.length, 8, 10) == false) { return(false); }
    else {
    var the1st = theStr.indexOf('/');
    var the2nd = theStr.lastIndexOf('/');
    if (the1st == the2nd) { return(false); }
    else {
    var m = theStr.substring(the1st+1,the2nd);
    var d = theStr.substring(0,the1st);
    var y = theStr.substring(the2nd+1,theStr.length);
    var maxDays = 31;
    if (isInt(m)==false || isInt(d)==false || isInt(y)==false) {
    return(false); }
    else if (y.length < 4) { return(false); }
    else if (isBetween (m, 1, 12) == false) { return(false); }
    else if (m==4 || m==6 || m==9 || m==11) maxDays = 30;
    else if (m==2) {
    if (y % 4 > 0) maxDays = 28;
    else if (y % 100 == 0 && y % 400 > 0) maxDays = 28;
    else maxDays = 29;
    }
    if (isBetween(d, 1, maxDays) == false) { return(false); }
    else { return(true); }
    }
    }
    }
    /_
  • FUNCTION: Compare Date! Which is the latest!
  • PARAMETERS: lessDate,moreDate AS String
  • CALLS: isDate,isBetween
  • RETURNS: TRUE if lessDate<moreDate
    /
    function isComdate (lessDate , moreDate)
    {
    if (!isDate(lessDate)) { return(false);}
    if (!isDate(moreDate)) { return(false);}
    var less1st = lessDate.indexOf('-');
    var less2nd = lessDate.lastIndexOf('-');
    var more1st = moreDate.indexOf('-');
    var more2nd = moreDate.lastIndexOf('-');
    var lessy = lessDate.substring(0,less1st);
    var lessm = lessDate.substring(less1st+1,less2nd);
    var lessd = lessDate.substring(less2nd+1,lessDate.length);
    var morey = moreDate.substring(0,more1st);
    var morem = moreDate.substring(more1st+1,more2nd);
    var mored = moreDate.substring(more2nd+1,moreDate.length);
    var Date1 = new Date(lessy,lessm,lessd);
    var Date2 = new Date(morey,morem,mored);
    if (Date1>Date2) { return(false);}
    return(true);
    }
    /
  • FUNCTION isEmpty checks if the parameter is empty or null
  • PARAMETER str AS String
    *_/
    function isEmpty (str) {
    if ((str==null)||(str.length==0)) return true;
    else return(false);
    }
    /_
  • FUNCTION: isInt
  • PARAMETER: theStr AS String
  • RETURNS: TRUE if the passed parameter is an integer, otherwise FALSE
  • CALLS: isDigit
    *_/
    function isInt (theStr) {
    var flag = true;
    if (isEmpty(theStr)) { flag=false; }
    else
    { for (var i=0; i<theStr.length; i++) {
    if (isDigit(theStr.substring(i,i+1)) == false) {
    flag = false; break;
    }
    }
    }
    return(flag);
    }
    /_
  • FUNCTION: isReal
  • PARAMETER: heStr AS String
    decLen AS Integer (how many digits after period)
  • RETURNS: TRUE if theStr is a float, otherwise FALSE
  • CALLS: isInt
    *_/
    function isReal (theStr, decLen) {
    var dot1st = theStr.indexOf('.');
    var dot2nd = theStr.lastIndexOf('.');
    var OK = true;
    if (isEmpty(theStr)) return false;
    if (dot1st == -1) {
    if (!isInt(theStr)) return(false);
    else return(true);
    }
    else if (dot1st != dot2nd) return (false);
    else if (dot1st==0) return (false);
    else {
    var intPart = theStr.substring(0, dot1st);
    var decPart = theStr.substring(dot2nd+1);
    if (decPart.length > decLen) return(false);
    else if (!isInt(intPart) || !isInt(decPart)) return (false);
    else if (isEmpty(decPart)) return (false);
    else return(true);
    }
    }
    /_
  • FUNCTION: isEmail
  • PARAMETER: String (Email Address)
  • RETURNS: TRUE if the String is a valid Email address
  • FALSE if the passed string is not a valid Email Address
  • EMAIL FORMAT: AnyName@EmailServer e.g; [email protected]
  • @ sign can appear only once in the email address.
    _/
    function isEmail (theStr) {
    var atIndex = theStr.indexOf('@');
    var dotIndex = theStr.indexOf('.', atIndex);
    var flag = true;
    theSub = theStr.substring(0, dotIndex+1)
    if ((atIndex < 1)||(atIndex != theStr.lastIndexOf('@'))||(dotIndex < atIndex + 2)||(theStr.length <= theSub.length))
    { return(false); }
    else { return(true); }
    }
    /_
  • FUNCTION: newWindow
  • PARAMETERS: doc -> Document to open in the new window
    hite -> Height of the new window
    wide -> Width of the new window
    bars -> 1-Scroll bars = YES 0-Scroll Bars = NO
    resize -> 1-Resizable = YES 0-Resizable = NO
  • CALLS: NONE
  • RETURNS: New window instance
    *_/
    function newWindow (doc, hite, wide, bars, resize) {
    var winNew="_blank";
    var opt="toolbar=0,location=0,directories=0,status=0,menubar=0,";
    opt+=("scrollbars="+bars+",");
    opt+=("resizable="+resize+",");
    opt+=("width="+wide+",");
    opt+=("height="+hite);
    winHandle=window.open(doc,winNew,opt);
    return;
    }
    /_
  • FUNCTION: DecimalFormat
  • PARAMETERS: paramValue -> Field value
  • CALLS: NONE
  • RETURNS: Formated string
    **********************************************************************************/
    function DecimalFormat (paramValue) {
    var intPart = parseInt(paramValue);
    var decPart =parseFloat(paramValue) - intPart;
    str = "";
    if ((decPart == 0) || (decPart == null)) str += (intPart + ".00");
    else str += (intPart + decPart);
    return (str);
    }

"^\d+$"  //非负整数(正整数 + 0)
"^[0-9][1-9][0-9]$"  //正整数
"^((-\d+)|(0+))$"  //非正整数(负整数 + 0)
"^-[0-9][1-9][0-9]$"  //负整数
"^-?\d+$"    //整数
"^\d+(.\d+)?$"  //非负浮点数(正浮点数 + 0)
"^(([0-9]+.[0-9][1-9][0-9])|([0-9][1-9][0-9].[0-9]+)|([0-9][1-9][0-9]))$"  //正浮点数
"^((-\d+(.\d+)?)|(0+(.0+)?))$"  //非正浮点数(负浮点数 + 0)
"^(-(([0-9]+.[0-9][1-9][0-9])|([0-9][1-9][0-9].[0-9]+)|([0-9][1-9][0-9])))$"  //负浮点数
"^(-?\d+)(.\d+)?$"  //浮点数
"^[A-Za-z]+$"  //由26个英文字母组成的字符串
"^[A-Z]+$"  //由26个英文字母的大写组成的字符串
"^[a-z]+$"  //由26个英文字母的小写组成的字符串
"^[A-Za-z0-9]+$"  //由数字和26个英文字母组成的字符串
"^\w+$"  //由数字、26个英文字母或者下划线组成的字符串
"^[\w-]+(.[\w-]+)@[\w-]+(.[\w-]+)+$"    //email地址
"^[a-zA-z]+://(\w+(-\w+)
)(.(\w+(-\w+)))(?\S*)?$"  //url

webstrom中vue语法高亮

webstorm中有两个vue插件vue和vue-for-idea

这个vue-for-idea安装后style标签中sass可能就报错 但项目建完索引后node_moudles目录就消失了,所以不推荐安装这个

vue这个插件虽然style中的sass语法报错 只需

<style lang="sass" rel="stylesheet/scss">

即可

对于js<script type="text/babel">即可

JSON.stringify() 与JSON.parse()

JSON.stringify()

将一个js对象 字符串化(将一个对象转化成json字符串);

var a = {a:1,b:2}

JSON.stringify(a)

//"{"a":1,"b":2}"

JSON.parse()

parse用于从一个字符串中解析出json对象

var str = '{"name":"huangxiaojian","age":"23"}'

JSON.parse(str)

//Object
//age: "23"
//name: "huangxiaojian"
//__proto__: Object

注意:单引号写在{}外,每个属性名都必须用双引号,否则会抛出异常。

sessionStorage

本地存储解决方案

  • Cookie: 在web中得到广泛应用,但局限性非常明显,容量太小,有些站点会因为出于安全的考虑而禁用cookie,cookie没有想象中的那么安全,Cookie 的内容会随着页面请求一并发往服务器。Cookie的大小是受限的,并且每次你请求一个新的页面的时候Cookie都会被发送过去,这样无形中浪费了带宽,另外cookie还需要指定作用域,不可以跨域调用。
  • localStorage: 相对于上述本地存储方案,localStorage有自身的优点:容量大、易用、强大、原生支持;缺点是兼容性差些(chrome, safari, firefox,IE 9,IE8都支持 localStorage,主要是IE8以下版本不支持)、安全性也差些(所以请勿使用localStorage保存敏感信息)。

sessionStorage和上文中提到的localStorage非常相识,方法也几乎一样:

非常通俗易懂的接口:

  • sessionStorage.getItem(key):获取指定key本地存储的值
  • sessionStorage.setItem(key,value):将value存储到key字段
//value如果是对象要先使用JSON.stringify()转换成JSON字符串,等获取时在使用JSON.parse()解析成object

sessionStorage.setItem("testsS",JSON.stringify({test:"testForSessionStorage"}));

console.log(JSON.parse(sessionStorage.getItem("testsS")).test);
  • sessionStorage.removeItem(key):删除指定key本地存储的值
  • sessionStorage.length是sessionStorage的项目数

sessionStorage 和 localStorage 就一个不同的地方, sessionStorage数据的存储仅特定于某个会话中,也就是说数据只保持到浏览器关闭,当浏览器关闭后重新打开这个页面时,之前的存储已经被清除。而 localStorage 是一个持久化的存储,它并不局限于会话。

sessionStorage和localStorage提供的key()和length可以方便的实现存储的数据遍历,例如下面的代码:
[code=”javascript”]
var storage = window.localStorage;
for (var i=0, len = storage.length; i < len; i++){ var key = storage.key(i); var value = storage.getItem(key); console.log(key + "=" + value); } [/code] sessionStorage 和 localStorage的clear()函数的用于清空同源的本地存储数据,比如localStorage.clear(),它将删除所有同源的本地存储的localStorage数据,而对于Session Storage,它只清空当前会话存储的数据。 关闭页面会导致 sessionStorage 的数据被清除,但刷新或重新打开新页面数据还是存在,如果需要存储的只是少量的临时数据。我们可以使用sessionStorage 。或者做页面间的小交互。 sessionStorage 和 localStorage具有相同的方法storage事件,在存储事件的处理函数中是不能取消这个存储动作的。存储事件只是浏览器在数据变化发生之后给你的一个通知。当setItem(),removeItem()或者clear() 方法被调用,并且数据真的发生了改变时,storage事件就会被触发。注意这里的的条件是数据真的发生了变化。也就是说,如果当前的存储区域是空的,你再去调用clear()是不会触发事件的。或者你通过setItem()来设置一个与现有值相同的值,事件也是不会触发的。当存储区域发生改变时就会被触发,这其中包含许多有用的属性:

storageArea: 表示存储类型(Session或Local)
key:发生改变项的key
oldValue: key的原值
newValue: key的新值
url*: key改变发生的URL

  • 注意: url 属性早期的规范中为uri属性。有些浏览器发布较早,没有包含这一变更。为兼容性考虑,使用url属性前,你应该先检查它是否存在,如果没有url属性,则应该使用uri属性
    如果调用clear()方法,那么key、oldValue和newValue都会被设置为null。
    PS.在firefox和chrome中存储和读取都是正常的, 但是对storage事件的触发似乎有点问题, 自身页面进行setItem后没有触发window的storage事件, 但是同时访问A.html和B.html, 在A页面中进行 setItem能触发B页面中window的storage事件, 同样的在B页面中进行setItem能触发A页面中window的storage事件. 在IE9中, 页面自身的设值能触发当前页面的storage事件,同样当前页面的设值能触发同一”起源”下其他页面window的storage事件,这看起来似乎更让人想的通些.

async 函数 async 和 await

async 函数

  • async函数自带执行器。

  • async和await,比起星号和yield,语义更清楚了。async表示函数里有异步操作,await表示紧跟在后面的表达式需要等待结果。

  • co模块约定,yield命令后面只能是Thunk函数或Promise对象,而async函数的await命令后面,可以是Promise对象和原始类型的值(数值、字符串和布尔值,但这时等同于同步操作)。

  • 返回值是Promise。async函数的返回值是Promise对象,这比Generator函数的返回值是Iterator对象方便多了。你可以用then方法指定下一步的操作。

    进一步说,async函数完全可以看作多个异步操作,包装成的一个Promise对象,而await命令就是内部then命令的语法糖。

    async函数返回一个Promise对象。

    async函数内部return语句返回的值,会成为then方法回调函数的参数。

    正常情况下,await命令后面是一个Promise对象。如果不是,会被转成一个立即resolve的Promise对象。

async function someAsyncfn(){

}

参考

Vue

  1. porps 与 v-bind
    模板中属性值为动态的(vue组件类中的表达式 如 data属性中的值,props,methods,computed中的值等),要用v-bind绑定该属性
    porps,组件标签上的属性, 此外 ~~模板里的标签中用到props的属性要用动态绑定使用:属性名~~好像标签中属性值是动态的属性名前都要有_:_来动态绑定

    伪代码为

    <child  :name='somethingfromfather'></child>
    //模板中
    <input  :value='name' type="text" />
    ...
    //类中属性
    default export{
        props:['name']
    }
  2. events $emit (es6相关= =)

    用实例或this调用.$emit等方法 只能触发组件自身的自定义事件 即组件实例.$on绑定的或events属性中声明的自定义事件Object.assign方法的第一个参数是目标对象,后面的参数都是源对象。
    注意,如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性。Object.assign方法实行的是浅拷贝,而不是深拷贝。也就是说,如果源对象某个属性的值是对象,那么目标对象拷贝得到的是这个对象的引用。一旦遇到同名属性,Object.assign的处理方法是替换,而不是添加。

  3. Object.assgin

    Object.assign方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)。

  4. slot

    一般来说,组件标签中内容将被抛弃(不渲染),除非其模板中有slot标签,如果组件标签中没内容,则会显示其模板中slot标签的内容

    假定 my-component 组件有下面模板:

<div>
  <h1>This is my component!</h1>
  <slot>
    如果没有分发内容则显示我。
  </slot>
</div>

父组件模板:

<my-component>
  <p>This is some original content</p>
  <p>This is some more original content</p>
</my-component>

渲染结果:

<div>
  <h1>This is my component!</h1>
  <p>This is some original content</p>
  <p>This is some more original content</p>
</div>

具名slot slot 可以有name属性 组件标签里的内容元素可以有slot属性,其值对应slot标签的name属性来插入同名的slot插槽中,没slot属性的插到没name属性的slot标签中,找不到的就抛弃

[参考doc](http://vuejs.org.cn/guide/components.html#单个-Slot)

js判断浏览器(或 ua) 是移动端还是pc端

var browser={  
    versions:function(){   
           var u = navigator.userAgent, app = navigator.appVersion;   
           return {//移动终端浏览器版本信息
                trident: u.indexOf('Trident') > -1, //IE内核
                presto: u.indexOf('Presto') > -1, //opera内核
                webKit: u.indexOf('AppleWebKit') > -1, //苹果、谷歌内核
                gecko: u.indexOf('Gecko') > -1 && u.indexOf('KHTML') == -1, //火狐内核
                mobile: !!u.match(/AppleWebKit.*Mobile.*/), //是否为移动终端
                ios: !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/), //ios终端
                android: u.indexOf('Android') > -1 || u.indexOf('Linux') > -1, //android终端或者uc浏览器
                iPhone: u.indexOf('iPhone') > -1 , //是否为iPhone或者QQHD浏览器
                iPad: u.indexOf('iPad') > -1, //是否iPad
                webApp: u.indexOf('Safari') == -1 //是否web应该程序,没有头部与底部
            };  
         }(),  
         language:(navigator.browserLanguage || navigator.language).toLowerCase()  
}   

  if(browser.versions.mobile || browser.versions.ios || browser.versions.android ||   
    browser.versions.iPhone || browser.versions.iPad){        
        console.log('mobile');      
  }else{console.log('pc')}

当然 如果使用chrome或Firefox的开发者工具 是可以转换移动端的 例如
devtool

切换之后内核也会相应跟着切换

js全局变量 与 const相关, js插件写法

  • 使用window.变量名定义为全局变量,但是注意:调用时候建议写上window.变量名,当然也可以不写
  • 当全局变量跟局部变量重名时,局部变量的scope会覆盖掉全局变量的scope,当离开局部变量的scope后,又重回到全局变量的scope,而当全局变量遇上局部变量时,怎样使用全局变量呢?用window.globalVariableName

全局变量的优点:

可以减少变量的个数,减少由于实际参数和形式参数的数据传递带来的时间消耗。

全局变量的缺点:

(1)全局变量保存在静态存贮区,程序开始运行时为其分配内存,程序结束释放该内存。与局部变量的动态分配、动态释放相比,生存期比较长,因此过多的全局变量会占用较多的内存单元。

(2)全局变量破坏了函数的封装性能。函数象一个黑匣子,一般是通过函数参数和返回值进行输入输出,函数内部实现相对独立。但函数中如果使用了全局变量,那么函数体内的语句就可以绕过函数参数和返回值进行存取,这种情况破坏了函数的独立性,使函数对全局变量产生依赖。同时,也降低了该函数的可移植性。

(3)全局变量使函数的代码可读性降低。由于多个函数都可能使用全局变量,函数执行时全局变量的值可能随时发生变化,对于程序的查错和调试都非常不利。
因此,如果不是万不得已,最好不要使用全局变量。

**let命令、const命令、class命令声明的全局变量,不属于全局对象的属性。**也就是说,从ES6开始,全局变量将逐步与全局对象的属性脱钩。

var a = 1;
// 如果在Node的REPL环境,可以写成global.a
// 或者采用通用方法,写成this.a
window.a // 1

let b = 1;
window.b // undefined

上面代码中,全局变量a由var命令声明,所以它是全局对象的属性;全局变量b由let命令声明,所以它不是全局对象的属性,返回undefined

项目中留意到,注意:

//在emc项目的某个api.js中,文件只是存放一些将要export导出的变量或方法
//项目中其实并没用引用api.js文件(只是import它export的方法等),虽然在emc.js(全局common.js)中定义了window.test
//但在这个文件(此文件与emc.js文件是相互独立的)中是没定义window.test的
//所以a 为 undefined
const a = window.test

v-if 相关

注意 v-show 不支持<template>语法。

v-else 元素必须立即跟在 v-if 或 v-show 元素的后面——否则它不能被识别。
好像也不存在 v-else-if 这种指令(if elseif else)

将 v-show 用在组件上时,因为指令的优先级 v-else 会出现问题。因此不要这样做:

<custom-component v-show="condition"></custom-component>
<p v-else>这可能也是一个组件</p>

用另一个 v-show 替换 v-else:

<custom-component v-show="condition"></custom-component>
<p v-show="!condition">这可能也是一个组件</p>

这样就可以达到 v-if 的效果。

v-if vs. v-show

在切换 v-if块时,Vue.js 有一个局部编译/卸载过程,因为 v-if 之中的模板也可能包括数据绑定或子组件。v-if 是真实的条件渲染,因为它会确保条件块在切换当中合适地销毁与重建条件块内的事件监听器和子组件。

v-if 也是惰性的:如果在初始渲染时条件为假,则什么也不做——在条件第一次变为真时才开始局部编译(编译会被缓存起来)。

相比之下,v-show 简单得多——元素始终被编译并保留,只是简单地基于 CSS 切换

一般来说,v-if 有更高的切换消耗而 v-show 有更高的初始渲染消耗。因此,如果需要频繁切换 v-show 较好,如果在运行时条件不大可能改变 v-if 较好。


项目中发现通过v-if切换的模板块 在切换之后vm的 $data中的值会被重置,造成bug.现在来看 也就是因为v-if切换时局部编译/卸载过程 , 对条件块内的事件监听器和子组件 合适地销毁与重建造成的吧

事件监听 addEventListener

参考

  • 绑定事件监听
element.addEventListener(<event-name>, <callback>, <use-capture>);

表示在 element 这个对象上面添加一个事件监听器,当监听到有 事件发生的时候,调用 这个回调函数。至于 这个参数,表示该事件监听是在“捕获”阶段中监听(设置为 true)还是在“冒泡”阶段中监听(设置为 false)。关于捕获和冒泡,我们会在下面讲解。

  • 移除事件监听

当我们为某个元素绑定了一个事件,每次触发这个事件的时候,都会执行事件绑定的回调函数。如果我们想解除绑定,需要使用 removeEventListener 方法:

element.removeEventListener(<event-name>, <callback>, <use-capture>);

需要注意的是,绑定事件时的回调函数不能是匿名函数,必须是一个声明的函数,因为解除事件绑定时需要传递这个回调函数的引用,才可以断开绑定。例如:

var fun = function() {
    // function logic
};


element.addEventListener('click', fun, false);
element.removeEventListener('click', fun, false);

一个非常棒的关于事件捕获与事件冒泡的demoClick on a layer to watch the event move through the DOM tree.

webpack 引入样式 与 使用ExtractTextPlugin插件

使用webpack打包代码可以将各种类型的文件当做模块,即样式,图片都可以当做模块被require()进来,对于样式文件来说,好像是将样式文件通过相应的loader转化为字符串打包到js文件中,再由js生成style标签将样式放在style标签中插入到head标签中,这样做缺点是会使js文件体积变大

而通过extract-text-webpack-plugin插件则可以将样式从js中抽出,生成单独的.css样式文件(根据entry入口),通过link标签引入.优缺点:

Advantages:

  • Fewer style tags (older IE has a limit)
  • CSS SourceMap (with devtool: "source-map" and css-loader?sourceMap)
  • CSS requested in parallel
  • CSS cached separate
  • Faster runtime (less code and DOM operations)
    Caveats:
  • Additional HTTP request
  • Longer compilation time
  • More complex configuration
  • No runtime public path modification
  • No Hot Module Replacement
    主要缺点应该是涉及资源引用加载,和无法热更新(配置了热更新的话想要看效果就得手动刷新)

使用 extract-text-webpack-plugin

一般将整个项目的大的公共样式集,通过入口js引入,再通过此插件提取,然后在html或模板中引入

一个大的公共样式集

webpackstyle

入口js引入
//ExtractTextPlugin.extract()中第一个参数是可选项一般是style-loader (第一个参数的文档说明为:notExtractLoader (optional) the loader(s) that should be used when the css is not extracted
//,即css不提取时的loader,通过style-loader可以将css用style标签放到头部)
{test: /\.css$/, loader: ExtractTextPlugin.extract('style', 'css?'+(DEBUG?'sourceMap':'')+'!postcss')},
{test: /\.scss$/, loader: ExtractTextPlugin.extract('style', 'css?'+(DEBUG?'sourceMap':'')+`!postcss!sass?`+(DEBUG?'sourceMap':'')+'')},
  • vue文件使用 在webpack.config.js中配置vue-loader
// vue-loader configurations
    vue: {
        // configure autoprefixer
        autoprefixer: {
            browsers: [
                'last 3 versions',
                'ie >= 8',
                'ff >= 30',
                'chrome >= 31'
            ]
        },
        //vue-loader config  主要是这里,开发时不用这个(由于不得不手动刷新)
        loaders: {
            css: DEBUG ? 'style!css' : ExtractTextPlugin.extract("css"),
            sass: DEBUG ? "style!css!sass" : ExtractTextPlugin.extract("css!sass")
        }
    },

css animation相关

animation

-webkit-animation-name:'name';/*动画属性名,也就是某个keyframes定义的动画名*/
 -webkit-animation-duration: 10s;/*动画持续时间*/
 -webkit-animation-timing-function: ease-in-out; /*动画频率,和transition-timing-function是一样的*/
 -webkit-animation-delay: 2s;/*动画延迟时间*/
 -webkit-animation-iteration-count: 10;/*定义循环次数,infinite为无限次*/
 -webkit-animation-direction: alternate;/*定义动画方式 规定是否应该轮流反向播放动画。如果 animation-direction 值是 "alternate",则动画会在奇数次数(1、3、5 等等)正常播放,而在偶数次数(2、4、6 等等)向后播放。*/
  • animation-delay 动画延时

    属性定义动画何时开始。
    animation-delay 值以秒或毫秒计。
    提示:允许负值,-2s 使动画马上开始,但跳过 2 秒进入动画。

  • animation-fill-mode属性规定动画在播放之前或之后,其动画效果是否可见。

描述
none 不改变默认行为。
forwards 当动画完成后,保持最后一个属性值(在最后一个关键帧中定义)。
backwards 在 animation-delay 所指定的一段时间内,在动画显示之前,应用开始属性值(在第一个关键帧中定义)。
both 向前和向后填充模式都被应用。

vue debounce 延迟 v-ref 子组件索引 v-el dom索引

  • debounce 过滤器 和 debounce属性

    限制: 指令的值须是函数,如 v-on

    参数:
    {Number} [wait] - 默认值: 300

    用法:

    包装处理器,让它延迟执行 x ms, 默认延迟 300ms。包装后的处理器在调用之后至少将延迟 x ms, 如果在延迟结束前再次调用,延迟时长重置为 x ms。

    示例:

    <input @keyup="onKeyup | debounce 500">

    debounce属性
    设置一个最小的延时,在每次敲击之后延时同步输入框的值与数据。如果每次更新都要进行高耗操作(例如在输入提示中 Ajax 请求),它较为有用。

    <input v-model="msg" debounce="500">

    注意 debounce 参数不会延迟 input 事件:它延迟“写入”底层数据。因此在使用 debounce 时应当用 vm.$watch() 响应数据的变化。若想延迟 DOM 事件,应当使用 debounce 过滤器。

  • v-ref

在父组件上注册一个子组件的索引,便于直接访问。不需要表达式。必须提供参数 id。可以通过父组件的 $refs 对象访问子组件。

在和 v-for 一起用时,注册的值将是一个数组,包含所有的子组件,对应于绑定数组。如果 v-for 用在一个对象上,注册的值将是一个对象,包含所有的子组件,对应于绑定对象。

<comp v-ref:child></comp>
<comp v-ref:some-child></comp>

// 从父组件访问
this.$refs.child
this.$refs.someChild
  • v-el

为 DOM 元素注册一个索引,方便通过所属实例的 $els 访问这个元素。

<span v-el:msg>hello</span>
<span v-el:other-msg>world</span>

this.$els.msg.textContent // -> "hello"
this.$els.otherMsg.textContent // -> "world"

es6 array find()

数组实例的find方法,用于找出第一个符合条件的数组成员。它的参数是一个回调函数,所有数组成员依次执行该回调函数,直到找出第一个返回值为true的成员,然后返回该成员。如果没有符合条件的成员,则返回undefined。

[1, 4, -5, 10].find((n) => n < 0)
// -5
[1, 5, 10, 15].find(function(value, index, arr) {
  return value > 9;
}) // 10

上面代码中,find方法的回调函数可以接受三个参数,依次为当前的值、当前的位置和原数组。

数组实例的findIndex方法的用法与find方法非常类似,返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1。

[1, 5, 10, 15].findIndex(function(value, index, arr) {
  return value > 9;
}) // 2

这两个方法都可以接受第二个参数,用来绑定回调函数的this对象。

另外,这两个方法都可以发现NaN,弥补了数组的IndexOf方法的不足。

[NaN].indexOf(NaN)
// -1

[NaN].findIndex(y => Object.is(NaN, y))
// 0

上面代码中,indexOf方法无法识别数组的NaN成员,但是findIndex方法可以借助Object.is方法做到。

webpack 相关

对webpack认识不透彻,反反复复搞来搞去好多遍每次都有新体验,一是对webpack理解不深,二是过一段时间根本就忘光了,再看也只是有印象(就像让我现在再看ionic angular一样),所以打算有时间把用webpack的经验总结一下,每次都有豁然开朗,灵光一闪的地方,再回头看却那么陌生,一定是我当时注释写的不好,再就是没有整体做总结的锅。。。

开坑待填

一个参考
又一个参考

mobile-web 相关

移动web页面弹性滚动

移动端ios fixed属性可能出现问题

参考

在出现滚动条的div上加样式-webkit-overflow-scrolling:touch;,overflow:auto;

iOS Safari应该是需要5.0。Android只在4.0以上支持。

CSS的属性-webkit-overflow-scrolling是真的创建了带有硬件加速的系统级控件,所以效率很高。但是这相对是耗更多内存的,最好在产生了非常大面积的overflow时才应用。


移动端active伪类无效的解决方法

active伪类在PC端的作用为鼠标点击到放开时给元素添加样式用,呈现目标被点击的激活状态.但是直接在移动端这么写会发现没有效果 需要:

document.body.addEventListener('touchstart', function (){}); //...空函数即可

参考

获取数组中的某一项

  • 获取数组中的某一项

    之前在vuex的mutate中经常会写类似这种function

    //
      SOME_MUTATE(state,nowobj){
          for(let obj of state.objlist){
              //在数组中找到当前的项
              if(Object.is(nowproduct,obj)){
                  //someoperation
              }
          }
      }

    之后想到array.indexOf();

    //
      SOME_MUTATE(state,nowobj){
          let index = state.objlist.indexOf(nowobj);
          //在数组中找到当前的项
          state.objlist[index]
      }

    其实在templete中循环渲染时 是可以带出 数组的index的通过使用$index 那么上面的函数则完全可以将nowobj参数替换为index改写成:

    SOME_MUTATE(state,index){
        //在数组中找到当前的项
        state.objlist[index]
    }

    当然以上都是可以取到index的情况(或某一项来获得index),如果只通过某一项的id来获取这一项,还是要通过循环的方式,比如:

      let id = getUrlParam("id");
          for (let item of this.products){
              if(item.id == id){
                  return item;
              }
          }
    • 伪元素 :after等不是dom元素无法绑定事件(随手一记)

vue $mount() $destroy() Object.assign()

  • Object.assign()

    Object.assign({},{test:1},a)其中后面的参数会合并到第一个参数中去,合并过程中如果有相同属性,后面的会覆盖前面的属性值

//控制台中
var a
undefined
Object.assign({},a)
Object {}
var b = Object.assign(a,a)
VM15518:1 Uncaught TypeError: Cannot convert undefined or null to object
  • $mount()

If a Vue instance didn’t receive the el option at instantiation, it will be in “unmounted” state, without an associated DOM element or fragment. vm.$mount() can be used to manually start the mounting/compilation of an unmounted Vue instance.

If no argument is provided, the template will be created as an out-of-document fragment, and you will have to use other DOM instance methods to insert it into the document yourself. If replace option is set to false, then an empty <div> will be automatically created as the wrapper element.

Calling $mount() on an already mounted instance will have no effect. The method returns the instance itself so you can chain other instance methods after it.

如果一个vue实例没有设置el属性那么它将处于一个"unmounted"的状态,没有和dom元素联系在一起,vm.$mount会将实例装载在某个dom上,但直接vm.$mount()调用会将dom中的内容全部替换为vm的内容**//vm.$mount("body")则body中的内容会全被替换),所以一般$mount()方法不填参数//just manually start the mounting/compilation of an unmounted Vue instance**,之后通过dom方法将内容添加到dom中vm.$mount().$appendTo("#domId")

  • $destory()

先了解下$remove()

Remove the Vue instance’s DOM element or fragment from the DOM. This method will trigger transitions if present. The callback is fired after the transition has completed (or immediately if no transition has been triggered).

所以$remove只是将vm实例的内容从dom中移除,而$destory()

Completely destroy a vm. Clean up its connections with other existing vms, unbind all its directives, turn off all event listeners and, if the remove argument is true, remove its associated DOM element or fragment from the DOM.

Triggers the beforeDestroy and destroyed hooks.

$destory则是将vm实例完全销毁,$destory()调用之后vm被销毁了,但dom结构中已添加的渲染了的dom元素**//vm template中的内容**还存在,想要一并移除则添加remove参数为ture即调用$destroy(true)

vue vuex 使用记录

出现警告 [vuex] Action bound to key 'vuex.actions.__esModule' is not a function.

import * as actions from "./actions.js" 导入所有actions中的action,然后

vuex:{
            getters:{
                users:getUsers,
                nowUser:getNowUser
            },
            //所有的actions
            actions

这样页面中总会有个警告 [vuex] Action bound to key 'vuex.actions.__esModule' is not a function.
改成一个一个引入action就好了...import {,,,} from "./actions.js" 可能是把__esModule当成action引入了(虽然不知道为什么会引入它),关于这个警告参考源码和这里

dom js中的scrollWidth clientWidth offsetWidth等

scrollWidth clientWidth offsetWidth

scrollWidth:对象的实际内容的宽度,不包边线宽度,会随对象中内容超过可视区后而变大。
clientWidth:对象内容的可视区的宽度,不包滚动条等边线,会随对象显示大小的变化而改变。
offsetWidth:对象整体的实际宽度,包滚动条等边线,会随对象显示大小的变化而改变。

该demo就在页面中放一个textarea元素,采用默认宽高显示。

情况1:

元素内无内容或者内容不超过可视区,滚动不出现或不可用的情况下。

scrollWidth=clientWidth,两者皆为内容可视区的宽度。

offsetWidth为元素的实际宽度。

各类width

情况2:

元素的内容超过可视区,滚动条出现和可用的情况下。

scrollWidth>clientWidth。

scrollWidth为实际内容的宽度。

clientWidth是内容可视区的宽度。

offsetWidth是元素的实际宽度。

各类width

此外

网页可见区域宽: document.body.clientWidth;

网页可见区域高: document.body.clientHeight;

网页可见区域宽: document.body.offsetWidth (包括边线的宽);

网页可见区域高: document.body.offsetHeight (包括边线的宽);

网页正文全文宽: document.body.scrollWidth;

网页正文全文高: document.body.scrollHeight;

网页被卷去的高: document.body.scrollTop;

网页被卷去的左: document.body.scrollLeft;

网页正文部分上: window.screenTop;

网页正文部分左: window.screenLeft;

屏幕分辨率的高: window.screen.height;

屏幕分辨率的宽: window.screen.width;

屏幕可用工作区高度: window.screen.availHeight;

屏幕可用工作区宽度:window.screen.availWidth;

scrollHeight: 获取对象的滚动高度。

scrollLeft:设置或获取位于对象左边界和窗口中目前可见内容的最左端之间的距离

scrollTop:设置或获取位于对象最顶端和窗口中可见内容的最顶端之间的距离

scrollWidth:获取对象的滚动宽度

offsetHeight:获取对象相对于版面或由父坐标 offsetParent 属性指定的父坐标的高度

offsetLeft:获取对象相对于版面或由 offsetParent 属性指定的父坐标的计算左侧位置

offsetTop:获取对象相对于版面或由 offsetTop 属性指定的父坐标的计算顶端位置

event.clientX 相对文档的水平座标

event.clientY 相对文档的垂直座标

event.offsetX 相对容器的水平坐标

event.offsetY 相对容器的垂直坐标

document.documentElement.scrollTop 垂直方向滚动的值

event.clientX+document.documentElement.scrollTop 相对文档的水平座标+垂直方向滚动的量

  以上主要指IE之中,FireFox差异如下:

IE6.0、FF1.06+:

clientWidth = width + padding

clientHeight = height + padding

offsetWidth = width + padding + border

offsetHeight = height + padding + border

IE5.0/5.5:

clientWidth = width - border

clientHeight = height - border

offsetWidth = width

offsetHeight = height

HTML控件offsetTop、scrollTop等属性

假设 obj 为某个 HTML 控件。

obj.offsetTop 指 obj 距离上方或上层控件的位置,整型,单位像素。

obj.offsetLeft 指 obj 距离左方或上层控件的位置,整型,单位像素。

obj.offsetWidth 指 obj 控件自身的宽度,整型,单位像素。

obj.offsetHeight 指 obj 控件自身的高度,整型,单位像素。


v-ref 子组件索引 从外部js调用挂在子组件上的方法

这里提到过v-ref子组件索引

EMC项目中遇到一种情况,安卓提供的接口回调的函数要在页面index.js中挂载在window上,这时就有这么个需求:从外部js中调用挂载在vue组件上的action方法

...
vuex:{
  actions:{
     //这里的方法会被挂载到相应实例上
  }
}
//index.js中

//vue实例
let vueAddcard = new Vue({
    el:'#emc-app',
    components:{
        addcard
    },
    store
})

//扫二维码返回s
window.showTxtResult = function(s) {
    //通过子组件索引找到子组件addcard
    vueAddcard.$refs.addcard.updateCardByTdcode(s);
}

vue 组件通信

先记录下个 小注意点
click

<div class="pop-btnBox">
    <!-- 此处事件为touched由于和父组件触发按钮太近,若为click的话一瞬间有时会触发click事件 导致popup出现又立刻消失(闪屏)-->
    <input type="button":class='["cancel-btn"]'value="取消"     @touchend="handleClose"/>
</div>

正题

vue中父子组件通信

父子通信

  • props

    默认单向 强制双向用.sync绑定修饰符
    子组件中设置props属性

        //子组件中
        export default{
            props:["items"]
        }
    

    父组件中向子组件标签里动态传值

        <child :items="something"></child>
    
  • Object.assign

    在父组件中 将引入的子组件对象进行合并

    ...
    import {popup} from './components/popup.vue';
    //父组件中
    export default{
        data(){
            return{
                test:1
            }
        },
        methods:{
            handle(){
                let tran_test = this.test;
                let mypopup = Object.assign(popup,{
                    data:{
                        something = tran_test;
                    }
                });
                let vuemypopup = new Vue(mypopup);
                vuemypopup.$on('someevent',(resp)=>{
                    //callback
                });
                vuemypopup.$mount().$append("body");
            }
        }
        ...
    }
    
  • costume event

  • 使用 $on() 监听事件;
  • 使用 $emit() 在它上面触发事件;
  • 使用 $dispatch() 派发事件,事件沿着父链冒泡;
  • 使用 $broadcast()广播事件,事件向下传导给所有的后代。
  • 不同于 DOM事件,Vue事件在冒泡过程中第一次触发回调之后自动停止冒泡,除非回调明确返回 true。

官方示例

<!-- 子组件模板 -->
<template id="child-template">
  <input v-model="msg">
  <button v-on:click="notify">Dispatch Event</button>
</template>

<!-- 父组件模板 -->
<div id="events-example">
  <p>Messages: {{ messages | json }}</p>
  <child></child>
</div>
// 注册子组件
// 将当前消息派发出去
Vue.component('child', {
  template: '#child-template',
  data: function () {
    return { msg: 'hello' }
  },
  methods: {
    notify: function () {
      if (this.msg.trim()) {
        this.$dispatch('child-msg', this.msg)
        this.msg = ''
      }
    }
  }
})

// 初始化父组件
// 将收到消息时将事件推入一个数组
var parent = new Vue({
  el: '#events-example',
  data: {
    messages: []
  },
  // 在创建实例时 `events` 选项简单地调用 `$on`
  events: {
    'child-msg': function (msg) {
      // 事件回调内的 `this` 自动绑定到注册它的实例上
      this.messages.push(msg)
    }
  }
})
  • Vuex store

    state,mutations,actions,getters

    通信组件共用store共享状态

这三种

document.readyState DOMContentLoaded事件 与 load事件

document.readyState
参考
Values

The readyState of a document can be one of following:

  • loading

The document is still loading.

  • interactive

The document has finished loading and the document has been parsed but sub-resources such as images, stylesheets and frames are still loading.

  • complete

The document and all sub-resources have finished loading. The state indicates that the load event has been fired.

When the value of this property changes a readystatechange event fires on the document object.

readystatechange as an alternative to DOMContentLoaded event

// alternative to DOMContentLoaded event
document.onreadystatechange = function () {
  if (document.readyState === "interactive") {
    initApplication();
  }
}

对于DOMContentLoaded事件

来自

事件DOMContentLoaded和load的区别

他们的区别是,触发的时机不一样,先触发DOMContentLoaded事件,后触发load事件。

DOM文档加载的步骤为

  1. 解析HTML结构。
  2. 加载外部脚本和样式表文件。
  3. 解析并执行脚本代码。
  4. DOM树构建完成。//DOMContentLoaded
  5. 加载图片等外部文件。
  6. 页面加载完毕。//load

在第4步,会触发DOMContentLoaded事件。在第6步,触发load事件。
用原生js可以这么写

// 不兼容老的浏览器,兼容写法见[jQuery中ready与load事件](http://www.imooc.com/code/3253),或用jQuery
document.addEventListener("DOMContentLoaded", function() {
   // ...代码...
}, false);

window.addEventListener("load", function() {
    // ...代码...
}, false);

用jQuery这么写

// DOMContentLoaded
$(document).ready(function() {
    // ...代码...
});

//load
$(document).load(function() {
    // ...代码...
});

onunload与onbeforeunload 页面跳转前 事件

onunload,onbeforeunload都是在刷新或关闭时调用,可以在<script>脚本中通过 window.onunload来调用。区别在于onbeforeunload在onunload之前执行,它还可 以阻止onunload的执行。

onbeforeunload 是正要去服务器读 取新的页面时调用,此时还没开始读取;而onunload则已经从服务器上读到了需要加载的新的页面,在即将替换掉当前页面时调用。

项目中跳页面使用到了

window.onbeforeunload = function(){
    showLoading();
};

SVG基本

svg

简单记录 主要还是看链接过来的页面

来自

<svg width="200" height="250">
  <rect x="10" y="10" width="30" height="30" stroke="black" fill="transparent" stroke-width="5"/>
  <rect x="60" y="10" rx="10" ry="10" width="30" height="30" stroke="black" fill="transparent" stroke-width="5"/>

  <circle cx="25" cy="75" r="20" stroke="red" fill="transparent" stroke-width="5"/>
  <ellipse cx="75" cy="75" rx="20" ry="5" stroke="red" fill="transparent" stroke-width="5"/>

  <line x1="10" x2="50" y1="110" y2="150" stroke="orange" fill="transparent" stroke-width="5"/>
  <polyline points="60 110 65 120 70 115 75 130 80 125 85 140 90 135 95 150 100 145"
      stroke="orange" fill="transparent" stroke-width="5"/>

  <polygon points="50 160 55 180 70 180 60 190 65 205 50 195 35 205 40 190 30 180 45 180"
      stroke="green" fill="transparent" stroke-width="5"/>

  <path d="M20,230 Q40,205 50,230 T90,230" fill="none" stroke="blue" stroke-width="5"/>
</svg>
- 矩形 - rect元素

这个元素有6个控制位置和形状的属性,分别是:

x:矩形左上角的坐标(用户坐标系)的x值。

y:矩形左上角的坐标(用户坐标系)的y值。

width:矩形宽度。

height:矩形高度。

rx:实现圆角效果时,圆角沿x轴的半径。

ry:实现圆角效果时,圆角沿y轴的半径。

比如上面例子中,实现了圆角效果,你也可以通过设置rx,ry为不同的值实现椭圆角效果。

  • 圆 - circle元素

    这个元素的属性很简单,主要是定义圆心和半径:

    r:圆的半径。

    cx:圆心坐标x值。

    cy:圆心坐标y值。

  • 椭圆 - ellipse元素
      
    这个是更加通用的圆形元素,你可以分别控制半长轴和半短轴的长度,来实现不同的椭圆,很容易想到,当两个半轴相等时,就是正圆形了。
    rx:半长轴(x半径)。

    ry:半短轴(y半径)。

    cx:圆心坐标x值。

    cy:圆心坐标y值。

  • 直线 - line元素

    直线需要定义起点与终点即可:

    x1:起点x坐标。

    y1:起点y坐标。

    x2:终点x坐标。

    y2:终点y坐标。

  • 折线 - polyline元素
      
    折线主要是要定义每条线段的端点即可,所以只需要一个点的集合作为参数:

    points:一系列的用空格,逗号,换行符等分隔开的点。每个点必须有2个数字:x值和y值。所以下面3个点 (0,0), (1,1)和(2,2)可以写成:"0 0, 1 1, 2 2"。

  • 多边形 - polygon元素

    这个元素就是比polyline元素多做一步,把最后一个点和第一个点连起来,形成闭合图形。参数是一样的。

    points:一系列的用空格,逗号,换行符等分隔开的点。每个点必须有2个数字:x值和y值。所以下面3个点 (0,0), (1,1)和(2,2)可以写成:"0 0, 1 1, 2 2"。

  • 路径 - path元素
      
    这个是最通用,最强力的元素了;使用这个元素你可以实现任何其他的图形,不仅包括上面这些基本形状,也可以实现像贝塞尔曲线那样的复杂形状;此外,使用path可以实现平滑的过渡线段,虽然也可以使用polyline来实现这种效果,但是需要提供的点很多,而且放大了效果也不好。这个元素控制位置和形状的只有一个参数:

    d:一系列绘制指令和绘制参数(点)组合成。

  绘制指令分为绝对坐标指令和相对坐标指令两种,这两种指令使用的字母是一样的,就是大小写不一样,绝对指令使用大写字母,坐标也是绝对坐标;相对指令使用对应的小写字母,点的坐标表示的都是偏移量。
svg

vue 排序 与 filter

vue 排序 与 filter

总不由自主的将 排序 orderBy过滤器 filter搞混

排序是 |管道符 + orderBy关键字 +排序字段 或 排序函数 与 参数 等等

限制: 指令的值须是数组,如 v-for

例如

<div id="orderby-example">
  <button @click="order = order * -1">Reverse Sort Order</button>
  <ul>
    <li v-for="user in users | orderBy 'name' order">
      {{ user.name }}
    </li>
  </ul>
</div>
new Vue({
  el: '#orderby-example',
  data: {
    order: 1,
    users: [{ name: 'Bruce' }, { name: 'Chuck' }, { name: 'Jackie' }]
  }
})

而对于过滤有两种

  • filterBy 关键字

    参考

  • Vue.filter() 自定义过滤器

    类似于自定义指令,可以用全局方法 Vue.filter() 注册一个自定义过滤器,它接收两个参数:过滤器 ID 和过滤器函数。过滤器函数以值为参数,返回转换后的值:

Vue.filter('reverse', function (value) {
  return value.split('').reverse().join('')
})
<!-- 'abc' => 'cba' -->
<span v-text="message | reverse"></span>

sass 的 @import 与 生成文件

Sass 扩展了 CSS 的 @import 规则,让它能够引入 SCSS 和 Sass 文件。 所有引入的 SCSS 和 Sass 文件都会被合并并输出一个单一的 CSS 文件。 另外,被导入的文件中所定义的变量或 mixins 都可以在主文件中使用。
Sass 会在当前目录下寻找其他 Sass 文件, 如果是 Rack、Rails 或 Merb 环境中则是 Sass 文件目录。 也可以通过 :load_paths 选项 或者在命令行中使用 --load-path 选项来指定额外的搜索目录。
@import 根据文件名引入。 默认情况下,它会寻找 Sass 文件并直接引入, 但是,在少数几种情况下,它会被编译成 CSS 的 @import 规则:
如果文件的扩展名是 .css。
如果文件名以 http:// 开头。
如果文件名是 url()。
如果 @import包含了任何媒体查询(media queries)。
如果上述情况都没有出现,并且扩展名是 .scss 或 .sass, 该名称的 Sass 或 SCSS 文件就会被引入。 如果没有扩展名, Sass 将试着找出具有 .scss 或 .sass 扩展名的同名文件并将其引入。

如果你有一个 SCSS 或 Sass 文件需要引入, 但是你又不希望它被编译为一个 CSS 文件, 这时,你就可以在文件名前面加一个下划线,就能避免被编译。 这将告诉 Sass 不要把它编译成 CSS 文件。 然后,你就可以像往常一样引入这个文件了,而且还可以省略掉文件名前面的下划线。
例如,你有一个文件叫做 _colors.scss。 这样就不会生成 _colors.css 文件了, 而且你还可以这样做
@import "colors";
来引入 _colors.scss 文件。
注意,在同一个目录不能同时存在带下划线和不带下划线的同名文件。 例如, _colors.scss 不能与 colors.scss 并存。

即带有下划线开头的文件(片段)不会生成单独的css文件,会通过其他文件的引用,生成一个大的样式文件在项目中img
这里便只会生成一个app.css

其中如__public.scss_sasspng虽然本文件中没@import相应含有buttonmixin的文件,但之前是有引用**_variables.scss_mixins.scss**的,如果针对于_public.scss要单独生成css文件的话这里会报错: 没定义 相应的 mixin

此外scss定义的变量和定义mixin 是不会生成具体的样式的 , 只有当被引用,被使用时才会在相应的css中生成具体的样式,「而无需引用的,或通过逻辑可编译的,或/**/注释」 则会生成出css代码

ES6

  • 打算把使用es6遇到的问题都记录在这里,好好总结下

箭头函数中 (参数) => {函数体} 如果=>后面没有{}的话 就直接是返回值 相当于return ,有{}就是函数体了不会自带return功能啦

简单的表单验证

  • class 类相当于实例的原型,所有在类中定义的方法,都会被实例继承。如果在一个方法前,加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”。

贴一个内部写的简单验证js

import {$, isEmpty} from './tools'

/**
 * 表单验证方法
 */
export default class Valid {
    //需要加的属性,值为"false"或false时才无效
    static attr = {
        //必填
        required: "required",
        //最小长度
        minlength: "minlength",
        //正则匹配
        pattern: "pattern"
    };

    //正则匹配
    static regexps = {
        //url
        url: /^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/,
        //邮箱
        email: /^([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+@([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+\.(?:com|cn)$/,
        //时分秒
        timeString: /^(2[0-3]|[01]?[0-9]):([0-5]?[0-9]):([0-5]?[0-9])$/,
        //日期
        dateString: /^(1[0-2]|0?[1-9])\/(3[01]|[12][0-9]|0?[1-9])\/(?:[0-9]{2})?[0-9]{2}$/,
        //手机号码
        mobile: /^1[3|4|5|7|8]\d{9}$/,
        //座机号码
        phone: /\d{3}-\d{8}|\d{4}-\d{7}/,
        //密码(字母开头,6-16字节,允许字母数字下划线)
        password: /^[a-zA-Z][a-zA-Z0-9_]{5,15}$/,
        //整数
        number: /^-?[0-9]\d*$/
    };
    //是否含有属性
    static hasAttr(dom, attr) {
        let str = dom.getAttribute(attr);
        return typeof str != "undefined" && str != "false" && str !== null;
    }

    //显示警告信息,symbol只是用来区分不同的警告信息显示隐藏
    static showWarn(text, dom, symbol) {
        let [offset,width,height] = [dom.getBoundingClientRect(), dom.offsetWidth, dom.offsetHeight];
        for (let item of [...$(`.warnMsg`)]) {
            if (item.getAttribute('class').indexOf(symbol) == -1) {
                document.body.removeChild(item);
            }
        }
        let class_old = dom.getAttribute("class");
        //没有class属性会返回null,需判断
        class_old = class_old ? class_old.replace(/(^\s*)|(\s*$)/g, '') : '';
        if (!isEmpty(class_old) && class_old.indexOf('error') != -1) {
            class_old = class_old.replace('error', '');
        }
        dom.setAttribute("class", `error ${class_old}`);
        var warnNode = document.createElement("span");
        warnNode.setAttribute("class", `warnMsg warnMsg-${symbol}`);
        warnNode.innerText = text;
        document.body.insertBefore(warnNode, document.body.firstChild);
        let warnHeight = warnNode.offsetHeight;
        warnNode.style.top = (offset.top + document.body.scrollTop - warnHeight) + "px";
        warnNode.style.left = (offset.left + width - warnNode.offsetWidth) + "px";
        warnNode.style.opacity = 1;
        document.body.scrollTop = offset.top + document.body.scrollTop - warnHeight;
        let timer = setTimeout(function () {
            clearTimeout(timer);
            for (let item of [...$(`.warnMsg-${symbol}`)]) {
                warnNode.style.opacity = 0;
                document.body.removeChild(warnNode);
                //dom.setAttribute("class",class_old);
                //dom.focus();
            }
        }, 2000);
    }

    //验证通过去掉错误样式
    static removeWarn(event) {
        let _this = event.target;
        let boo = Valid.validInput(_this);
        //_this.removeEventListener('input');
        if (boo) {
            let class_this = _this.getAttribute("class");
            class_this = class_this ? class_this.replace(/(^\s*)|(\s*$)/g, '') : '';
            if (!isEmpty(class_this) && class_this.indexOf('error') != -1) {
                class_this = class_this.replace('error', '');
            }
            _this.setAttribute("class", class_this);
        }
    }

    //必填
    static validRequired(text, dom) {
        let boo = isEmpty(dom.value);
        boo && Valid.showWarn(text, dom, "required");
        return boo;
    }

    //最小长度
    static validMinLength(text, min, dom) {
        let boo = dom.value.length < Number(min);
        boo && Valid.showWarn(text, dom, "minLength");
        return boo;
    }

    //正则
    static validPattern(text, reg, dom) {
        let value = dom.value;
        let regExp = new RegExp(reg);
        let boo = !regExp.test(value);
        boo ? Valid.showWarn(text, dom, "pattern") : null;
        return boo;
    }

    /**
     * 单个input校验,不通过返回false
     * @param dom
     * @returns {boolean}
     */
    static validInput(dom) {
        if (Valid.hasAttr(dom, Valid.attr.required)) {
            let boo = Valid.validRequired("必填", dom);
            if (boo) {
                return false;
            }
        }
        if (Valid.hasAttr(dom, Valid.attr.minlength)) {
            let minlength = dom.getAttribute(Valid.attr.minlength);
            let boo = Valid.validMinLength(`至少${minlength}位`, minlength, dom);
            if (boo) {
                return false;
            }
        }
        if (Valid.hasAttr(dom, Valid.attr.pattern)) {
            let reg = dom.getAttribute(Valid.attr.pattern);
            let boo = Valid.validPattern(`格式不匹配`, reg, dom);
            if (boo) {
                return false;
            }
        }
        if (dom.getAttribute("type") == "email") {
            let boo = Valid.validPattern(`必须为email地址`, Valid.regexps.email, dom);
            if (boo) {
                return false;
            }
        }
        if (dom.getAttribute("type") == "tel" && dom.getAttribute("mobile")) {
            let boo = Valid.validPattern(`必须为手机号码`, Valid.regexps.mobile, dom);
            if (boo) {
                return false;
            }
        }
        if (dom.getAttribute("type") == "tel" && dom.getAttribute("phone")) {
            let boo = Valid.validPattern(`必须为电话号码`, Valid.regexps.phone, dom);
            if (boo) {
                return false;
            }
        }
        if (dom.getAttribute("type") == "tel") {
            let boo = Valid.validPattern(`必须为电话号码`, Valid.regexps.mobile, dom) && Valid.validPattern(`必须为电话号码`, Valid.regexps.phone, dom);
            if (boo) {
                return false;
            }
        }
        if (dom.getAttribute("type") == "number") {
            let boo = Valid.validPattern(`必须为数字`, Valid.regexps.number, dom);
            if (boo) {
                return false;
            }
        }
        return true;
    }

    /**
     * 表单校验,不通过返回false
     * @param dom
     * @returns {Promise}
     */
    static validForm(dom) {
        let boo = true;
        let iptDom = dom.getElementsByTagName("input");
        let textDom = dom.getElementsByTagName("textarea");
        let selectDom = dom.getElementsByTagName("select");
        for (let item of [...iptDom, ...textDom]) {
            //添加事件监听   监听oninput  调用Valid.removeWarn方法
            item.addEventListener('input', Valid.removeWarn, false);
            boo = Valid.validInput(item);
            if (!boo) {
                break;
            }
        }
        //select验证, value小于0不通过(根据实际情况修改)
        if (boo) {
            for (let sel of [...selectDom]) {
                if (Valid.hasAttr(sel, Valid.attr.required)) {
                    sel.addEventListener('change', function (event) {
                        let _this = event.target;
                        let value = Number(_this.value);
                        if (value >= 0 || isNaN(value)) {
                            let class_this = _this.getAttribute("class");
                            if (!isEmpty(class_this) && class_this.indexOf('error') != -1) {
                                class_this = class_this.replace('error', '');
                            }
                            _this.setAttribute("class", class_this);
                        }
                    }, false);
                    let val = Number(sel.value);
                    boo = val >= 0 || isNaN(val);
                    if (!boo) {
                        Valid.showWarn("必选", sel, "select");
                        break;
                    }
                }
            }
        }
        return new Promise((resolve, reject) => {
            resolve(boo);
        });
    }
}

px em和rem等

页面中body的默认font-size 一般为16px; 那么 1.4rem = (16 * 1.4 )px

但一般我们使用“1em”等于“10px”来改变默认值“1em=16px”,这样一来,我们设置字体大小相当于“14px”时,只需要将其值设置为“1.4em”。所以需要设置

body {
                font-size: 62.5%;/*10 ÷ 16 × 100% = 62.5%*/ /*font-size设为10px*/
            }

那么在sass中我们可以有如下mixin

//字体大小
@mixin fontSize($size:14){
    font-size:#{$size/10}rem;   /*默认1.4rem = 1.4 *10 px */
}

vuex action 中调用 action

当从一个模块中调用另一个模块的 action 时,或者调用同一模块中的另一个 action 时,切记,action 的第一个参数是 store 实例,因此应该将调用者 action 的第一个参数传递给被调用 action。
如果你使用 ES6 的解构形式来编写 action,确保调用者 action 的第一个参数包含两个 action 中用到的所有属性和方法。举例说明,调用者 action 仅使用 dispatch 方法,而被调用 action 使用了 state 属性和 watch 方法,那么,dispatch、state 和 watch 应该都出现在传递给调用者 action 的第一个形式参数中,示例如下:

import {callee} from './anotherActionModule'

export const caller = ({dispatch, state, watch}) => {
  dispatch('MUTATION_1')
  callee({state, watch})
}
import {reqLocationinfo} from '../../api/api.js';
import {setProductInfo} from '../../../common/vuex/actions.js';


export async function initProductInfo({dispatch,state},id){
    //产品信息 
    await setProductInfo({dispatch,state},id);
    let addressId = state.productInfo.addressId;
    console.log(addressId)
    //地址信息
    let locationinfo = await reqLocationinfo(addressId);
    if(locationinfo){
        dispatch('INIT_LOCATION',locationinfo);
    }
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.