Giter Site home page Giter Site logo

learn-blog's People

Contributors

ivan135 avatar

Watchers

 avatar

learn-blog's Issues

websocket在vue的应用

项目的需求

在项目需要在局域网中,电脑网页和电话实时连接,当收到订单时,网页会有提示

选择websocket的原因

假如使用setInterval轮询接口,需要客户端定时向服务器发送ajax请求,服务器接到请求后返回响应信息。这就需要大量的占据服务器资源。同时在HTTP1.x协议中也存在一些比如线头阻塞、头部冗余等问题

而使用websocket的话,建立在 TCP 协议之上,数据格式比较轻量,性能开销小,通信高效,可以发送文本,也可以发送二进制数据。同时它还没有同源限制,客户端可以与任意服务器通信。

websocket使用心跳重连

在某些场景下使用websocket的时候,如果设备网络断开,不会立刻触发websocket的任何事件,前端也就无法得知当前连接是否已经断开。这个时候如果调用websocket.send方法,浏览器才会发现链接断开了,便会立刻或者一定短时间后,触发onclose函数。

后端websocket服务也可能出现异常,造成连接断开,这时前端也并没有收到断开通知,因此需要前端定时发送心跳消息ping,后端收到ping类型的消息,立马返回pong消息,告知前端连接正常。如果一定时间没收到pong消息,就说明连接不正常,前端便会执行重连。

为了解决以上两个问题,以前端作为主动方,定时发送ping消息,用于检测网络和前后端连接问题。一旦发现异常,前端持续执行重连逻辑,直到重连成功。

代码实现

export default {
  data() {
    return {
      websock: null,//建立的连接
      lockReconnect: false,//是否真正建立连接
      timeout: 30*1000,//30秒一次心跳
      timeoutObj: null,//心跳心跳倒计时
      serverTimeoutObj: null,//心跳倒计时
      timeoutnum: null,//断开 重连倒计时
    };
  },
  created() {
    //页面刚进入时初始化长连接
    this.initWebSocket();
  },
  destroyed: function() {
    //页面销毁时关闭长连接
    this.websocketclose();
  },
  methods: {
    initWebSocket(){//建立连接
      //初始化weosocket
      //const wsuri = "ws://sms.填写您的地址.com/websocket/" //ws地址
      const wsuri = ""
      //建立连接
      this.websock = new WebSocket(wsuri);
      //连接成功
      this.websock.onopen = this.websocketonopen;
      //连接错误
      this.websock.onerror = this.websocketonerror;
      //接收信息
      this.websock.onmessage = this.websocketonmessage;
      //连接关闭
      this.websock.onclose = this.websocketclose;
    },
    reconnect() {//重新连接
      var that = this;
      if(that.lockReconnect) {
        return;
      };
      that.lockReconnect = true;
      //没连接上会一直重连,设置延迟避免请求过多
      that.timeoutnum && clearTimeout(that.timeoutnum);
      that.timeoutnum = setTimeout(function () {
        //新连接
        that.initWebSocket();
        that.lockReconnect = false;
      },5000);
    },
    heartCheckReset(){//重置心跳
      var that = this;
      //清除时间
      clearTimeout(that.timeoutObj);
      clearTimeout(that.serverTimeoutObj);
      //重启心跳
      that.heartCheckStart();
    },
    heartCheckStart(){//开启心跳
      var self = this;
      self.timeoutObj && clearTimeout(self.timeoutObj);
      self.serverTimeoutObj && clearTimeout(self.serverTimeoutObj);
      self.timeoutObj = setTimeout(function(){
        //这里发送一个心跳,后端收到后,返回一个心跳消息,
        if (self.websock.readyState == 1) {//如果连接正常
          self.websock.send("heartCheck");
        }else{//否则重连
          self.reconnect();
        }
        self.serverTimeoutObj = setTimeout(function() {
          //超时关闭
          self.websock.close();
        }, self.timeout);

      }, self.timeout)
    },
    websocketonopen() {//连接成功事件
      //提示成功
      s.success("连接成功",3)
      //开启心跳
      this.heartCheckStart();
    },

    websocketonerror(e) {//连接失败事件
      //错误
      console.log("WebSocket连接发生错误");
      //错误提示
      s.error("Websocket error, Check you internet!")
      //重连
      this.reconnect();
    },
    websocketclose(e) {//连接关闭事件
      //关闭
      console.log("connection closed (" + e.code + ")");
      //提示关闭
      s.error("连接已关闭",3);
      //重连
      this.reconnect();
    },
    websocketonmessage(event) {//接收服务器推送的信息
      //打印收到服务器的内容
      console.log(event.data);
      //收到服务器信息,心跳重置
      this.heartCheckReset();
    },
    websocketsend(msg) {//向服务器发送信息
      //数据发送
      this.websock.send(msg);
    },
  }
};

