解决 [Vue warn]: You may have an infinite update loop in a component render function

在 `v-for` 循环当中,如果用方法或者计算属性对 vm.$data 的属性进行操作,理论上,可能因为修改到循环对象,诱发无限循环。此时 Vue 就会发出警告(并不是真的已经无限循环了)。

今天写着写着,突然发现控制台里有错误:

[Vue warn]: You may have an infinite update loop in a component render function

这个问题很奇怪,之前从来没有遇到过。如果是我自己主导的项目,倒也好办,慢慢 debug 就是;偏偏在公司的项目里遇到这个问题,而公司项目的体系结构很复杂,我还没完全掌握。更恼火的是,因为体系复杂,debug 也非常困难,再加上尚无测试框架,这个难搞啊……

好死不死的,当时是下午3、4点钟,正好到了肚饿的时刻,结果又落入低血糖状态,真是屋漏偏逢连阴雨,船小又碰顶头风,饿得我脑仁生疼……

不过终于还是被我 Google + debug 出来。事实上是这样的,在 v-for 循环当中,如果用方法或者计算属性对 vm.$data 的属性进行操作,理论上,可能因为修改到循环对象,诱发无限循环。此时 Vue 就会发出警告(并不是真的已经无限循环了)。

例如这样一个组件,它里面是用 :checked + <label> 实现的一组按钮。它有以下功能:

  1. 为了能够分组,需要设置它们的 name 属性
  2. 为了能够用 <label> 控制 <input>,需要给 <input> 设置 id
  3. 按钮可以被删除

于是我选择这样做:

<template>
<div>
  <template v-for="(item, index) in items">
    <input type="checkbox" :name="'my-component-' + selfIndex" :id="getID">
    <label :for="getID(false)">
    <button type="button" @click="remove(index)">&times;</button>
  </template>
</div>
</template>

<script>
let count = 0;

export default {
  data() {
    return {
      selfIndex: 0,
      itemIndex: 0,
    }
  },
  methods: {
    getID(increase = true) { // 注意,问题就出在这里
      if (increase) {
        this.itemIndex++;
      }
      return `my-component-${this.selfIndex}-${this.itemIndex}`;
    },
  },
  beforeMount() {
    this.selfIndex = count;
    count++;
  }
}
</script>

这里,为了能生成唯一 ID,我选择每次循环都对 vm.itemIndex++,这就会出现前面说的问题,存在隐患。

解决的方案有两种,一种是把 itemIndex 也放在局部变量里,使它不直接关联在组件上;另一种则是写一个全局的唯一 ID 生成函数,然后引用进来。原理都是一样的。


这两天听评书《乱世枭雄》,学到一句话“拉屎脸朝外”,形容讲义气,不知道咋联系的……

MediaElement 笔记

贵司官网需要放视频,于是需要用播放器,最后选定 MediaElement。然后就开始踩坑之旅。当然,有些是我的问题,不过也有不少是文档没说清楚。这里记录一下。

贵司官网需要放视频,于是需要用播放器。然后就产生如下需求:

  1. 协议好,支持免费商用,最好 MIT
  2. 支持 SRT 字幕
  3. 支持尽可能多的平台

经过筛选,最后选定 MediaElement,一看 WordPress 在用基本就放心了。然后就开始踩坑之旅。当然,有些是我的问题,不过也有不少是文档没说清楚。这里记录一下。


全屏和弹性宽度

当前版本 4.2.5 有个 Bug,如果设置宽度为 100%,那么从全屏恢复到内嵌状态时,会留着全屏的宽度,撑开页面。如果设定一个特定的宽度就不会。但我们的页面是响应式的,需要允许它随页面变化而变化。

这个时候只好手工来做,我的选择是让它 100%,然后侦听从全屏返回的事件,发生后就把宽度恢复。另外,因为 fullscreenchange 事件还没有统一标准,所以不同浏览器里的事件名称也不一样,更不爽的是,IE 下是驼峰,其它浏览器是全小写,我也懒得再写函数转化了,反正就3种情况,全写一遍好了。

