vue在混合开发中应用的思考

一、前言😃

我目前在做的一个项目,前端这块虽然说使用的是CS架构,但其实是C#提供了一层Chrome内核来运行app的。也就是混合开发的一种。现在的工作是将以前的jquery一把梭的开发模式转移到vue上来,这就带来了vue在混合开发中应用的思考。

二、混合开发

Android,WPFIOS等等这些原生(或桌面)应用都会提供一个WebView的控件来支持原生web交互。

而交互的方式分为两种:

  • 一是原生调用js中window上的对象(或函数)。
  • 二是js调用原生提供在window上的对象。

一般情况都是原生容器提供一个对象,js去调用这个对象的方法,若为同步处理,直接返回值;若是异步的处理,原生容器会在处理结束后再调用window上的回调函数。
总的就是

// 原生容器提供的对象
window.OBJ.callback("123");
// js提供回调给原生容器调用
window.onOBJCallback = function (data){
    console.log(data);
}

三、vue应用于混合开发

1. 一代

可以看到js和原生交互都在window上,而vue这种内部处理数据的方式和这种window交互其实不是很搭的,要写也可以,但是极为别扭。如:

export default {
  data() {
    return {
      text: ""
    };
  },
  mounted() {
    // 挂载到window上
    window.onCallback = this.onCallback;
  },
  methods: {
    onCallback(data) {
      this.text = data;
    }
  }
};

这样虽然直观,但如果回调太多,代码写的多而易读性差不说还丑😐。

2. 二代⚡

混入(mixin) 提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能。一个混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项。

由于混入是在已有组件的调用前调用的,所以在使用恰当的方式下不影响已有组件的开发。

设计思路
  • 考虑到可以混入其他属性,那可以混入一个叫callbacks的属性,就像methods属性一样去写方法,但可以很明显地区别开内部方法和回调方法。
  • vue的配置可以通过组件内this.$options来获取,那么若要混入callbacks,就可以this.$options.callbacks来获取到所有组件里的方法。
  • 拿到定义好的callbacks,那就可以混入mounted()来挂载回调方法到window上。
  • 说干就干,代码如下
export class Callackable {

  // 用于缓存每个页面的callbacks
  callbacks = {};
  install(Vue, options) {
    // 让Vue的组件能访问到这个实例里
    const self = this;

    // 开始混入
    Vue.mixin({
      beforeCreate() {
        if (this.$options.callbacks && !(this.$route.name in self.callbacks)) {
          self.installCallback(this, this.$options.callbacks)
        }
      },
      mounted() {
        const name = this.$route.name;
        if (self.callbacks[name]) {
          self.callbacks[name].forEach(callback => {
            // 挂载
            window[callback.name] = callback.func
          });
        }
      }
    })
  }

  installCallback(vm, callbacks) {
    const routeName = vm.$options.name
    Object.keys(callbacks).forEach(name => {
      (this.callbacks[routeName] || (this.callbacks[routeName] = [])).push({
        name,
        // 将回调方法的this指向绑定到自己的组件实例上
        func: callbacks[name].bind(vm)
      })
    })
  }
}

主要思路就是每次组件加载时,在beforeCreated中获取callbacks,然后根据组件名称缓存起来,然后再在mounted时挂载组件。
重点主要在:绑定this。如果直接挂载到winodw上,那么调用这个回调函数时,this指向的就是window,所以通过bind方法来绑定到当前组件上

然后在main.js中通过Vue.use(new Callbackable())就可以了。

开发时如下:

export default {
  data() {
    return {
      text: ""
    };
  },
  callbacks: {
    onCallback(data) {
      this.text = data;
    }
  }
};
然而这其实是bug版本!!!👾

3. 二代改良版🔥

后面开发中发现,如果回调里处理data数据,切换路由后到其他页面再切换回来就会出现不能绑定到template上的情况!经过各种调试,发现虽然会触发data数据的改变,但并不会触发该组件内的watch去监听,自然就没有渲染。奇怪的是this也是组件本身。。。🙉

偶然地机会,🤔发现了两次this._uid不一样,恍然大悟下知道了vue-router其实每次进入路由,若没有通过<keep-alive>包裹<router-view>,那么都会新建一个组件,这就是解释了之前的问题,也就是this指向的是之前的那个组件,所以回调改变的其实也是之前的组件的data。所以每次路由切换都要重新绑定一次this才行。代码如下:

export class Callackable {

  callbacks = [];
  install(Vue, options) {
    const self = this;
    Vue.mixin({
      beforeCreate() {
        /**
         * 不能通过缓存来取callback。
         * 因为路由切换会导致组件实例的重新创建,this便指向过去的组件实例,而不是当前新创建的实例
         */
        if (this.$options.callbacks) {
          self.installCallback(this, this.$options.callbacks)
        }
      },
      mounted() {
        self.callbacks.forEach(callback => {
          window[callback.name] = callback.func
        });
      }
    })
  }

  installCallback(vm, callbacks) {
    Object.keys(callbacks).forEach(name => {
      this.callbacks.push({
        name,
        func: callbacks[name].bind(vm)
      })
    })
  }
}

这次就完美地解决了之前的问题。

四、总结

vue在混合开发中的应用就暂时告一段落了,大概设计了回调的使用方式和了解了vue-router的机制,还是要多读源码啊:P。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,539评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,911评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,337评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,723评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,795评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,762评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,742评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,508评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,954评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,247评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,404评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,104评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,736评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,352评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,557评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,371评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,292评论 2 352