vue点滴

vue自定义指令

  • 它是用来操作DOM的,所以所有Vue指令都会挂在template里的某个元素上
  • 它有4个钩子函数,一是bind,它在指令第一次绑定到元素上调用而且只调用一次,这个钩子很重要,我们在这个例子里会用到;第二个是inserted,它在元素插入到父元素的时候调用,官方文档里给了一个v-focus的例子就用到了它;第三个和第四个分别是update和componentUpdated,前者是在vNode更新时调用,后者是在更新完成后调用;最后是unbind,在指令和元素解绑时调用。
  • 这4个钩子函数可以都至少可以传3个参数,第一是el就是被绑定指令的元素,第二个binding,它是个对象,而且它的一些属性特别有用,它的属性包括name,expression和value等,当然不只这三个,但是我们这个例子要用。举个例子: 假如我写一个自定义指令v-test="test",而这个test是我在methods里写的一个方法,那么就可以通过binding.name拿到test字符串,可以通过binding.value拿到test函数本身并且执行

Vue自定义指令的应用

1.需求场景

在pc端的select组件和自定义的日历组件香相结合的场景,点击select组件,显示日历组件,点击select组件外的元素,日历组件会隐藏。
参考了iview的select组件的实现方式,可以用自定义指令来实现。

#2.代码实现

//outside.js

export default {
  // 初始化指令
  bind(el, binding, vnode) {
    function clickHandler(e) {
      // 这里判断点击的元素是否是本身,是本身,则返回
      if (el.contains(e.target)) {
        return false;
      }
      // 判断指令中是否绑定了函数
      if (binding.expression) {
        // 如果绑定了函数 则调用那个函数,此处binding.value就是handleClose方法
        binding.value(e);
      }
    }
    // 给当前元素绑定个私有变量,方便在unbind中可以解除事件监听
    el.__vueClickOutside__ = clickHandler;
    document.addEventListener('click', clickHandler);
  },
  update() {},
  unbind(el, binding) {
    // 解除事件监听
    document.removeEventListener('click', el.__vueClickOutside__);
    delete el.__vueClickOutside__;
  },
};

大屏页面

分析DataV

DadaV地址

  • 使用 MutationObserver 追踪 DOM 的变化和节流防抖来检测窗口的变化

MutationObserver 的使用

创建一个MutationObserver对象,这个对象有三个方法:

  • observe — 开始监听变化。需要两个参数 - 你需要观察的 DOM 和一个设置对象
  • disconnect — 停止监听变化
  • takeRecords — 在回调函数调用之前,返回最后一个批次的变化。
var mutationObserver = new MutationObserver(function(mutations) {
  mutations.forEach(function(mutation) {
    console.log(mutation);
  });
});

// 开始监听页面中根 HTML 元素中的变化。
mutationObserver.observe(document.documentElement, {
  attributes: true,
  characterData: true,
  childList: true,
  subtree: true,
  attributeOldValue: true,
  characterDataOldValue: true
});

现在,假设在 DOM 中你有一些非常简单的 div :

<div id="sample-div" class="test"> Simple div </div>
复制代码使用 jQuery,你可以移除这个 div 的 class 属性:

$("#sample-div").removeAttr("class");