// fix MediaElement's issue
  let fitVideo = function() {
    setTimeout(() => {
    $('.mejs__container').width('100%')
      .find('video').width('100%')
      .end().find('.mejs__layers')
      .children().width('100%');
  }, 50);
};
if ('onwebkitfullscreenchange' in document) {
  document.onwebkitfullscreenchange = function() {
    if (!document.webkitFullscreenElement) {
       fitVideo();
    }
  };
} else if ('onmozfullscreenchange' in document) {
  document.onmozfullscreenchange = function() {
    if (!document.mozFullScreenElement) {
      fitVideo();
    }
  };
} else if ('MSFullscreenChange' in document) {
  document.MSFullscreenChange = function() {
    if (!document.msFullscreenElement) {
      fitVideo();
    }
  };
}

默认字幕

Web 标准是有默认字幕的,<track defualt> 即可。但是 MediaElement 没有,最后在 StackOverflow 上找到答案,原来有个未记录在文档里的初始化属性可以控制:

let player = new MediaElementPlayer('intro-video', {
  startLanguage: 'cn', // 这里的名字应该和 <track> 种的 srclang 属性一致
});

插件与生态

MediaElement 把一些有用但不太常用的功能抽出来做成了插件,放在 MediaElement Plugins。不过看起来这个项目有些属于维护,使用的时候很多问题。比如,直接在 features 里开启特定功能,即使对应的插件没有加载,也不会报错,就是没反应,很令人迷茫。

避免发起又取消请求

网站上线后,老板发现一个问题:从 Chrome 的 Network 面板可以看到,网页打开后,对视频文件发起了一到多个不等的请求,并且都取消了。

经过研究,我认为这个请求是 <video> 发起的,因为 preload 的默认值是 auto(参见:MDN),也即打开页面就预加载。而此时 MediaElement 被初始化,为了正确显示 UI,它会把 <video> 标签挪到自己创建的 <div> 里,这个过程就会导致“预加载 -> 取消”。因为视频默认不播放,所以我给 <video> 加上了 preload="none",问题解决。


其它大体上文档都能找到,就不多说了。

再次出发

从本月中开始,加入 OpenResty Inc. 开始新的旅程。

去年前司裁员,我等外地工人终于也没逃脱,在年前和平分手。

在创业公司连续工作五年,虽然遇到很棒的老板,但还是有点累。加上被罗辑思维蛊惑,再加上看到一些同行做培训做得很好,所以我就打算先不去找工作,尝试做一下培训。再不济,也能给将来的生活带来一笔客观稳定的被动收入嘛。

如果你有看过我之前的文章应该已经知道结果了。总之,不好搞啊不好搞。

前几日突然看到 OpenResty Inc. 在招前端工程师,而且是远程。我对这个项目早有耳闻,对远程工作也很感兴趣,于是马上投简历过去。经过数轮面试,顺利得到这个职位。

于是从本月中开始,我成为 OpenResty Inc 的一员!


我对这份工作很满意,原因有四:

  1. 远程
  2. 技术型老板,技术型公司
  3. 开源项目,商用收费,在国内应该还很少见,国外比较多,比如 WordPress,感觉很有趣的样子
  4. 具体到细分领域,OpenResty 在行业内名气似乎很响亮,甚至可能是最响亮的一个

祝自己大展鸿图。

Vue 里 $mount 方法的作用

关于 Vue 的 $mount 方法,一问一答。

今天由同学问道:“vue文档里说如果 Vue 实例在实例化时没有收到 el 选项,则它处于“未挂载”状态,没有关联的 DOM 元素。可以使用 vm.$mount() 手动地挂载一个未挂载的实例。这个方法在项目中有什么用呢,是一个组件可以挂载到多个dom上就这一个作用吗?”

我的答案如下:

