作者: admin

  • less笔记

    使用大概介绍:

    less类似与jquery,用最少的代码来实现效果
    less代码始终都是要编译成css的
    less格式的文件中,我们可以像以前一样去写样式和可以使用less语法去写都行。

     

    注释:
    在less中可以使用//和/**/注释代码,
    使用/**/编译成css会被保留,但是//不会保留在css中

     

    变量:

    @test:100px;
    
    div{
        height:@test;
    }

     

     

     

    混合(可带参数):

    可以理解为定义一个函数,别的地方去调用

    @test:100px;
    
    div{
      height:@test;
     .bor(2px); //div就有了.bor的样式
    }
    
    
    .bor(@w:1px){ //其他地方调用有传参数就用参数没有就用默认值1px
      border:@w solid red;
    }

     

     

    匹配模式:

    .a(red,@f){
       color:red;
       font-size:@f;
    }
    
    
    .a(yellow,@f){
       color:yellow;
       font-size:@f;
    }
    
    .a(@_,@f){ //有了@_表示,不管是哪里调用.a(),里面都会有这些样式
       background:#000;
    }
    
    
    div{
     .a(red,#000) //选择哪个就选择哪个
    }

     

     

    计算:

    @a:10px
    
    div{
      height:@a-1;
    }

     

     

    嵌套:

    ul{
      border:1px solid #000;
      li:{
         float:left;
         a:{
           color:red:
           &:hover{ color:yellow; } //&表示去找父元素
         }
      }
    }
    
    
    编译后:
    ul{border:1px solid #000;}
    ul li{float:left;}
    ul li a{color:red:}
    ul li a:hover{color:yellow;}

     

    获取所有元素:

    @arguments

     

     

    避免less编译

    div{
     width:~'calc(100px-10px)' //less不编译直接输出
    }

     

    编译less的工具很多,例如node.js   webpack   gulp 都有,这里推荐http://koala-app.com/

  • js获取数据及未来取代XMLHttpRequest——fetch对象

    要使用js获取到其他网站提供的数据,我们一般的反应就是使用ajax来实现,其中ajax又是使用的是XMLHttpRequest来实现的,具体来感受下它的代码

    原生ajax笔记

    在封装好之前是不是觉得又点凌乱,在来感受一下原生的fetch对象。

    //从服务器获取数据
    fetch('http://45.32.197.68/a1.php').then(function(res) {
        if (res.ok) {
            res.json().then(function(obj) {
                console.log(obj); //这里是返回的数据
            })
        }
    }, function(ex) {
        console.log('这里是失败后才回调')
    });

     

     

    //发送数据给服务器
    fetch('http://45.32.197.68/a.php', {
     method: 'post',
     headers: {
        "Content-type": "application/x-www-form-urlencoded; charset=UTF-8",  //模拟表单提交数据给服务器
        "userToken": "100131601455909631number2"
     },
     body: JSON.stringify({}),  //要发送给服务器的数据
     referrer: "about:client",
      referrerPolicy: "no-referrer-when-downgrade",
      mode: "cors", 
      credentials: "same-origin",
      cache: "default",
      redirect: "follow",
      integrity: "",
      keepalive: false,
      signal: undefined
    })
     .then(Response =>{
        return Response.json()    //text  json  blob  arrayBuffer
     })
     .then(function (data) {
          console.log('Request succeeded with JSON response', data);  //提交数据成功后的回调
     })
     .catch(function (error) {
          console.log('Request failed', error);   //失败后的回调
     });

     

    1,提交 JSON 数据

    const user = { name: 'John', surname: 'Smith' };
    
    headers: {
       'Content-Type': 'application/json;charset=utf-8'
    }, 
    body: JSON.stringify(user)

     

    2,提交表单

    const form = document.querySelector('form');
    
    const response = await fetch('/users', {
      method: 'POST',
      body: new FormData(form)
    })

     

    3,文件上传以及整个表单

    const input = document.querySelector('input[type="file"]');
    
    const data = new FormData();
    data.append('file', input.files[0]);
    data.append('user', 'foo');
    
    fetch('/avatars', {
     method: 'POST',
     body: data
    });

     

    4,直接上传二进制数据

    let blob = await new Promise(resolve => 
     canvasElem.toBlob(resolve, 'image/png')
    );
    
    let response = await fetch('/article/fetch/post/image', {
     method: 'POST',
     body: blob
    });

     

    其他介绍:

    cache属性指定如何处理缓存。可能的取值如下:

    default:默认值,先在缓存里面寻找匹配的请求。
    no-store:直接请求远程服务器,并且不更新缓存。
    reload:直接请求远程服务器,并且更新缓存。
    no-cache:将服务器资源跟本地缓存进行比较,有新的版本才使用服务器资源,否则使用缓存。
    force-cache:缓存优先,只有不存在缓存的情况下,才请求远程服务器。
    only-if-cached:只检查缓存,如果缓存里面不存在,将返回504错误。

     

    mode属性指定请求的模式。可能的取值如下:

    cors:默认值,允许跨域请求。
    same-origin:只允许同源请求。
    no-cors:请求方法只限于 GET、POST 和 HEAD,并且只能使用有限的几个简单标头,不能添加跨域的复杂标头,相当于提交表单所能发出的请求。

     

    credentials属性指定是否发送 Cookie。可能的取值如下:

    same-origin:默认值,同源请求时发送 Cookie,跨域请求时不发送。
    include:不管同源请求,还是跨域请求,一律发送 Cookie。
    omit:一律不发送。

    跨域请求发送 Cookie,需要将credentials属性设为include。

    fetch('http://another.com', {
     credentials: "include"
    });

     

    signal

    signal属性指定一个 AbortSignal 实例,用于取消fetch()请求

     

    keepalive

    keepalive属性用于页面卸载时,告诉浏览器在后台保持连接,继续发送数据。

    一个典型的场景就是,用户离开网页时,脚本向服务器提交一些用户行为的统计信息。这时,如果不用keepalive属性,数据可能无法发送,因为浏览器已经把页面卸载了。

    window.onunload = function() {
     fetch('/analytics', {
      method: 'POST',
      body: "statistics",
      keepalive: true
     });
    };

     

    redirect属性指定 HTTP 跳转的处理方法。可能的取值如下:

    follow:默认值,fetch()跟随 HTTP 跳转。
    error:如果发生跳转,fetch()就报错。
    manual:fetch()不跟随 HTTP 跳转,但是response.url属性会指向新的 URL,response.redirected属性会变为true,由开发者自己决定后续如何处理跳转。

     

    integrity

    属性指定一个哈希值,用于检查 HTTP 回应传回的数据是否等于这个预先设定的哈希值。

    比如,下载文件时,检查文件的 SHA-256 哈希值是否相符,确保没有被篡改。

    fetch('http://site.com/file', {
     integrity: 'sha256-abcdef'
    });

     

    referrer

    属性用于设定fetch()请求的referer标头。

    这个属性可以为任意字符串,也可以设为空字符串(即不发送referer标头)。

    fetch('/page', {
     referrer: ''
    });

     

    referrerPolicy

    属性用于设定Referer标头的规则。可能的取值如下:

    no-referrer-when-downgrade:默认值,总是发送Referer标头,除非从 HTTPS 页面请求 HTTP 资源时不发送。
    no-referrer:不发送Referer标头。
    origin:Referer标头只包含域名,不包含完整的路径。
    origin-when-cross-origin:同源请求Referer标头包含完整的路径,跨域请求只包含域名。
    same-origin:跨域请求不发送Referer,同源请求发送。
    strict-origin:Referer标头只包含域名,HTTPS 页面请求 HTTP 资源时不发送Referer标头。
    strict-origin-when-cross-origin:同源请求时Referer标头包含完整路径,跨域请求时只包含域名,HTTPS 页面请求 HTTP 资源时不发送该标头。
    unsafe-url:不管什么情况,总是发送Referer标头。

     

    中途取消fetch()请求

    let controller = new AbortController();
    let signal = controller.signal;
    
    fetch(url, {
     signal: controller.signal
    });
    
    signal.addEventListener('abort',
     () => console.log('abort!')
    );
    
    controller.abort(); // 取消
    
    console.log(signal.aborted); // true

    上面示例中,首先新建 AbortController 实例,然后发送fetch()请求,配置对象的signal属性必须指定接收 AbortController 实例发送的信号controller.signal。

    controller.abort()方法用于发出取消信号。这时会触发abort事件,这个事件可以监听,也可以通过controller.signal.aborted属性判断取消信号是否已经发出。

    下面是一个1秒后自动取消请求的例子。

    let controller = new AbortController();
    setTimeout(() => controller.abort(), 1000);
    
    try {
     let response = await fetch('/long-operation', {
     signal: controller.signal
    });
    } catch(err) {
     if (err.name == 'AbortError') {
      console.log('Aborted!');
     } else {
      throw err;
     }
    }

     

    http://www.ruanyifeng.com/blog/2020/12/fetch-tutorial.html

     

    实用案例及上传

    案例demo

     

    其实功能上的差不多,但fetch的优点就是代码简洁,容易维护,但一个缺点就是没有类似XMLhttprequest中的onprogress监听函数,无法显示上传进度监听。

    个人推荐使用reqwest.js插件兼容性都很好,参考:https://sdeno.com/?p=6218

  • 跨域请求兼容ie浏览器——reqwest.js

    js 兼容ie6/7/8跨域 跨域

    一般涉及到跨域时,我们都会使用jquery里面ajax的jsonp,但是遇到ie浏览器就不兼容了。这里推荐使用reqwest.js,对浏览器的兼容性很好支持xmlHttpRequest, JSONP, CORS, 和 CommonJS。

    同时也能在node.j后台和前端上使用

    IE6+
    Chrome 1+
    Safari 3+
    Firefox 1+
    Opera

    具体没测试这么多浏览器,但至少满足了ie8,跨域以及各种常用功能。

     

    跨域

    使用的是jsonp,兼容比较老的浏览器如,ie6/7

    //客服端
    reqwest({
        url: 'https://sdeno.com/a.php'
        , method: 'get'  //jsonp用的就是get方式跨域的,改成post也会默认是get
        ,type: 'jsonp'
        , jsonpCallbackName: 'ni'
    
        , success: function (resp) {
            document.title=JSON.stringify(resp)
        }
    })

     

    //服务器端   a.php
    <?php
     $data='[{name:"chenge"},{age:24}]'; 
     $str='ni('.$data.')';
     echo $str;
    ?>

     

     

    以下使用CORS方法跨域,支持跨域携带cookies,支持全部方式请求,IE8以上浏览器使用new XDomainRequest(),其他浏览器使用new XMLHttpRequest()

    //客户端
    reqwest({
     url: 'http://45.32.197.68/a.php' //可以是接收数据的地址,也可以是要发送给服务器数据的地址
     , type: 'json'
     , method: 'post' 
     , contentType: 'application/json'
     , crossOrigin: true
     , withCredentials: true //cookies跨域要设置true,但是Access-Control-Allow-Origin:的值就不能是*,不然会报错。
     , error: function (err) { }
     , success: function (resp) {
         qwery('#content').html(resp.content)
     }
    })

     

    客户端使用cors来实现跨域,服务器也要设置。

    <?php
    if(isset($_SERVER["HTTP_ORIGIN"])) {
     header('Access-Control-Allow-Origin:'.$_SERVER["HTTP_ORIGIN"]); 
    }
    header('Access-Control-Allow-Methods:OPTIONS, GET, POST');
    header('Access-Control-Allow-Headers:x-requested-with');
    header('Access-Control-Max-Age:86400'); 
    header('Access-Control-Allow-Origin:'.$_SERVER['HTTP_ORIGIN']);
    header('Access-Control-Allow-Credentials:true');
    header('Access-Control-Allow-Methods:GET, POST, PUT, DELETE, OPTIONS');
    header('Access-Control-Allow-Headers:x-requested-with,content-type');
    header('Access-Control-Allow-Headers:Origin, No-Cache, X-Requested-With, If-Modified-Since, Pragma, Last-Modified, Cache-Control, Expires, Content-Type, X-E4M-With');
    
    $data='[{"name":"chenge"},{"age":"24"}]'; 
    echo $data;
    ?>

    关于:cors跨域请求的服务器配置参考地址:http://www.jianshu.com/p/552daaf2869c

     

     

    post/get方式提交数据给服务器

    //post提交数据
    reqwest({
        url: 'path/to/html'  //服务器接收数据地址 
      , type: 'json'  //将数据以json格式发给服务器
      , method: 'post'
      , data: { foo: 'bar', baz: 100 } //要发给服务器的数据
      , success: function (resp) {
          qwery('#content').html(resp)
        }
    })
    
    
    //get提交数据
    reqwest({
        url: 'path/to/html'
      , type: 'json'
      , method: 'get'
      , data: [ { name: 'foo', value: 'bar' }, { name: 'baz', value: 100 } ]  //http://localhost:3001/xxx1?foo=bar&baz=100
             //或者{ foo: 'bar', baz: 100 }
      , success: function (resp) {
          qwery('#content').html(resp)
        }
    })

     

     

    回调

    reqwest.({})
     .then(function (resp) {  //成功回调
        qwery('#content').html(resp.content)
     })
     .fail(function (err, msg) {  //失败回调
        qwery('#errors').html(msg)
     })
     .always(function (resp) {  //总是回调
        qwery('#hide-this').hide()
     })

     

     

    对IE6/7的兼容

    <script>
    (function () {
      if (!window.JSON) {
        document.write('<scr' + 'ipt src="http://cdnjs.cloudflare.com/ajax/libs/json3/3.3.2/json3.min.js"><\/scr' + 'ipt>')
      }
    }());
    </script>

    reqwest.min

    参考:http://www.ruanyifeng.com/blog/2016/04/cors.html

    https://www.npmjs.com/package/reqwest

  • js视频播放器——video.js

    js 手机 视频 js 兼容

    视频播放器在不支持video标签就自动使用flash,达到兼容ie8效果:

    http://videojs.com/getting-started/

    https://sdeno.com/wp-content/uploads/2020/02/videojs.zip

     

    自适应

    var player = videojs('video', { fluid: true }, function () {   //id="video"
     console.log('Good to go!');
     this.play(); // if you don't trust autoplay for some reason 
    })

     

    开始,暂停,结束

    <video  id="example_video_1" class="video-js vjs-big-play-centered vjs-default-skin" controls preload="none" data-setup="{}">
    
    </video>
    var player = videojs('video', {
             width:1000,//宽string|number
             height:450,//高:string|number
             controls:true,//控制条:boolean
             preload:"none",//预加载:string;'auto'|'true'|'metadata'|'none'
             poster:'source/suoluetu.jpg',//预览图:string
             autoplay:false,//自动播放:boolean
             loop:true,//循环:boolean
             muted:true,//静音:boolean
             sources:[
                 {
                     src:'source/test.mp4',
                     type:'video/mp4'
                 }
             ],
             controlBar: {
                 muteToggle: false,
                 volumeMenuButton:false//静音按钮
             }
     }, function () {
       console.log('Good to go!');
       //this.play(); // if you don't trust autoplay for some reason
       player.src('http://www.xx.com/1.mp4');  //动态加载视频
       this.on('ended',function(){
            //播放结束后回调
       });
     });
     player.on('play', function () {
     console.log('开始/恢复播放');
     });
     player.on('pause', function () {
     console.log('暂停播放');
     });
     player.on('ended', function () {
     console.log('结束播放');
     });

     

     

    更新事件

    player.on('timeupdate', function() {
     console.log(player.currentTime());
    });

     

     

    判断当前时间和总时间是否相等来判断视频是否结束:

    player.on('timeupdate', function () { 
     // 如果 currentTime() === duration(),则视频已播放完毕
     if (player.duration() != 0 && player.currentTime() === player.duration()) {
     // 播放结束
     }
    });

     

     

    iis MIME视频格式设置:

    默认的iis MIME设置是没有增加mp4类型的,会出现本地播放没有问题,但是到了服务器上就出404错误。这需要在iis中设置MIME:

     

     

    常见视频格式:

    flv格式是加入关联扩展名:.flv,内容类型:application/octet-stream
    f4v格式是扩展名:.f4v,内容类型:application/octet-stream
    mp4格式是扩展名:.mp4,内容类型:video/mp4
    ogv格式是扩展名:.ogv ,内容类型:video/ogg
    webm格式是扩展名:.webm,内容类型:video/webm
    设置完重启iis才能生效。

     

     

    设置默认使用html5还是flash技术优先级:

    video.js默认会使用html5技术优先,但我们可以设置为flash优先,如:

    <video data-setup='{"techOrder": ["flash", "html5", "other supported tech"]}'

    或者

    videojs("videoID", {
     techOrder: ["flash", "html5", "other supported tech"]
    });

     

     

    自动播放:

    <video id="video" autoplay> </video>

    或者

    var player = videojs('video', { autoplay:true }, function () {
     console.log('Good to go!');
     //this.play(); // 保险你还可以主动调用play()
    });

     

     

    添加自定义方法:

    //定义一个插件
            function examplePlugin(options) {
                this.on('play', function (e) {
                    console.log('playback has started!');
                });
            }
    
            //注册
            videojs.plugin('examplePlugin', examplePlugin);
            // 使用
            player.examplePlugin({ exampleOption: true });

     

    插件内部可以直接调用播放器的api。 有一款playlist的插件可以研究下,如过你需要播放列表。https://github.com/brightcove/videojs-playlist 以及 http://videojs.com/advanced/ 有这样的效果:

     

     

    官方文档:

    http://docs.videojs.com/docs

    参考博客:

    http://www.tuicool.com/articles/7jYvQrR

    http://blog.videojs.com/Video-js-5-s-fluid-mode-and-playlist-picker/

    Creating Intrinsic Ratios for Video

     

    https://pan.baidu.com/s/1gfQuN0f

  • 类数组(伪数组)转数组

    如果使用:

    document.getElementsByTagName('div')  //getElementsByName()同样也是返回nodelist类数组对象

    获取到div元素返回来的就是类数组

    类数组我们不方便操作,由于它不是数组我们就不能使用数组下的属性去操作它,所以必须转化为数组。

     

    证明:

    document.getElementsByTagName('div') instanceof Array   //返回false,说明就不是数组

     

    转化成数组使用以下方法:

    let arr1 = Array.prototype.slice.call(arrayLike);  //最低兼容ie9
    let arr2 = [].slice.call(arrayLike); //最低兼容ie9
    let arr3 = Array.from(arrayLike);  //兼容性不太好

     

    兼容模式:

    function realArray(c) {
        try {
            return Array.prototype.slice.call(c);
        } catch (e) {
            var ret = [], i = 0, len = c.length;
            for (; i < len; i++) {
                ret[i] = (c[i]);
            }
            return ret;
        }
    }