分类: vue

  • Vue3 中使用 h + render 渲染组件,实现自定义弹窗功能

    Vue3 中使用 h + render 渲染组件,实现自定义弹窗功能

    Vue3 里面使用模版添加组件非常常见,不过有时候,我们不方便直接把组件写入模版。比如,最常见的情况,在用户进行一些危险的、不可逆的操作前,我们常常需要要求用户确认。要求不高的时候,可以原生 JS confirm;但是如果要求高一些,我们就希望自定义弹窗样式。

    这个时候,如果必须事先把弹窗组件放入组件模版,就会很麻烦;如果我们能像使用原生 confirm 一样,使用 if (!myConfirm(message)) return,就会好很多。

    但是我没能在 Vue 官方文档找到合适的方案,还是 GPT-4 给我提供了思路,实验之后发现效果比较理想,所以写个笔记记录一下。

    import { h, render } from 'vue';
    import { ModalsConfirm } from '#components';

    export function showConfirmModal(message: string, title = 'Confirm') {
      // 因为要等待用户操作,所以必须返回 Promise
    return new Promise((resolve) => {
        // 创建一个新节点,用来容纳 modal
    const node = document.createElement('div');
        // 使用 `h` 创建虚拟节点,其中ModalsConfirm 是做好的 Vue SFC
    const vnode = h(ModalsConfirm, {
    message,
    title,
          // `on` + `事件名称` 即事件处理函数
    onConfirm() {
    node.remove();
    resolve(true);
    },
    onCancel() {
    node.remove();
    resolve(false);
    },
    });
    document.body.appendChild(node);
        // 使用 `render` 将虚拟节点添加到 DOM 树里
    render(vnode, node);
    });
    }

    使用的时候只需要调用即可:

    function onDelete(item) {
      if (!(await showConfirmModal('are u sure?')) return;

      // 真实的删除逻辑
    }

    GPT-4 之后,在辅助开发方面的提升非常大,理解更准确,幻觉更少。大家有机会的话多试试。

  • Vue 使用 Provide/Inject 向子组件内注入数据

    Vue 使用 Provide/Inject 向子组件内注入数据

    前阵子做厂里的需求,允许用户编辑算法生成的 CSS,以便将我厂的产品应用到生产环境。我们允许用户使用可视化编辑器编辑某条特定规则,大约如下图所示:

    我们知道,CSS 规则有优先级,优先级高的规则会覆盖优先级低的规则中的同名属性;也会继承低优先级规则里没有被覆盖的属性。反应到我们的可视化编辑器里,就是:

    1. 有些属性用户不能删除,因为那是从低优先级的样式里继承来的
    2. 有些属性用户修改了也不会生效,因为会有更高优先级的规则把它覆盖掉

    所以我们希望给用户一些提示,避免他们实际操作的时候感到疑惑。那么问题来了:怎么实现呢?

    从图上可以看出,CSS 可视化编辑器挺复杂的,有些属性可以直接编辑,比如 visibility,独立生效,那随便写个 <input type="checkbox"> 就行;有些则与其它属性一起发生作用,比如 align-items,那我们就需要比较复杂的组件,里面会嵌套别的组件。

    所以一般的 v-bind 方式就不适用:我计算出优先级之后,需要传递多次才能穿透组件间的嵌套关系,太复杂,很难用。我们需要更简单的传递方案。好在 Vue 提供了 provide/inject 方式。

    Vue 官方称这个功能为“依赖注入”,我们在父组件上使用 provide 暴露一些属性,然后在子组件里用 inject 把这些属性拿进来使用。不管子组件和父组件之间嵌套了几层,都可以获取到:

    provide() {
      return {
        foo: this.foo
      }
    }
    inject: ['foo']

    用法比较简单,就这么两步,但是有一些注意事项:

    1. 注入的变量默认没有响应式,Vue 就是这么设计的,这样可以避免一些问题。如果需要响应式,那就需要传入包含响应式的变量,比如 data 或者 computed
    2. 如果你用 vue-property-decorator,那么需要用 ProvideReactiveInjectReactive
    3. 这个依赖注入和设计模式里的 DI 不是一回事,面试时不要乱讲。
    4. 不要滥用这个设计,只有不特定层级子组件需要用到属性,才这么做。

    扩展阅读:

  • 理解 Vue3 里的 defineProps 和 defineEmits

    理解 Vue3 里的 defineProps 和 defineEmits

    大家请先看这个问题:https://segmentfault.com/q/1010000041497872/a-1020000041498716,看看你们能不能给出答案。

    Vue3 增加了 Composition API,是一个很大的改进。一方面可以提升代码复用效率,另一方面通过更好的 tree-shaking,打包体积也会小很多:作为参考,前面博客中提到 mywordle.org,打包后 vendor.js 只有区区 96kB,里面可是用到了 vue3 全家桶。

    最初的 Composition API 是在 Options API 基础上改进的,不仅需要使用 setup() 函数,还要在 setup() 末尾返回所有模版需要用到的变量和函数,使用起来相当繁琐。于是后面就增加了 <script setup> 语法糖:

    1. 从生命周期来讲,相当于 created
    2. 支持顶层 await(因为实际上这还是个 setup() 函数)
    3. 所有 import 的内容、声明的变量和函数默认都返回
    4. 至少省了两层缩进

    但是由于少了 export,没法传参,也不方便暴露接口,所以作者就增加了三个工具方法:

    • defineProps
    • defineEmits
    • defineExpose

    注意,这三个工具方法只是帮助 Vue 编译器构建组件,它们不会出现在最终代码里,我们也不能预期它们会像普通函数那样工作。比如下面这段代码,就得不到常见的结果:

    const props = defineProps({
      userMenu: {
        type: Array,
        default() {
          return []
        }
      }
    })
    console.log(props) // 该对象中的 userName 总是有值
    console.log(props.userMenu) // 该对象始终是一个空数据

    因为 Vue 是 MVVM 框架,它的视图会在数据变化后自动渲染,于是通常情况下,props 里的值什么时候被填充并不重要,Vue 开发团队也不想追求 defineProps 工作的一般化。所以使用目前版本,上面这段代码,访问到的 props 是的 reactive 对象,数据被填充后就能看到 userName 里有值;而 props.userMenu 在访问时还没有被填充,所以得到的是 default() 返回的默认值,一直是空的。

    同时大家还要知道,console.log() 输出的是对象的指针,而非快照。所以里面的值只跟你展开时有关,跟运行时关系不大。

  • 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

    (更多…)
  • Chat:Vue 进阶必经之路

    Chat:Vue 进阶必经之路

    Vue 进阶必经之路

    Vue 的学习曲线平缓,入门很简单,所以后发夺人,争取到一大批支持者,我也是其中之一。但是因为隐蔽了很多细节,所以我也没少踩坑,挠头拍桌,不厌其烦。如今,我终于突破屏障,遇到大部分问题,都能举一反三,快速定位、快速解决。这段过程,难免追本溯源,穷究细节。我希望通过这次分享,把我的经验和收获传达给大家。

    面向听众:

    1. 有一定 Vue 开发经验,希望进一步提升;
    2. 平时业务代码写得多,想学习技术细节。

    写完了,不得不说,没有预先想象中写得好。原因嘛,当然是工作太忙,能够写文的时间不太够。以后还是平时多写,Chat 当汇总比较好。

    不过还是希望大家都来看,毕竟我这两年踩坑得到的 Vue 经验都在里面了。

    (更多…)