有些时候你创建 vm 的时候 DOM 可能还没准备好,或者写 vm 的时候不确定它要挂在哪个 DOM 上,这个时候就有用了。

当项目大的时候,很多情况是开发的时候估计不到的。比如 A 类里面想使用一个 B 类,但是 B 类有 10 个子类,对应不同场景,你写 A 类的时候根本不知道产品中会使用哪个 B 的子类,所以就要想办法把控制权交出去,这就叫“控制反转”——即控制权从开发者的手上,交到使用者的手上。

我觉得 $mount 这里也是类似的,就是你写了一个 Vue 类,但是不能控制使用场景。所以就要有一个 $mount 方法,由使用者控制,绑到目标 DOM 上。

他又问:“懂了,还有一个问题是一个组件能不能利用$mount属性挂载到多个dom上,我刚刚试了一下是可以渲染,这种用法常见吗??”

我答:

我没这么做过,不过我认为是合理的。

我觉得这个跟 Vue 的定位有关。Vue 和 React、Angular 不一样,后者是大公司企业级产品。Vue 其实很想取代 jQuery,所以这方面其实跟 jq 的插件是很相似的。

Webpack 笔记

记录一些 webpack 的使用经验。我是渐进式使用 webpack 的,一开始只用它打包 js。但是现在开始会把越来越多的依赖交给它管理,所以记一篇笔记。这里不会教怎么使用,而是结合开发经验,总结一些特定需求的解决方案。

我使用的版本:3.5.1

我是渐进式使用 webpack 的,一开始只用它打包 js。但是现在开始会把越来越多的依赖交给它管理,所以记一篇笔记。这篇不是教程,而是结合开发经验,总结一些特定需求的解决方案。

继续阅读“Webpack 笔记”

关于“大漠”的一点不好的记忆

关于大漠的一点不好的记忆。不过当年没搞清楚到底是哪个。发生了最近的事情,我觉得可能是这个……

我这个人不爱交际,在行业里一直是个小透明。

不过我当年也曾想试着改变一下自己,所以找了个前端交流群加了进去。具体的群名字忘记了,总之是“大漠”创建的群。

然后发现这个群真TM恶心。群主大漠有几个小弟,一副高高在上颐指气使的样子,对群里成员吆五喝六随意攻击,不仅对发问者提出各种限制,对回答者也提出各种限制。群主也是一副老子对你们这些废柴施恩,还不快快对我歌功颂德的气势。(具体做法记不清了,好多年了。)

然后我就受不了啦。如果前端圈子都这个吊样子,那我不交际也不要紧。于是吐槽两句自己退群了。

退了之后,想说这个大漠是谁啊,怎么这么差劲,然后搜了一下,发现叫这个名字的好多,无法确定是哪个,我也懒得跑回去确认。


发生了最近的事情后,我举得按人品和气度,有可能是这个……

Vue 笔记:事件

记一些 Vue 的笔记。本篇均与事件处理相关。

onload

需要侦听 load

<template>
  <img src="/path/to/img" @load="onLoad">
</template>

<script>
export default {
  methods: {
    onLoad(event) {
      // do something
    }
  }
}
</script>

drop

需要阻止 dragover 的默认行为,不然不触发。

<template>
  <div class="drop-area" @dragover.prevent="onDragOver" @drop="onDrop">
</template>

<script>
export default {
  methods: {
    onDragOver(event) {
      // 此时仍然可以处理
    },
    onDrop(event) {
      console.log(event.dataTransfer);
    }
  }
}
</script>

尬聊会:第二期实录

尬聊会第二期实录。聊了创业、准备简历等问题。

视频地址

