标签: vue

  • Vue3 < script setup > + TypeScript 笔记

    Vue3 < script setup > + TypeScript 笔记

    近期把一个老项目(Vue 组件库)从 Options API 风格重构成了 <script setup> 风格 + TypeScript,写篇博客记录下坑和心得。

    注:这篇博客只记录超出我踩过坑和不熟悉的内容,符合直觉、看了文档写完一次过的部分,我就不记录了。

    0. Composition API 与 <script setup>

    Vue 3 给我们带来了 Composition API,改变了之前 Options API 使用 mixins 继承和扩展组件的开发模式。这种模式让前端在开发时复用组件、改进组件变得更容易。具体改进我在本文里不再详述,大家可以看下 Vue master 的视频教程:Why the Composition API

    之后尤大又提出了 script-setup rfc,进一步改进了使用 Composition API 的体验。简单总结下新提案:

    1. 使用 <script setup> 取代 setup(),里面定义的所有变量,包括函数,都可以直接在模版中使用,不需要手动 return
    2. 可以使用顶级 await
    3. <script setup> 可以与其它 <script> 在同一个 SFC 里共存

    实际体验之后,我觉得这个提案的确能节省不少代码,不过也会增加一些复杂度。

    1. 导出 name 等非模版属性

    <script setup>setup() 的语法糖,主要目的是降低 composition API 的代码复杂度。它直接向模板暴露整个 <script setup> 的上下文,所有定义过的变量自动导出供模版使用,这样我们就不需要手动一个一个 return 了。

    所以它就不适合导出其它非模版属性,比如组件名称 name。如有需要,可添加一个普通 <script> 节点,用常见的 export default 导出初始化对象。如下:

    <script>
    export default {
      name: 'SomeVue3Component',
    };
    </script>
    
    <script setup>
    import {ref} from 'vue';
    
    const foo = ref('bar');
    </script>

    2. defineProps/defineEmits

    要在 <script setup> 里使用 props(传入参数)和 emit(广播事件),需要使用 defineProps()defineEmits() 定义。但要注意,这俩东西其实是编译宏,并非真实函数,不能把它们当作函数来使用。所以也不需要 import,当它们是全局函数直接用就好。同时记得修改 .eslintrc.js 把它们添加到 global 里。

    最简单的使用方法如下,以前的 props 定义规则可以沿用。

    const props = defineProps({
      foo : {
        type: String,
        default: 'bar',
      },
    });
    const emit = defineEmits(['change']);

    要配合 TypeScript,通常需要使用 withDefaults()props 生成默认值。这也是个宏,不能当函数用,也不能使用当前环境里的变量。改造后的代码如下:

    interface Props = {
      foo: string;
    };
    const props = withDefaults(defineProps<Props>(), {
      foo: 'bar', // 'bar' 不能是变量
    });
    const {
      foo,
    } = toRefs(props);
    
    const emit = defineEmits<{
      (e:'change', value:string),
    }>();

    这个地方的设计相当不完善,我不知道 Vue 团队会如何改进这里。比如,我们不能使继承 interface,然后再初始化 props,因为继承是常规 ts 语句,而 defineProps 是编译宏,两者的工作环境不一样。而因为无法使用变量,我们也无法将父级组件的 props 混入本地 props。于是复用组件又变得麻烦起来。

    耐心等待吧。

    3. 使用 undefined 初始化对象

    定义 props 问题真不少。有一些参数是可选参数,不一定要定义,也不一定要用到;但是使用 ts 定义时,即使如此,也要初始化他们,可以传值为 undefined,不然 tsc 可能会报告错误:变量可能为空。之所以用 undefined,而不是 null,则是因为 TypeScript 认为 null 是独立类型。

    即:

    interface Props {
      foo?: string;
    }
    const props = withDefaults(defineProps<Props>(), {
      foo: undefined,
    });
    const {
      foo,
    } = toRefs(props);
    
    // 接下来才能正常使用
    const bar = computed(() => {
      return foo.value || 'bar';
    });

    4. 使用的变量未初始化错误

    有些函数,可以传入为定义变量做参数,但是函数自身的签名没有很好的体现这一点,就会报错。比如 setTimeout,以下这段代码就会报告:

    type timer = ReturnType<typeof setTimeout>;
    let timeout:timer;
    function doAction() {
      clearTimeout(timeout);
    }

    我确定这段代码没问题,但是 tsc 不给过,只好给 timeout 加上 ! 修饰符,即:let timeout!:timer。这样就可以了。

    5. Vue SFC 文件类型定义

    为让 tsc 能够正确理解 Vue SFC 格式,需要创建这个描述文件,并且告诉 tsc 加载这个描述文件。

    declare module "*.vue" {
      import { defineComponent } from "vue";
      const component: ReturnType<typeof defineComponent>;
      export default component;
    }
    {
      "compilerOptions": {
        "target": "esnext",
        "module": "esnext",
        "strict": true,
        "jsx": "preserve",
        "moduleResolution": "node",
        "suppressImplicitAnyIndexErrors": true,
        "allowSyntheticDefaultImports": true,
        "allowJs": true,
        "resolveJsonModule": true,
        "esModuleInterop": true,
    
        "paths": {
          "@/*": [
            "./src/*"
          ]
        },
        "lib": ["DOM", "ESNext"]
      },
      "include": [
        "src/**/*.ts",
        "src/**/*.vue",
        "test/**/*.ts"
      ],
      "exclude": [
        "node_modules"
      ],
      "files": ["src/types/vue-shims.d.ts"]
    }

    6. 待解决问题

    • 因为第一次使用 TypeScript,很多不熟悉的地方,tsc 大量报错。但是由于使用了 vue-loader,所以 tsc 报告的错误行号基本都不对,很难查找问题所在,浪费了大量时间。
    • 导入了 moment locale 文件,但是缺少定义,不知道该怎么声明某个对象属于某个接口。可能要通过前面类似定义 Vue SFC 的方式。

    7. 项目地址

    对项目感兴趣,或者寻求范例的同学可以在 GitHub 上找到这个项目:meathill/muimui-ui: A simple vue 3 ui components suit. (github.com)

  • 升级 Vue@2 项目到 Vue@3

    升级 Vue@2 项目到 Vue@3

    这篇主要是笔记。(我估计会是第一篇,因为只迁移了一个项目)

    1. 安装新包

    只记录必须重装的:

    npm i vue@3 vue-loader@16.0.0-beta.8 vue-router@4.0.0-beta.13 @vue/compiler-sfc

    2. 修改 Webpack 配置

    // v2
    const VueLoaderPlugin = require('vue-loader/lib/plugin');
    // v3
    const {VueLoaderPlugin} = require('vue-loader');
    
    // for DefinePlugin
    {
      plugins: [
        new DefinePlugin({
          __VUE_OPTIONS_API__: true,
          __VUE_PROD_DEVTOOLS__: false,
        }),
      ],
    }

    3. 修改入口文件

    没有 new Vue({}) 了,取而代之的是 Vue.createApp({}),后者还支持 tree-shaking。

    也不需要注册 Vue-router 了,直接 app.use(router) 就好。所以传统的入口文件就要修改为:

    // v2
    import Vue from 'vue';
    import VueRouter from 'vue-router';
    import App from './app';
    import 'bootstrap/dist/css/bootstrap.min.css';
    import '@/styl/index.styl';
    import router from './router';
    
    Vue.use(VueRouter);
    
    Vue.config.productionTip = false;
    
    new Vue({
      router,
      ...App,
    }).$mount('#app');
    
    // v3
    import {createApp} from 'vue';
    import App from './app';
    import 'bootstrap/dist/css/bootstrap.min.css';
    import '@/styl/index.styl';
    import router from './router';
    
    const app = createApp({
      ...App,
    });
    app.use(router);
    app.mount('#app');

    4. 修改 router

    Vue-router 的变化很大,建议大家好好看看 迁移手册。就我厂这个项目而言,主要是三个变化:

    1. 使用支持 tree-shaking 的函数 createRouter
    2. 修改 history: createWebHistory()
    3. 使用渲染函数 h 替换之前渲染方式
    // 加载方式
    import {h} from 'vue';
    import {
      createRouter,
      createWebHistory,
      createWebHashHistory,
      RouterView,
    } from 'vue-router';
    
    const routes = [
      {
        path: '/',
        name: 'home',
        component: {
          // vue-router v3
          render(createElement) {
            return createElement('router-view');
          }
    
          // vue-router v4
          render() {
            return h(RouterView);
          },
        },
        children: components,
      },
      // ....
    ];
    
    const router = createRouter({
      // vue-router v3
      mode: process.env.NODE_ENV === 'production' ? 'history' : 'hash',
      // vue-router v4
      history: process.env.NODE_ENV === 'production'
        ? createWebHistory()
        : createWebHashHistory(),
      scrollBehavior: (to) => {
        if (to.hash && !/^#/.test(to.hash)) {
          return {selector: to.hash};
        }
        // 这里有个小改动,x => left, y => top,简单提一下
        return {top: 0};
      },
      routes,
    });

    5. 自定义组件 v-model 修改

    • prop: value => modelValue
    • event: input => `update:modelValue`

    6. 一些小修改

    • beforeDestroy => beforeUnmount

    7. createApp 与 Application,与 Component

    v2 时,我们可以通过 new Vue({}) 初始化 Vue 实例。这个阶段,Vue 默认有一个全局对象 + 若干个实例,除了 local 的,就是全局的。

    v3 时,引入了 Application(应用)的概念,在全局和组件之间,增加了一个新的层级。这样一来,我们就可以在同一个 Web 产品中,使用 Application 来划分命令、组件、mixins 的范围。应该会增加代码的强壮程度(虽然我暂时还没用到)。

    不过,迁移代码的时候,也要注意。以前我们可能 new 一个实例,调用它的 methods;现在不行了,要这样做:

    // v2
    const ins = new Vue({});
    ins.doSomething();
    
    // v3
    const app = createApp({});
    const vm = app.mount('$el');
    vm.doSomething();

    8. 新的响应式 API

    v3 最大的变化就是重构了响应式实现,所以新增了不少响应式 API。同时,也会检查开发者的代码,如果发现不需要响应式的地方用到响应式对象,就会提示开发者,因为响应式会增加系统开销。

    这个时候可以用 markRawtoRaw 方法来修改对象,撤销之前附加在上面的响应式属性,提高访问效率。

    其它 API 还很多,后面慢慢更新吧。

    9. Devtool 和 SourceMap

    遗憾的是,目前 Vue Devtool 无法检测到 Vue。老项目的 SourceMap 也完全不生效,无法正常对 SFC 进行 debug。

  • webpack 入口是 vue 文件时,无法合并 CSS

    webpack 入口是 vue 文件时,无法合并 CSS

    在多页网站中合并 CSS 是很常见的优化手法。一般来说,CSS 体积不会太大,使用同一份 CSS,改进用户点击链接后的加载速度,大部分收益都大于多加载几 K CSS 带来的损耗。

    对于 UI 库来说也是如此,用统一的样式库,减少 import 时的心智负担,也是性价比很高的做法。

    最开始我在 UI 库的入口文件里 export 所有组件,然后在其它仓库里用 import {component} from 'my-components' 使用组件。后来通过分析得知,这样做无法 tree-shaking,而且会导致组件库的重复引用,即 A import B,B import C,那么无论 A 里有没有用到 C(比如用到 B 的一个小功能 b1,它不依赖 C),都会把 C 的代码打包进去。

    通过研读 Webpack 的 tree-shaking 文档,我得知也没有什么好办法可以规避这个问题,毕竟 JS 很灵活,你也不知道哪个开发者会搞个 eval('const myRequire = require'),如果要识别解析分辨所有情况太复杂,所以选择最保守的策略:认不出来具体功能的代码都给你带上。(早年我写 NerveNet 的时候,就是想不通这里怎么搞,最后坑掉了。早知道大家都选择绕开,说不定我的 NerveNet 也能如愿写出来了……)

    总之,目前 lodash 的做法比较常见且能解决问题,即增加多入口,为每个可能用到的函数都打包独立的函数。这样需要引用那个就引用哪个,不用担心把整个 lodash 都打包进去。

    于是我就立项开始重构我厂的几个前端库。然后很快就卡在 UI 库上面:无法生成合并过的 CSS 文件。Google 许久没有结果,吃饭前我灵机一动:vue-loader 必须搭配 VueLoaderPlugin 才能正确打包,会不会这个过程有 bug,导致如果我的入口都是 Vue 单文件组件,就会没法正确合并 CSS 文件。

    然后我就测试了一下,代码大约如下:

    // a.js
    import './a.styl'
    
    // b.js
    import './b.styl'

    可以生成合并过的 CSS 文件。与之相较,这样的 Vue 单文件组件就不行:

    // a.vue
    <style lang="stylus">
    body
      font-size 16px
    </style>
    
    // b.vue
    <style lang="stylus">
    body
      color red
    </style>

    但是,同样是 vue 单文件组件,样式使用 import 的方式导入,就没问题:

    // a.vue
    <script>
    import './a.styl';
    </script>
    
    // b.vue
    <script>
    import './b.styl';
    </script>

    现在可以确定是 vue-loader 或者 VueLoaderPlugin 有问题。不过最近身体欠佳,每天要花很多时间锻炼,另外还欠下不少坑要填,所以暂时没空去翻 issue 或者提 issue。哪位同学看见了,愿意帮忙的,可以搞一下,也算参与 开源社区建设了,功德无量。

  • Vue 3.0-beta.1 发布!

    Vue 3.0-beta.1 发布!

    经历一年多的推倒重来反复打磨,在众多开发者的千呼万唤之下,Vue 开发团队终于在今天发布了 3.0-beta.1 版本,也就是测试版。通常来说,从测试版到正式版,只会修复 bug,不会引入新功能,或者删改老功能。所以,如果你对新版本非常感兴趣,或者有新项目即将上马,不妨尝试一下新版本。

    按照官方路线图,原计划 Q1 末发布测试版,Q2 发布正式版。目前看来稍微有些延期,不过不多。相信正式版会很快到来,非常期待呀。

    在我看来,Vue 已经是一份杰作,而 3.0 的变化则让它更加优秀。

    起初,Vue 开创性的使用 Object.defineProperty 改写对象属性赋值运算,隐性收集依赖,把前端开发的难度降低了一个维度。从此,我们不需要考虑怎么绑定数据,怎么更新视图,只需要简简单单修改变量的值,界面就会自动变化,如魔法一般。

    如今,Vue 3.0 更进一步,使用 Proxy 拦截赋值操作,不仅实现了同样的功能,还大幅降低系统消耗、减少计算时间。——更加值得期待的是,因为新 API 更强大,之前困扰众多开发者的“修改数据,界面不更新”问题,应该会变得极为罕见。

    这会令 Vue 的入门门槛变得更低。在我看来,这件事善莫大焉。写代码并不仅仅是写代码,它是这个世界上成本最低的“创造型”工作。其它创造型工作,比如雕塑、美术,除了复杂的基础教育,还需要昂贵的生产成本。编程不需要,只要你有一台电脑,坐下来就可以写,想怎么写就怎么写,想写什么就写什么。而前端,又是其中成本最低的,你甚至不需要搭建开发环境,拿个记事本就能写,写完放到浏览器里就能跑。

    从这个角度出发,每次在知乎看到“我出身不好,能不能学编程”,或者“我学历不好,能不能学编程”,我都会建议他们学。因为学会编程,不仅仅是掌握一门手艺,可能养家糊口,更是给自己的未来增加了一种可行性。学会编程,你就可以把手伸到我这种专业程序员伸不到的地方,帮助自己、帮助他人、甚至帮助世界,同时也能给自己换来各种各样的回报。

    另外,新增的 Composition API——不管是一些人口中的“学 React hooks”,还是 Vue 作者尤雨溪说的“这不是 hooks,这比 hooks 强太多了”——大大增强了代码的可复用性,能很好的改进代码架构,为更大的项目、更强的架构,带来了更多的可能。

    如果说 jQuery 让更多的人可以学会开发,那么 Vue 就让更多的人可以开发中大型软件。它会给整个行业带来的巨大帮助,让更多的产品可以有更好的用户体验,让更多的产品可以迁移、升级到新平台、新架构。

    这个影响是潜移默化的,就像当年 Flash Player 集成 H.264 视频解码器一样,虽然很多人没注意,但是视频网站的春天就是那个时候到来的。如今,有了更好的基础设施,哪个新产品会崛起,我无法判断,但我觉得,对技术来说,更好的一天已经开始了。

    (更多…)
  • Vue 2020 年路线图,Vue 3.0 计划于 Q2 发布

    Vue 2020 年路线图,Vue 3.0 计划于 Q2 发布

    昨天 Vue 团队更新了 2020 年的路线图,里面包含了很多 Vue 3.0 的信息。建议大家一定要看原文,地址在:https://github.com/vuejs/vue/projects/6。下面我结合自己的理解翻译一下:

    FAQ

    问:3.0 啥时候能好?

    答:请往后看。另外请注意,这些日期仅供参考,我们团队的首要目标是发布生产级别的高质量代码,不是赶 deadline。

    问:3.0 里都有啥变化啊?

    答:请自行翻阅最新的 RFC。另外,也要注意核心团队提交的 RFC 草案。

    如果某个 RFC 里包含破坏性变更,那么里面一定会有“升级策略”章节,讨论迁移问题。

    对于现在的 2.x 用户,我们会提供:

    • 迁移向导
    • 能够兼容 2.x 的兼容性版本(如果能兼容的话),并且对该升级的地方给出提示和升级建议
    • 命令行迁移工具
      • 自动升级能升级的代码
      • 不能自动升级的,扫描出来提示手动升级

    问:我是新人,我现在该学 Vue 2.0 还是等 3.0?

    答:如果你刚刚开始学习框架,那么应该开始使用 Vue 2。我们没有对 Vue 3 进行巨大的重新设计,所以大部分 Vue 2 知识仍将适用于 Vue 3。 如果你打算学习框架,没有必要等待。

    如果你要为某个生产级别的项目选择技术栈:

    • 如果项目需要立即动工:我们仍然建议使用 Vue 2,以便获得完整的、框架级别的支持。 但是,也请留心 3.0 中即将发生的更改,不要使用将被移除的功能,最好也不要使用与 Vue 2 深度耦合的第三方依赖。
    • 如果项目可以等到 Q2 末:那我们建议你等等,用 3.0。

    问:以后 2.x 会咋样呢?

    答:接下来会有一个小版本(2.7)更新:

    • 将兼容的 3.x 功能反向移植回 2.x
    • 对 3.x 弃用的功能发出警告

    这是 2.x 最后一个小版本,并提供长达 18 个月的 LTS(长期支持)。即使在 LTS 结束之后,我们也会继续提供重要的安全更新。

    问:Vuex 方面有什么计划么?

    答:一方面,我们正在开发Vuex(4.0)版本,其 API与 当前版本(3.0)完全相同,但与 Vue 3 兼容。我们力求向下兼容,让用户可以在 Vue 3 项目中继续使用现有 Vuex 代码。

    另一方面,我们也在尝试新的设计,更多的利用 Vue 3 的响应式 API,也让 Vuex API 不那么冗长。 这个新版本暂定为“ vuex-next”,也就是 5.0。 眼下,我们只是在进行早期探索,最早也要到 2020 年第三季度才会发布。

    2020 一季度计划

    • 3.0 SSR
    • 3.0 迁移
      • 升级向导(施工中)
      • 2.x 兼容版本
      • 迁移工具
    • 3.0 框架
      • router(施工中)
      • Vuex(施工中)
      • 测试工具(施工中)
      • JSX babel 插件(施工中)(我以为不会有这个东西了呢)
      • CLI
      • Devtools
      • 其它(虽然最后三个没标施工中,不过我觉得多半也是在施工中咯)
    • 3.0 beta
      • Q1 末发布!
      • 3.0 核心现在其实已经完成了,我们希望 API 到这个时候也能稳定下来。
      • 我们还需要更多的时间才能更新周边的库和工具。 如果您的使用场景对 router 和 vuex 没有硬性要求,这个时候就可以开始使用 3.0 了,但最好是非关键性应用程序。

    2020 二季度计划

    • 继续之前未完成的 3.0 框架工作
    • 季度中,发布 3.0 RC
      • 冻结 API,不再有重大变化。进入 RC 之前,所有涉及到重大变更的 RFC 都要定案。
      • 全家桶能够和 3.0 版本协同工作。
      • 3.0 版本就绪,此阶段基本可用。仍然会有一些小错误和框架集成问题,在 RC 阶段都会慢慢被解决掉。
    • 3.0 发布管理
      • 回归测试
      • 自动化每晚发布
      • 正式确定版本生命周期
    • 3.0 IE11 兼容性版本
    • 3.0 官方正式版

    2020 三季度计划

    发布 2.7 版本

    • 反相迁移 3.x 功能到 2.x
    • 对 3.x 中弃用的功能发出警告
    • 2.x 最后的小版本,LTS
  • 迎接 Vue 3.0

    迎接 Vue 3.0

    思否(SegmentFault)去年引入了新的运营合伙人,大张旗鼓,计划重新梳理视频教程体系。第一个举措就是推出新系列:思否编程公开课。这个系列的优势在于结合社区运营的知识与一线讲师的实战能力:即社区寻找大家关心的话题,请相关领域的讲师来讲解,达到受众明确、内容扎实的目标。

    很高兴能够得到邀请,做了一期《迎接 Vue 3.0》,我也趁机深入了解了一把 Vue 3.0。

    Vue 3.0 原计划 2019 年发布,但是开发过程有些波折,一些早期的设计被放弃了,因为不够好;引入了新的更好的设计,于是延期至今,仍然是 alpha 版。在新的设计下,Vue 3.0 更快,快到不需要时间切片;而且还能基本保持与 2.x 版本的兼容。

    至于新增的 Compisition API,其实是选修课,类似 Async 之于 Promise。有了它,我们能更好的复用代码、维护代码;不用它,也不耽误我们享受其它升级带来的便利。

    其实看过很多 Vue 3.0 的东西之后,我越发感激开发团队为这个框架做得一切,越发感激开源文化为我们带来的新世界。

    我备课一向认真充分,所以讲课的内容应该是现在最新最全面的,欢迎大家围观:【思否编程公开课】迎接Vue 3.0

    (更多…)
  • 在 Chart.js 的线图里增加竖线

    在 Chart.js 的线图里增加竖线

    我经常使用 Chart.js 生成图表,无它,名字好记+免费+持续更新。现在主要基于 Vue 开发项目,所以经常使用 vue-chart.js。前阵子遇到一个需求:

    1. 把一组数据画成线图
    2. 用户可以任意点击时间
    3. 用数据生成饼图

    那么就需要在线图中画一条竖线,标识出当前时间点。本以为这个需求不复杂,没想到不仅 Chart.js 不支持,包含这个功能的插件因为 Chart.js 升级的关系,暂时没法用。所以只好自己实现。

    (更多…)
  • Intersection Observer 笔记

    Intersection Observer 笔记

    有时候我们需要根据一个元素的位置来修改它的属性,比如图片的 lazyload,比如视频离开视窗之后停止播放。

    以前的做法通常是:

    1. 侦听 window.scroll 事件
    2. scroll 触发,遍历每个要检查的 DOM Element,执行 .getBoundingClientRect() 取出它的 widthheighttopleft,然后根据 viewport 和宽高 scrollTop scrollLeft 计算对象是否应该出现
    3. 然后做处理

    这样做会产生一些问题:

    1. 如果漏掉移除侦听器,可能造成内存泄漏
    2. 不同组件之间,很难共享侦听器
    3. 每一次都计算所有 Element,成本很高

    于是现在我们有了 Intersection Observer,专门用来观察一个 Element 是否出现在 viewport 或者父容器里。它可以很好的解决这些问题:

    1. API 更清晰
    2. 逻辑原生,速度更快,消耗更少
    3. 可以自定义阈值,更加可控

    关于 Intersection Observer 的详细知识,建议大家认真阅读 MDN – Intersection Observer,我就不抄文档了。

    使用 Intersection Observer 大体上分为三步:

    1. 声明一个 Intersection Observer 实例,这一步最关键的是要确定显隐依据哪个元素,也就是 root
    2. 将需要检查的元素加入侦听队列
    3. 在回调函数里处理元素状态

    写成代码大概是这样的:

    // 声明一个实例
    // 因为我的视口即当前 viewport,所以这里不需要 `options`
    const observer = new IntersectionObserver(entries => {
      // 遍历所有实例,如果它显示出来,即 intersectionRatio 显示比例大于 0
      // 那么就让它 `dispatch('visible')`
      entries.forEach(({target, intersectionRatio}) => {
        const event = new CustomEvent('visible', {
          detail: {
            isVisible: intersectionRatio > 0,
          },
        });
        target.dispatchEvent(event);
      });
    });
    
    // 然后可以在 Vue 里侦听这个事件
    export default {
      template: '<div @visible="onVisible"></div>',
      mounted() {
        observer.observe(this.$el);
      },
      beforeDestroy() {
        observer.unobserve(this.$el);
      },
    }

    Intersection Observer API 公布一段时间之后,又进行了升级,现在支持更丰富的参数,比如我们可以定义一个函数去判断更复杂情况下的显示状态。不过大部分场景下,我们并不需要很精准的判断,所以我觉得这个只是保障选择的机会。


    参考阅读:

    Proposed Updates for Intersection Observer

  • Chat idea:记一次 Firefox 下 Vue 带来的性能危机的解决

    Chat idea:记一次 Firefox 下 Vue 带来的性能危机的解决

    前两天遇到一个问题:我厂的一个产品在 Firefox 下,可能发生因为 CPU 占用过高而卡死的情况。这个问题在测试环境不复现,在 Chrome下基本上也不会复现。

    因为我厂老板是这个产品的主要用户,这个 bug 让我倍感压力,但一直没有解决它的好办法。终于有一天,在某台生产机上调试另外一个 bug 的时候,我终于发现了稳定复现这个 bug 的方式。

    接下来就是几个小时的 debug,然后发现问题所在,然后解决问题,然后发现解决方案不理想,于是寻求新的解决方案,然后找到新的 API,最终彻底的解决这个问题。

    接下来我就分享这个过程,读完整篇文章当中你将学会:

    1. 使用开发者工具查找性能问题
    2. 不断切分,缩小问题范围
    3. 理解 Vue 响应式原理分析问题根源
    4. 修复问题并验证
    5. 新的解决方案 Intersection Observer
    6. 解决问题并上线

    目标读者:

    1. 中级开发者
    2. 熟悉原生 JS

    大家觉得这个 idea 如何?请留言告诉我。不出意外的话这将是我下个月的 gitchat 内容。


    有同学在 Drift 里留言,这里更新回答一下:这篇文章最后没写,因为当时 GitChat 的编辑不感兴趣,所以就放弃了。将来有机会会写。

  • Chat Idea:扫雷网页版实战

    Chat Idea:扫雷网页版实战

    最近最常玩的游戏是扫雷。年纪大了,干什么时候都先考虑成本,游戏也是如此。扫雷的成本最低,倒不是说购买成本,而是启动、游戏、退出之类的成本。

    可惜的是,经典版扫雷已经从 Windows 10 里移除了,现在只能通过 Windows 应用商店装一个很复杂的扫雷游戏,花样多了很多,却并不好玩。所以我现在多半玩网页版。

    玩着玩着,出于程序员的本能,我就开始考虑如何写这个游戏,逻辑不算复杂,功能点也不多,好像蛮适合做成“实战派”教程的,比如用 Grid 写界面,项目结构就用 Vue CLI 3 吧,然后部署的话前端纯静态就够了。

    那么就愉快的决定了吧,把这个项目做出来,把中间需要的知识,用到的技能、工具,可能会遭遇的问题记下来分享出来,写成一篇文章,分享出去。读完整篇文章,你将学会:

    1. 使用 Vue CLI 3 搭建项目
    2. 使用 CSS Flex + Grid 完成页面布局
    3. 扫雷游戏的逻辑
    4. 使用 Vue 完成游戏逻辑
    5. 记录成绩
    6. 部署和分享

    目标读者:

    1. 初级开发者,能看到一个项目的成型
    2. 希望了解现代化前端框架、工具链