当我们开始观察,在调用 mutationObserver.observe(...) 之后我们将会在控制台看到每个 MutationRecord 的日志:
image

这个是由移除 class 属性导致的变化。

最后,为了在任务结束后停止对 DOM 的观察,你可以这样做:

// 停止 MutationObserver 对变化的监听。
mutationObserver.disconnect();

分析的源码:
https://github.com/DataV-Team/DataV/blob/bfc7cc7c574bedecaf7a7aa2b322e01c471a3b77/src/util/index.js
https://github.com/DataV-Team/DataV/blob/72433f8ff127c387d91b56c75988c6ceb61f68a9/src/mixin/autoResize.js

flex实现四个子元素分布在四个边缘

   <div class="container">
     <header>   <div class="item"></div>
   <div class="item"></div></header>
     <main>内容</main>
     <footer>  <div class="item"></div>
   <div class="item"></div></footer>
   </div>
.item{
    /* flex: 0 0 40%; */
    width: 100px;
    height: 80px;
    box-sizing: border-box;
    border: 1px solid red
}

header{
  height:100px;
  background:#ccc;
  display: flex;
  justify-content: space-between;
}


footer{
  height:100px;
  background:#ccc;
   display: flex;
   justify-content: space-between;
  align-items: flex-end;
}
.container{
  display:flex;
  flex-direction:column;
  height:100vh;
}
main{
  flex-grow:1;
}

css中的居中

1.单行垂直居中

如果一个容器中只有一行文字,对它实现居中相对比较简单,我们只需要设置它的实际高度height和所在行的高度line-height相等即可
若文字长度超出盒子的宽度,可以使用overflow:hidden隐藏超出的宽度

2. (未知高度)多行文本垂直居中

  • 设置上下的padding值一样即可并,若是宽度可以拉伸,就无法水平居中如:

div{
     padding:25px; 
} 

3. (未知高度)多行文本垂直水平居中

  • Flex布局

缺点:子元素的float、clear和vertical-align属性将失效,有兼容性问题(兼容到IE11+)
只需要在父盒子设置:display: flex; justify-content:(平行方向) center;align-items: center(垂直方向); 就可以达到垂直水平居中

  • relative+absolute+transform 水平垂直居中

<div class="parent">
  <div class="child">Demo</div>
</div>

<style>
  .parent {
    position: relative;
  }
  .child {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
  }
</style>

说明left和top相对父元素,transform是对自身的影响
兼容性较好,用于轮播图的圆点

  • relative+absolute + 负 margin

.parent{
    position:relative;
}
.child{
     width: 100px;
     height: 100px;
     position: absolute;
     top: 50%;
     left: 50%;
     margin: -50px 0 0 -50px;
}

缺点:需要确定子元素宽高

  • 绝对定位方式+四个方向置0

子元素可以是块级元素也可以是行内元素,没有影响

.parent{
    position:relative
}
.child{
    margin:auto;
    height: 100px;
    width: 100px;
    position: absolute;
    top: 0; left: 0; bottom: 0; right: 0;
}

缺点:同样是需要确定子元素宽高
说明绝对居中(AbsoluteCentering)的工作机理可以阐述如下:
1、在普通内容流(normal content flow)中,margin:auto的效果等同于margin-top:0;margin-bottom:0。
2、position:absolute使绝对定位块跳出了内容流,内容流中的其余部分渲染时绝对定位部分不进行渲染。
3、为块区域设置top: 0; left: 0; bottom: 0; right: 0;将给浏览器重新分配一个边界框,此时该块block将填充其父元素的所有可用空间,父元素一般为body或者声明为position:relative;的容器。
4、 给内容块设置一个高度height或宽度width,能够防止内容块占据所有的可用空间,促使浏览器根据新的边界框重新计算margin:auto
5、由于内容块被绝对定位,脱离了正常的内容流,浏览器会给margin-top,margin-bottom相同的值,使元素块在先前定义的边界内居中。
这么看来, margin:auto似乎生来就是为绝对居中(Absolute Centering)设计的,所以绝对居中(Absolute Centering)应该都兼容符合标准的现代浏览器。

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.