时间锚点:

  1. [00:33] 创业那点事儿
    1. 股权
    2. 期权
    3. 融资
    4. 估值 200w / 20% = 1000w
    5. 市盈率
  2. [10:00] 如何制作简历
    1. 两个不好的简历
    2. [47:55] 一个好的简历
  3. [37:50] 面试时算法和计算机基础怎么准备?
  4. [39:00] 校招和社招的差别

  5. [43:00] 学了 H5 和 CSS,怎么巩固?

  6. [47:55] 一份好的简历

  7. [52:35] 实习工资

    1. 北京 10K
    2. 杭州 4.5K
  8. [1:00:33]怎么选择合适的公司
    1. 在各个方面给予提升
    2. 看老板,看业务
    3. 慎重选择每一份工作
  9. [1:08:15] 对于转行自学就业,找工作,这方面能不能发表下你个人看法
  10. [1:13:33] 我今年31在一家大公司的地方站做前端工作 4年工作经验 今年想去北京工作

  11. [1:16:55] 前端接口测试通常要怎么做呢?有没有考虑做个课程出来聊聊?

  12. [1:18:55] 老师,对原生JS使用熟练, 目前项目多是混合app开发,没有react, angular,vue 框架的经验,对目前面试有影响吗

  13. [1:21:25] 框架学到怎样的程度合适呢

  14. [1:22:00] 老师,最近想换实习公司,如果在上班的时候,面试的HR打电话过来

  15. [1:24:22] 会写小程序优势大吗?

  16. [1:27:19] 与今天有关的课程广告

继续阅读“尬聊会:第二期实录”

尬聊会:第一期实录

尬聊会第一期实录。

这个视频斗鱼说有问题,色情暴力之类的,给我拒了。我百思不得其解。如果你看完发现问题所在,请告诉我,谢谢。

时间锚点:

  1. [01:40] webpack该怎么学习呢?
  2. [05:20] 我为什么想搞尬聊会
  3. [07:10] 面试小经验
  4. [16:20] node怎么进行学习
  5. [21:00] 经常被问 ……源代码? 怎么读别人的源代码呢?
  6. [29:35] 初学者学习es6有什么好的方法?
  7. [34:35] 请加下,现在做跨平台,ionic2和RN选哪个好一点呢?
  8. [38:45] Phonegap
  9. [41:45 进度条这里出问题了,不知道线上怎么样] 现在的很多公司是否都不愿意带新人,兼谈学习
    1. 非常主动
    2. 胆大(有问题就问)心细(不要逮着一个人问)脸皮厚
    3. 问题必须经过自己的思考,尽量问一句话能答完的问题
  10. [44:20] 框架选择问题。Vue 作者尤雨溪的访谈
  11. [51:07] 半路出家的 JSer 学写样式
  12. [57:00] 会写页面但是不会 JS 的同学怎么学?

继续阅读“尬聊会:第一期实录”

卖不动的硬知识

再分析一下培训/知识售卖领域的现状。总而言之一句话:这个活儿,我不适合。

距离上次总结还没到一个月,按说不该写总结的。但是前些日子读到一篇文章:《知识付费:硬的尴尬,软的大方》,结合最近看到的想到的,有感而发,于是想再啰嗦几句。

前年年底,我确诊糖尿病,决定要跑步锻炼,于是开始听《罗辑思维》。罗辑思维是知识服务知识付费的先锋军,为了提升基本面,他没少鼓吹这个行业。当然,也不算胡说,他的估值和各种销售额都在印证这个思路。我听着听着也心动起来。去年被前司裁掉后,我觉得开发培训应该值得一做,即使做不成,也能给自己带来持续稳定的收入。再加上短时间也找不到满意的工作,于是我今年就投入了大量的时间和精力做培训,以备课做直播为主。

结果很失败。做一次直播好的话能挣400块,不好的话大约100~200,但是需要准备2~3天,甚至4天也有可能。付出回报完全不成比例。GitChat 文章也差不多。当然,有些讲师的课卖得不错,每次能卖好几百人,收入算起来也有好几千,但是,我假定他们的准备时间跟我类似,这点收入和正常上班的收入比起来也完全不够看。

消费者的问题

