zoukankan      html  css  js  c++  java
  • webpack学习:uni运行时代码解读二 (页面的交互)

    页面点击触发vm(vue实例)的方法

    uni里的vue代码

    <template>
            <view
                    class="content"
                    @click="qq"
                    @longpress='fq'
            >
                    3345
            </view>
    </template>
    

    经过uni转换后的小程序wxml代码

    <view data-event-opts="{{[['tap',[['qq',['$event']]]],['longpress',[['fq',['$event']]]]]}}"
     class="content" bindtap="__e" bindlongpress="__e">3345</view>
    

    微信的小程序实例methods里只有2个方法(上文有写),__l是用来关联vm的父子关系的,__e是用来和data-event-opts属性一起使用,关联vm与小程序事件的。__e的代码如下,
    写的挺长,其实不看无所谓,你看上文data-event-opts属性的内容就大概知道uni是怎么让小程序的页面交互触发到vm的方法里去了

    function handleEvent (event) {
      event = wrapper$1(event);
      // [['tap',[['handle',[1,2,a]],['handle1',[1,2,a]]]]]
      const dataset = (event.currentTarget || event.target).dataset;
      if (!dataset) {
        return console.warn('事件信息不存在')
      }
      const eventOpts = dataset.eventOpts || dataset['event-opts']; // 支付宝 web-view 组件 dataset 非驼峰
      if (!eventOpts) {
        return console.warn('事件信息不存在')
      }
    
      // [['handle',[1,2,a]],['handle1',[1,2,a]]]
      const eventType = event.type;
    
      const ret = [];
    
      eventOpts.forEach(eventOpt => {
        let type = eventOpt[0];
        const eventsArray = eventOpt[1];
    
        const isCustom = type.charAt(0) === CUSTOM;
        type = isCustom ? type.slice(1) : type;
        const isOnce = type.charAt(0) === ONCE;
        type = isOnce ? type.slice(1) : type;
    
        if (eventsArray && isMatchEventType(eventType, type)) {
          eventsArray.forEach(eventArray => {
            const methodName = eventArray[0];
            if (methodName) {
              let handlerCtx = this.$vm;
              if (handlerCtx.$options.generic) { // mp-weixin,mp-toutiao 抽象节点模拟 scoped slots
                handlerCtx = getContextVm(handlerCtx) || handlerCtx;
              }
              if (methodName === '$emit') {
                handlerCtx.$emit.apply(handlerCtx,
                  processEventArgs(
                    this.$vm,
                    event,
                    eventArray[1],
                    eventArray[2],
                    isCustom,
                    methodName
                  ));
                return
              }
              const handler = handlerCtx[methodName];
              if (!isFn(handler)) {
                throw new Error(` _vm.${methodName} is not a function`)
              }
              if (isOnce) {
                if (handler.once) {
                  return
                }
                handler.once = true;
              }
              let params = processEventArgs(
                this.$vm,
                event,
                eventArray[1],
                eventArray[2],
                isCustom,
                methodName
              );
              params = Array.isArray(params) ? params : [];
              // 参数尾部增加原始事件对象用于复杂表达式内获取额外数据
              if (/=\s*\S+\.eventParams\s*\|\|\s*\S+\[['"]event-params['"]\]/.test(handler.toString())) {
                // eslint-disable-next-line no-sparse-arrays
                params = params.concat([, , , , , , , , , , event]);
              }
              ret.push(handler.apply(handlerCtx, params));
            }
          });
        }
      });
    
      if (
        eventType === 'input' &&
        ret.length === 1 &&
        typeof ret[0] !== 'undefined'
      ) {
        return ret[0]
      }
    }
    

    vm修改了data如何响应到页面

    vue代码

     data() {
               return {
                      title: "Hello"
              };
      },
      methods: {
              qq() {
                      this.title = 'oo'
              }
      },
    

    在vm的qq方法改变了data里的title的值,就会触发vue的依赖更新,然后会执行vue的patch方法,代码如下,uni是修改过vue的patch方法的,
    其中cloneWithData和diff是比较关键的代码,比较长就不贴出来了,关于diff方法不是vue原生的算法,代码很简单,
    但是为什么这么处理我就不知道了,有一点比较特别假如说原来data的title是一个数组[1,2,35],
    然后你重新赋值一个新的数组[3,5,67],只有数组长度一样,uni会setData{title[0]: 3, title[1]: 5, title[2]: 67},
    不知道uni这么做出于什么考虑,这样可能会快一些吧。

    var patch = function(oldVnode, vnode) {
        var this$1 = this;
      
        if (vnode === null) { //destroy
          return
        }
        if (this.mpType === 'page' || this.mpType === 'component') {
          var mpInstance = this.$scope;
          var data = Object.create(null);
          try {
              // 将你的vm里的data赋值到一个新的对象
            data = cloneWithData(this);
          } catch (err) {
            console.error(err);
          }
          data.__webviewId__ = mpInstance.data.__webviewId__;
          // mpdata 就是小程序实例mp的data里的值
          var mpData = Object.create(null);
          Object.keys(data).forEach(function (key) { //仅同步 data 中有的数据
            mpData[key] = mpInstance.data[key];
          });
          // vm和mp里的data两者比较算出差别来,然后通过mp的setData赋值给mp的data里然后页面就修改了
          var diffData = this.$shouldDiffData === false ? data : diff(data, mpData);
          if (Object.keys(diffData).length) {
            if (process.env.VUE_APP_DEBUG) {
              console.log('[' + (+new Date) + '][' + (mpInstance.is || mpInstance.route) + '][' + this._uid +
                ']差量更新',
                JSON.stringify(diffData));
            }
            this.__next_tick_pending = true;
            mpInstance.setData(diffData, function () {
              this$1.__next_tick_pending = false;
              flushCallbacks$1(this$1);
            });
          } else {
            flushCallbacks$1(this);
          }
        }
      };
    

    用一张图来快速理解

    需要注意的地方:

    一 mp和vm这2个实例是分别有自己的data

  • 相关阅读:
    Git的使用
    工具使用--Tomcat
    数据库优化-索引
    sql语句小练习
    Oracle sql 优化
    用词云图分析一带一路峰会哪3个词说的最多
    为什么你用不好Numpy的random函数?
    python3.6下安装结巴分词需要注意的地方
    UFO长啥样?--Python数据分析来告诉你
    关于matplotlib,你要的饼图在这里
  • 原文地址:https://www.cnblogs.com/wzcsqaws/p/15769068.html
Copyright © 2011-2022 走看看