通过我的观察,我发现这个领域的消费者和我之前设想的完全不同。每个人都会以自己的经历作为主要参考坐标,所以我自然是把我自己当成潜在客户,我对知识类产品的消费习惯是:

  1. 知道自己应该学什么
  2. 要求精深的知识
  3. 付费100以下可以忽略
  4. 主动学习,耐心学习

然而实际做了一段时间之后,我发现这个市场完全不是我想象中的样子,大部分同学是这样的:

  1. 不知道自己应该学什么。你问他想听什么,他说想听“如何成为高阶前端”、“如何看懂 jquery 源码”……
  2. 知识欠缺太多,太深的完全听不懂。
  3. 价格非常敏感,3块5块10块都有很大差别,为了找5元优惠可以转好几个 QQ 群。其实想想也对,5块钱大学里可能够吃顿饭了。
  4. 主动学习的很少,耐心学习的就更少。大部分同学都想速成屠龙之技,所以总会问出 1 里面的问题,得到鸡汤答案或者得不到答案之后就会去该干啥干啥了。

其实我当年又何尝不是如此?只是丢到社会上被歧视被压榨被摔打,多了,就知道该努力了,也知道该怎么努力了。现在想找到一批又想努力又踏实,还能力落后又肯花钱购买服务的人,真的是,太困难了……

行业的问题

应该说这个行业也没做好准备。

国内没有专业的编程直播平台,毕竟烧钱的项目,可以理解。斗鱼之类的平台倒也不拦着你,但是没什么流量,我在斗鱼直播,最好的时候50+人,偶尔互动两下。上周开尬聊会,好不容易把视频弄了下,填了半天的时间锚点,传上去,结果说我涉嫌色情暴力,也不告诉我哪一段,就不给我通过……

SF 直播,我投入最多时间的地方,专业技术论坛。到现在视频加锚点、视频加字幕、视频进入搜索结果都还没做。每次一问,态度都特别好,正在计划中。然则开播半年了,除了实现基础的直播功能,其它优化乏善可陈。我问了一下,公司 21 人,开发任务排得很满。不知道这种“一锤子买卖”的情况还要持续多久。

然后是 GitChat,文章竟然不支持后期编辑,简直匪夷所思,写好的文章想更新都更新不了。然后文章页完全没 SEO,没关键字没描述,百度搜不到,Google 也只抓了列表页。首页上看不到即将开始的话题,也没有分类……全是槽点。

所以我觉得,虽然知识付费已经很火,硬知识领域也可能有机会,但目前的行业各参与者,都还没做好准备。在合适的产品出现之前,先入者都在用自己肉身趟雷,填坑……

哦,对了,小密圈涉黄被关,我的朋友圈里也哀鸿遍野。

马太效应

马太效应,即赢者通吃,在公司上比较常见,在具体工作人员身上到没啥表现。同一级别的开发人员,在小公司拿这么多钱,在大公司也差不多,了不起配一些股票,差距不会太大。

但是知识售卖领域,马太效应就很明显。弱者比如我,各项积累都很差,基本上每次直播只能卖几十张门票;但是强者如果背景够好,卖几百人问题不大,破千也有可能。本就囊中羞涩的求知者,肯定更倾向于参与名家的分享,来我这里的更少。

于是我就得不到成就感,久而久之就放弃(我已经计划这样做了)。大家也很难挣到足够的钱持续做下去——而且一旦全职投入做分享,恐怕也要失去做“大家”的资本了——所以必须保证正职,所以时间就有限,所以场次就填不上。所以聚拢过来的消费者也渐渐散去。

啧啧,我是不是说的有点过……


所有的硬知识,都是如此。既然硬,就需要更多的时间消化,更多的时间练习,本就不可能速成。不能速成,就缺乏成就感;补偿机制不同,就不愿意投入精力、时间、金钱。最终,想要靠卖硬知识糊口,很困难。至少在目前,很困难。