精华内容
下载资源
问答
  • 在今年2020的5月28日,Vue.js的作者尤雨溪公布了Vue3的整个设计过程,让我们来了解一下吧。 简单的来说,这个框架的版本更新一定是为了弥补前一个版本的不足之处,回想一下Vue2的出现也已经有四年之久了,尤大的...

    随着前端框架的快速更新迭代,现在的主流前端框架之一Vue.js迎来了它的新版本3.0。在今年2020的5月28日,Vue.js的作者尤雨溪公布了Vue3的整个设计过程,让我们来了解一下吧。

    在这里插入图片描述
    简单的来说,这个框架的版本更新一定是为了弥补前一个版本的不足之处,回想一下Vue2的出现也已经有四年之久了,尤大的团队也一直在研究新的版本的Vue,也就是Vue3。

    翻阅了一下他们的Vue3设计过程可以了解到版本更新的原因有以下两点:

    1. 现在的主流浏览器对 JavaScript 语言已经有了非常好的支持,其中包括了后来ES6更新的语法,而Vue2使用的大多都是ES6之前的语法,所以现在可以通过利用新的语法对Vue框架进行更新,以提高性能
    2. Vue2代码库中的设计和体系架构存在一定的问题,所以不得不对其进行更正

    那么Vue3到底更新了什么呢?它有哪些新的特性?它相对于Vue2的优势是什么?Vue3如何进行使用?

    别急,本文就将带着大家提前体验一下Vue3,以上的问题也会一一得到解答,大家也可以从中感受一下Vue3的魅力。

    • 公众号:前端印象
    • 不定时有送书活动,记得关注~
    • 关注后回复对应文字领取:【面试题】、【前端必看电子书】、【数据结构与算法完整代码】、【前端技术交流群】

    在这里插入图片描述

    一、Vue3的亮点

    在体验Vue3之前,我们先来了解一下Vu3到底有哪些亮点之处

    总共有6大两点:

    1. Performance(性能比vue2的runtime快2倍左右)
    2. Tree shaking support(按需打包模块)
    3. Better TypeScript support(更好的TS代码支持)
    4. Composition API(组合API)
    5. Custom Renderer API(自定义渲染API)
    6. Fragment, Teleport, Suspense

    (1)Performance

    在原本的Vue2中,每次DOM某个地方需要更新都需要遍历整个虚拟DOM,然后判断哪个地方需要进行更新,然后再重新渲染。而Vue3选择了一种新的渲染策略,即采用某些方式使得每次需要更新DOM时,无需遍历整个虚拟DOM树就可以检测到改变而进行DOM更新。

    (2)Tree shaking support

    这个就时为了实现按需打包,我们知道Vue框架里有很多的API和模块,但是一个项目中不可能用到所有的API和模块,所以该功能就可以实现在打包时去除掉Vue中没有被用到的模块和API,使得整个项目大小大幅度减小。

    根据官方的说法,Vue3如果只写入了一个 Hello World,即没有用到任何的模块API,打包后的大小大约为 13.5kb;若用到了所有的Vue3所有的模块,打包后的大小也就只有大约 22.5kb;而Vue2若只写入了 Hello World,并没有用到任何的模块API,打包后的大小大约为 32kb 左右,这就是因为Vue2中没有 Tree shaking 的原因。

    从中可以看出,Vue3比Vue2更轻量。

    (3)Better TypeScript support

    为了更好的用户使用,Vue3使用了TS重新对Vue框架进行了重写,增加了对TS更好的支持。

    (4) Composition API

    Composition API是为了解决原本Vue项目中代码逻辑分散而导致不易维护的问题

    首先先来看一个图
    在这里插入图片描述
    这幅图里颜色相同的区域表示的是实现同一个功能的代码区域

    图中左侧的是Vue2的一个API,叫做 Options,就是我们代码中的 datamethodsmounted ……这些存储数据或方法的对象

    我们都知道,在大的项目中,我们要实现一个组件的完整功能,需要上百甚至上千行代码。例如,我们要做一个轮播图组件,现在把图中左侧这一列图像看成是轮播图组件的代码,假设这里有1000行代码。

    首先我们在 methods 里写了实现轮播功能的方法,然后在 mounted 里写上在进入页面时自动开启轮播功能的代码,此时又想起来应该加一个功能,在鼠标移入该组件时应暂停轮播,所以又在 methods 里新增了一个方法,如图
    在这里插入图片描述
    这时你就会有这种感受,仅仅为了实现一个轮播的功能,却在这个页面中的不同地方写了不同的代码,那这样维护起来就特别的麻烦了,假设你的轮播功能出bug了,你需要排查问题,这时你先检查 实现轮播功能的代码 有无问题,然后又往下翻几百行代码找到 鼠标移入暂停轮播的代码,检查一下是否有问题,再又往下翻几百行代码找到 进入页面开启轮播的代码是否又问题。最终一顿分析才能查出bug。

    这样一来,代码逻辑在页面中比较分散,很难维护,所以Vue3舍弃了这种 Options API,而换用 Composition API,也就是图中右侧的部分。

    我们来看一下,刚才举的例子如果换用 Composition API 会时什么样
    在这里插入图片描述
    所有实现轮播这一功能的代码都放在一起,也就自然方便了维护

    (5) Custom Renderer API

    Custom Renderer API 也算是Vue3一个很不错的亮点了,它的作用就是将我们的代码绘制到 canvas 画布上

    (6) Fragment

    Vue3实现了不再限于模板中的单个根节点

    在Vue2中大家应该遇到过这样的情况
    在这里插入图片描述
    这个报错的原因是因为,Vue2要求组件模板中只能有一个根节点,而不可以有多个根节点,如图
    在这里插入图片描述
    图中这种情况就是有两个根节点,所以会报错。所以我们可以通过给这两个标签外部加一个节点来解决报错问题,如图
    在这里插入图片描述
    这样就不会在报错了,但有时会觉得这样特别麻烦,所以Vue3解决这个报错问题,实现了模板中不限于单个根节点,即即使有多个根节点也不会报错

    二、Vue3的性能

    在Vue3中,重写了虚拟dom的实现,并且针对编译模板进行了优化。

    在上面我们讲到了,在Vue2中,每次更新dom都需要重新遍历整个虚拟dom树,检测到变化点再去做相应的更新。但是Vue3在每次更新dom时就不需要遍历整个虚拟dom树了,这是为什么呢?

    这里先放上两个网址,分别可以查看到Vue2和Vue3的模板编译是如何的:

    Vue的渲染过程是先将html模板生成一个 render 函数,然后再根据该 render 函数进行渲染的,我们首先来看一下Vue2的模板编译情况
    在这里插入图片描述
    图中左侧部分就是我们平时写的html模板,右侧部分则是该html模板编译后生成的 render 函数

    接下来我们再来看一下Vue3的模板编译情况是如何的
    在这里插入图片描述
    很明显的可以看到,对比Vue2的 render 函数,在图中的第7行代码中多出了一个数字 1/* TEXT */,这是针对html模板打上了一个标记,告诉程序这个位置的数据是动态的(html模板中的{{ msg }}是可能会改变的,是一个动态的数据),所以之后如果要更新dom,就会针对打上标记的位置进行遍历检测。

    现在我们再在html模板上写上一个静态的数据,看看它是如何编译模板的
    在这里插入图片描述

    我们可以看到,我先给最外部的 div 加上了一个动态的 class 属性,即:class="isShow",所以编译后的 render 函数中的第11行代码中,有一个数字 9 、 注释 /* TEXT, PROPS */ 以及 ["class"],表示html模板该处的 text文本部分是动态的,属性 class 也是动态的,所以在后面更新dom时,会对该处的这两个值进行遍历检测;另外我们给属性name 赋值了 box,该值是一个静态固定的值,所以在图中右侧的 render函数中我们并没有看到对其有任何的标记,所以在之后更新dom时,会自动忽略该处的值。

    这就是Vue3通过标记来追踪动态数据的绑定,从而节约遍历虚拟dom的大部分开学。

    结合官方的说法,Vue3比Vue2的页面渲染速度提升了1.3倍~2倍,SSR(服务器渲染)速度提高了2倍~3倍

    这里放上两者性能的对比图
    在这里插入图片描述

    三、升级Vue3

    虽然目前为止Vue3还未正式发布,但我们已经可以提前体验Vue3了,为了更好地进行版本的迭代更新,Vue3对Vue2进行了很大程度的兼容,并且还提供了一个版本升级工具,可以将原本的Vue2项目很好的升级到Vu3。接下来我给大家介绍一下升级Vue3的步骤

    (1)创建Vue2项目

    我们先通过 vue-cli脚手架的 vue create 项目名 来创建一个 vue2项目,这里建议大家在创建时把 vue-routervuex 一并安装上,因为等会在升级时,会把这两个一并升级,因此代码会有所变化。
    在这里插入图片描述

    (2)将Vue2升级成Vue3

    那么我们现在只需要在原来的 vue项目目录下通过命令 vue add vue-next 来将Vue2升级成Vue3
    在这里插入图片描述
    在升级之前,我先记录一下几个文件的代码,可以方便我们看看升级前和升级后的差别

    • Vue2的 main.js 文件
      在这里插入图片描述
    • Vue2的 vue-routerindex.js 文件
      在这里插入图片描述
    • Vue2的 vuexindex.js 文件
      在这里插入图片描述

    稍微等待一下,Vue3就升级成功了,结果如图
    在这里插入图片描述
    那么此时我们来看看升级后的Vue文件有哪些变化

    • Vue3的 main.js 文件
      在这里插入图片描述
    • Vue3的 vue-routerindex.js 文件
      在这里插入图片描述
    • Vue3的 vuexindex.js 文件
      在这里插入图片描述

    对比一下各个文件升级前和升级后的区别,我们可以很明显地看到:

    Vue2的文件中都是 import Vue from 'vue' 导入了整个Vue,也就是把所有的模块API都导入了,但是用到的API可能就那么几个,所以这非常影响性能

    Vue3的文件都是将用到的Vue中的模块API单独地导出,而不是导入整个Vue,类似图中的 import { createApp } from 'vue' ,这样就跟吃自助时吃多少拿多少的道理一样,非常得节省代码性能的消耗。

    到这里,Vue3就算已经升级成功了,接下来我们就来体验一下Vue3的一些新特性把。

    四、体验Vue3新特性

    这里主要是来体验一下 Composition API的,首先了解一下 Composition API新特性的入口—— setup()函数,该函数是为组件提供的新属性。

    上面说了,这个API主要就是为了整合代码,使得为了实现相同功能的代码集中在一起便于维护查看,我们来用一个简单的例子来感受一下

    我们要实现以下这个功能
    在这里插入图片描述
    首先看看在Vue2里是如何实现的

    <template>
        <div>
            <div>{{ count }}</div>
            <button @click="add">增加</button>
        </div>
    </template>
    
    <script>
        export default {
            name: "demo",
            data() {
                return {
                    count: 0
                }
            },
            methods: {
                add() {
                    this.count ++
                }
            }
        }
    </script>
    

    我们可以看到,首先数据 count和 方法 add 是分开的,分别分布在 data 属性 和 methods 属性中的,这也就是证明了,实现一个功能时,代码时分开的,如果这个组件里有很多很多功能,就会比较难找了。

    接下来我们再来看一下在Vue3中是如何实现这一功能的吧

    <template>
    
      <div>
          <div>{{ count }}</div>
          <button @click="add">增加</button>
      </div>
    
    </template>
    
    <script>
    // 导入ref函数
    import {ref} from 'vue'
    
    function increase() {
    	// 声明响应式数据count,值为0
        const count = ref(0)
        // 创建方法add
        const add = () => {
            count.value ++
        }
        // 导出数据和方法,便于外界访问
        return {
            count,
            add
        }
    }
    
    export default {
      name: 'demo',
      setup() {
      	  //调用increase函数,并获取 count 和 add
          let {count, add} = increase()
          
          //return出需要被访问的值和方法
          return {
              count,
              add
          }
      }
    }
    </script>
    

    Vue3中没有再使用 data 属性,而是通过使用vue中的 ref()函数来命名响应式数据的,ref()函数返回的是一个对象,我们命名的数据是存储在这个对象的 value属性里的,如图
    在这里插入图片描述
    同样的也没有再使用 methods属性,而是直接通过 function 命名一个函数即可

    同时,为了让代码整合在一起,我们在最外部命名了一个 increase函数,里面存放了所有的数据和方法。

    在Vue3中有一个新的属性 setup(),它可以看作是一个生命周期,介于 beforeCreatecreated 之间,在这个生命周期内被 return的值和方法可以被外界访问到

    所以在代码中,我们直接调用了刚才将功能代码整合在一起的 inscrease函数,同时获取了函数内 return 的两个变量,这是因为这两个变量是需要被访问的,例如 <div>{{ count }}</div>中需要访问 count<button @click="add">增加</button>中需要访问 add方法。

    不要看这一个简单的功能中,似乎Vue3显得更麻烦,其实在一个功能非常多的项目中,这样的逻辑方式会使代码阅读与维护起来非常的方便。

    五、结束语

    好了,Vue3的尝鲜就到这里了,但Vue3的功能和API远远不止这些,相信大家对Composition API也有了深刻的印象,后面我会再出一篇博客来更详细地介绍这个API的更多用法,欢迎大家继续关注我~

    我是Lpyexplore,欢迎关注公众号:前端印象,了解更多前端与爬虫知识

    创作不易,喜欢的加个关注,点个收藏,给个赞~ 带你们在Python爬虫的过程中学习Web前端

    展开全文
  • Vue 3教程(适用于Vue 2用户)

    万次阅读 多人点赞 2020-06-01 14:44:40
    Vue 3尚未正式发布,但是维护者已经发布了Beta版本,供我们的参与者尝试并提供反馈。 如果你想知道Vue 3的主要功能和主要变化是什么,那么我将在这篇文章中重点介绍一下,告诉你使用Vue 3 beta 9创建一个简单的应用...

    微信搜索【前端全栈开发者】关注这个脱发、摆摊、卖货、持续学习的程序员的公众号,第一时间阅读最新文章,会优先两天发表新文章。关注即可大礼包,送某网精品视频课程网盘资料,准能为你节省不少钱!

    Vue 3尚未正式发布,但是维护者已经发布了Beta版本,供我们的参与者尝试并提供反馈。

    如果你想知道Vue 3的主要功能和主要变化是什么,那么我将在这篇文章中重点介绍一下,告诉你使用Vue 3 beta 9创建一个简单的应用程序。

    我将介绍尽可能多的新内容,包括fragments,teleport,Composition API以及其他一些晦涩的更改。我将尽力解释该功能或更改的原理。

    目录


    我们将建立什么

    我们将构建一个带有模式窗口功能的简单应用。我之所以选择它,是因为它可以方便地展示Vue 3的许多变化。

    这是该应用在打开和关闭状态下的外观,因此你可以在脑海中描绘出我们正在做什么:

    Vue 3安装和setup

    与其直接安装Vue 3,不如克隆一个项目 vue-next-webpack-preview,这将为我们提供一个包括Vue 3在内的最小的Webpack设置。

    $ git clone https://github.com/vuejs/vue-next-webpack-preview.git vue3-experiment
    $ cd vue3-experiment
    $ npm i
    

    一旦克隆好了,安装好了NPM模块,我们需要做的就是删除样板文件,然后创建一个新的 main.js 文件,这样我们就可以从头开始创建我们的Vue 3 app了。

    $ rm -rf src/*
    $ touch src/main.js
    

    现在,我们将运行开发服务器:

    $ npm run dev
    

    创建一个新的Vue 3 app

    我们启动一个新的Vue应用程序的方式改变了,我们现在需要导入新的 createApp 方法,而不是使用新的 Vue()

    我们调用这个方法,传递我们的Vue实例定义对象,并将返回对象分配给一个变量 app

    接下来,我们将在 app 上调用 mount 方法,并传递一个CSS选择器来指示我们的mount元素,就像在Vue 2中使用 $mount 实例方法一样。

    // src/main.js
    
    import { createApp } from "vue";
    
    const app = createApp({
      // 根实例定义
    });
    
    app.mount("#app");
    

    变化的原因

    与旧的API一样,我们添加的任何全局配置(plugins,mixins,原型属性等)都将永久更改全局状态。例如:

    // src/main.js
    
    // 影响两个实例
    Vue.mixin({ ... })
    
    const app1 = new Vue({ el: '#app-1' })
    const app2 = new Vue({ el: '#app-2' })
    

    在单元测试中,这确实是一个问题,因为要确保将每个测试都与上一个测试隔离是很棘手的。

    在新的API下,调用 createApp 将返回一个新的app实例,该实例不会被应用于其他实例的任何全局配置污染。

    了解更多:Global API change RFC

    添加state属性

    我们的模态窗口可以处于两种状态之一——打开或关闭。让我们用一个布尔状态属性 modalOpen 来管理它,我们将给它一个初始值 false

    在Vue 2下,我们可以通过在我们的应用实例上创建一个 data 属性并将一个对象分配给该对象来声明 modalOpen 属性,例如:

    // src/main.js
    
    const app = createApp({
      data: {
        modalOpen: false
      }
    });
    

    不再允许这样做。相反,必须为数据分配一个返回状态对象的工厂函数。

    // src/main.js
    
    const app = createApp({
      data: () => ({
        modalOpen: false
      })
    });
    

    变化的原因

    使用对象而不是工厂函数来存储数据的优点是,首先,它在语法上更简单;其次,你可以在多个根实例之间共享顶级状态,例如:

    // src/main.js
    
    const state = {
      sharedVal: 0
    };
    
    const app1 = new Vue({ state });
    const app2 = new Vue({ state });
    
    // 影响两个实例
    app1._data.sharedVal = 1;
    

    这种用例很少,可以使用。因为有两种类型的声明是不适合初学者的,所以决定删除这个特性。

    了解更多:Data object declaration removed RFC

    在继续之前,我们还添加一个方法来切换 modalOpen 值。这与Vue 2没什么不同。

    // src/main.js
    
    const app = createApp({
      data: () => ({
        modalOpen: true  
      }),
      methods: {
        toggleModalState() {
          this.modalOpen = !this.modalOpen;
        }
      }
    });
    

    使用一个根组件

    如果你现在进入浏览器并检查控制台,则会看到警告“Component is missing render function”,因为我们尚未为根实例定义模板。

    Vue 2的最佳实践是为根实例创建一个最小的模板,并创建一个app组件,其中将声明主app标记。

    让我们在这里也这样做。

    $ touch src/App.vue
    

    现在我们可以获取根实例来渲染该组件。区别在于,对于Vue 2,我们通常会使用render函数来执行此操作:

    // src/main.js
    
    import App from "./App.vue";
    
    const app = createApp({
      ...
      render: h => h(App)
    });
    
    app.mount("#app");
    

    我们仍然可以做到这一点,但是Vue 3有一个更简单的方法——使 App 成为根组件。为此,我们可以删除根实例定义,而是传递 App 组件。

    // src/main.js
    
    import App from "./App.vue";
    
    const app = createApp(App);
    
    app.mount("#app");
    

    这意味着 App 组件不仅由根实例渲染,而且是根实例。

    在此过程中,我们通过删除 app 变量来简化语法:

    // src/main.js
    
    createApp(App).mount("#app");
    

    现在移至根组件,让我们向该组件重新添加状态和方法:

    // src/App.vue
    
    <script>
    export default {
      data: () => ({
        modalOpen: true  
      }),
      methods: {
        toggleModalState() {
          this.modalOpen = !this.modalOpen;
        }
      }
    };
    </script>
    

    我们还为模态功能创建一个新组件:

    $ touch src/Modal.vue
    

    现在,我们将提供一个最小的模板,其中包括内容插槽。这确保了我们的模态是可重用的。稍后我们将向此组件添加更多内容。

    // src/Modal.vue
    
    <template>
      <div class="modal">
        <slot></slot>
      </div>
    </template>
    

    多根模板

    现在让我们为我们的根组件创建模板。我们将创建一个按钮来打开模态,它将触发 toggleModalState 方法。

    我们还将使用我们刚刚创建的modal组件,它将根据 modalState 的值来渲染。让我们也在槽中插入一段文字作为内容。

    // src/App.vue
    
    <template>
      <button @click="toggleModalState">Open modal</button>
      <modal v-if="modalOpen">
        <p>Hello, I'm a modal window.</p>
      </modal>
    </template>
    <script>
    import Modal from "./Modal.vue";
    export default {
      components: {
        Modal
      },
      ...
    }
    </script>
    

    注意这个模板有什么奇怪的地方吗?再看一遍。

    没错——有两个根元素。在Vue 3中,由于有了一个叫做片段(fragments)的功能,它不再强制要求有一个单一的根元素!

    使用Composition API进行重构

    Vue 3的旗舰功能是Composition API。这个新的API允许你使用 setup 功能而不是使用添加到组件定义对象的属性来定义组件功能。

    现在,让我们重构App组件以使用Composition API。

    在解释代码之前,请清楚我们所做的只是重构——组件的功能将相同。还要注意,模板没有更改,因为Composition API仅影响我们定义组件功能的方式,而不影响我们渲染它的方式。

    src/App.vue

    <template>
      <button @click="toggleModalState">Open modal</button>
      <modal v-if="modalOpen">
        <p>Hello, I'm a modal window.</p>
      </modal>
    </template>
    <script>
    import Modal from "./Modal.vue";
    import { ref } from "vue";
    export default {
      setup () {
        const modalState = ref(false);
        const toggleModalState = () => {
          modalState.value = !modalState.value;
        };
        return {
          modalState,
          toggleModalState
        }
      }
    };
    </script>
    

    setup 方法

    首先,请注意,我们导入了 ref 函数,该函数允许我们定义响应式变量 modalState。此变量等效于this.modalState

    toggleModalState 方法只是一个普通的JavaScript函数。但是,请注意,要更改方法主体中的 modalState 值,我们需要更改其子属性 value。 这是因为使用 ref 创建的响应式变量被封装在一个对象中。这对于保留它们的响应式是非常必要的,因为它们在被传递的过程中会被保留下来。

    最后,我们从 setup 方法返回 modalStatetoggleModalState ,因为这些是在呈现模板时传递给模板的值。

    变化的原因

    请记住,Composition API并不是更改,因为它纯粹是可选的。主要动机是允许更好的代码组织和组件之间的代码重用(因为mixin本质上是一种反模式)。

    如果你认为在这个例子中重构App组件以使用Composition API是没有必要的,那你的想法是正确的。但是,如果这是一个更大的组件,或者我们需要与其他组件共享其功能,那么你就会发现它的用处。

    Teleporting content

    如果你曾经创建过模态功能,你会知道它通常被放置在关闭的 </body> 标签之前。

    <body>
      <div>
        <!--main page content here-->
      </div>
      <!--modal here-->
    </body>
    

    这样做是因为模式通常具有覆盖页面的背景,要使用CSS来实现,您不需要处理父元素定位和z-index堆栈上下文,因此最简单的解决方案是将模式放在DOM的最底部。

    但这在Vue.js中产生了一个问题,它假定UI将作为一个单一的组件树来构建。为了允许将树的片段移动到DOM中的其他位置,在Vue 3中添加了一个新的 teleport 组件。

    要使用teleport,首先要在页面上添加一个元素,我们要将模态内容移动到该页面。我们将转到 index.html,并将ID为 modal-wrapperdiv 放在Vue的安装元素旁边。

    index.html

    <body>
      ...
      <div id="app"></div><!--Vue mounting element-->
      <div id="modal-wrapper">
        <!--modal should get moved here-->
      </div>
    </body>
    

    现在,回到 App.vue,我们将模态内容包装在 teleport 组件中。我们还需要指定一个 to 属性,为该属性分配一个查询选择器,以标识目标元素,在本例中为 #modal-wrapper

    src/App.vue

    <template>
      <button @click="toggleModalState">Open modal</button>
      <teleport to="#modal-wrapper">
        <modal v-if="modalOpen">
          <p>Hello, I'm a modal window.</p>
        </modal>
      </teleport>
    </template>
    

    就是这样,teleport 中的任何内容都将渲染在目标元素中。

    Emitting 和 event

    现在,让我们在modal中添加一个按钮,让它可以被关闭。要做到这一点,我们要在modal 模板中添加一个按钮元素,并添加一个点击处理程序,该处理程序会发出一个 close 事件。

    src/Modal.vue

    <template>
      <div class="modal">
        <slot></slot>
        <button @click="$emit('close')">Dismiss</button>
      </div>
    </template>
    

    然后,该事件将由父组件捕获,并将切换 modalState 的值,从逻辑上将其设置为 false 并导致窗口关闭。

    src/App.vue

    <template>
      ...
        <modal 
          v-if="modalOpen" 
          @click="toggleModalState"
        >
          <p>Hello, I'm a modal window.</p>
        </modal>
      </teleport>
    </template>
    

    到目前为止,此功能与Vue 2中的功能相同。但是,现在在Vue 3中,建议您使用新的 emits 组件选项显式声明组件的事件。就像props一样,你可以简单地创建一个字符串数组来命名组件将发出的每个事件。

    src/Modal.vue

    <template>...</template>
    <script>
    export default {
      emits: [ "close" ]
    }
    </script>
    

    变化的原因

    想象一下,打开别人写的组件的文件,看到它的prop和event明文声明。马上,你就会明白这个组件的界面,也就是它要发送和接收什么。

    除了提供自说明代码外,你还可以使用事件声明来验证你的事件有效载荷,虽然我在这个例子中找不到理由来验证。

    了解更多:Emits Option RFC

    样式插槽内容

    为了使模态可重用,我们提供了一个内容插槽。让我们开始通过为组件添加 style 标签来为内容设置样式。

    在我们的组件中使用 scoped CSS是一种很好的做法,以确保我们提供的规则不会对页面中的其他内容产生意外影响。

    让我们把任何被放入插槽中的段落文字变成斜体。要做到这一点,我们将使用 p 选择器创建一个新的CSS规则。

    src/Modal.vue

    <template>...</template>
    <script>...</script>
    <style scoped>
      p {
        font-style: italic;
      }
    </style>
    

    如果你尝试一下,你会发现这一点并不奏效。问题是,在编译时,当插槽内容仍属于父对象时,Scoped styling是在编译时确定的。

    Vue 3提供的解决方案是提供一个伪选择器 ::v-slotted(),允许你在提供插槽的组件中使用范围化规则来针对插槽内容。

    这是我们的用法:

    <style scoped>
      ::v-slotted(p) {
        font-style: italic;
      }
    </style>
    

    Vue 3还包含了其他一些新的Scoped Styling选择器:::v-deep::v-global,你可以在这里了解更多:Scoped Styles RFC

    其他改变

    好吧,这就是我可以在一个简单示例中涵盖的所有新功能。主要的我基本都有了,但这里有一些我认为很重要的,在总结文章之前,我觉得足够重要,可以自己研究一下。

    添加的:

    移出的:

    更改的:

    关于Vue Router也有各种变化,但我将专门用一篇文章来介绍这些变化!


    本文首发于公众号 《前端全栈开发者》,私信回复:大礼包,送某网精品视频课程网盘资料,准能为你节省不少钱!

    展开全文
  • vue2与vue3的区别

    千次阅读 2020-09-25 17:13:28
    Vue2和Vue3开发组件有什么区别 vue2和vue3双向数据绑定的区别 总结: 1. vue2和vue3双向数据绑定原理发生了改变 vue2 的双向数据绑定是利用ES5 的一个 API Object.definePropert()对数据进行劫持 结合 发布订阅模式...

    参考文档:

    Vue2和Vue3开发组件有什么区别

    vue2和vue3双向数据绑定的区别

    总结:

    1. vue2和vue3双向数据绑定原理发生了改变

    vue2 的双向数据绑定是利用ES5 的一个 API Object.definePropert()对数据进行劫持 结合 发布订阅模式的方式来实现的。

    vue3 中使用了 es6 的 ProxyAPI 对数据代理。

    相比于vue2.x,使用proxy的优势如下

    1. defineProperty只能监听某个属性,不能对全对象监听
    2. 可以省去for in、闭包等内容来提升效率(直接绑定整个对象即可)
    3. 可以监听数组,不用再去单独的对数组做特异性操作 vue3.x可以检测到数组内部数据的变化

    2. 默认进行懒观察(lazy observation)。

    在 2.x 版本里,不管数据多大,都会在一开始就为其创建观察者。当数据很大时,这可能会在页面载入时造成明显的性能压力。3.x 版本,只会对「被用于渲染初始可见部分的数据」创建观察者,而且 3.x 的观察者更高效。

    3. 更精准的变更通知。

    比例来说:2.x 版本中,使用 Vue.set 来给对象新增一个属性时,这个对象的所有 watcher 都会重新运行;3.x 版本中,只有依赖那个属性的 watcher 才会重新运行。

    4. 3.0 新加入了 TypeScript 以及 PWA 的支持

    5.vue2和vue3组件发送改变

    具体参考Vue2和Vue3开发组件有什么区别

    展开全文
  • Vue 3 开发文档

    千次阅读 多人点赞 2020-07-28 19:49:31
    博客的边界:本博客只会带来 Vue 3 新增内容的整理文档(经过验证的) 重点内容: Vite Composition API 新的响应式机制 计算属性和侦听器 利用 vite 创建下一代的 Vue 项目 两个重要的点: Vue CLI v4.5 之上...

    本博客会长期更新(在 Vue 的中文官方文档没有发布前)。

    博客的边界:本博客只会带来 Vue 3 新增内容的整理文档(经过验证的)


    重点内容:

    • Vite
    • Composition API
    • 新的响应式机制
    • 计算属性和侦听器
    • teleport (传送)
    • Fragment(碎片)
    • 自定义事件($emit 验证)
    • 组件的 v-model 升级

    利用 vite 创建下一代的 Vue 项目

    两个重要的点:

    1. Vue CLI v4.5 之上的版本
    2. Vite

    Vue CLI

    想要构建 Vue 3.x 项目,那么需要使用 Vue CLI v4.5 之上的版本

    yarn global add @vue/cli@next
    # or
    npm install -g @vue/cli@next
    

    如果想要在现有的项目中(Vue 2.x),升级构建工具,则需要执行以下代码

    vue upgrade --next
    

    Vite

    Vite 是一个想要用来代替 webpackWeb 开发构建工具,也是官方推荐使用的构建工具,使用 vite 将脱离 webpack

    // ----------npm----------
    npm init vite-app <project-name>
    cd <project-name>
    npm install
    npm run dev
    // ----------yarn----------
    yarn create vite-app <project-name>
    cd <project-name>
    yarn
    yarn dev
    

    Composition API

    简介

    为什么会有 Composition API

    创建Vue组件使我们能够将接口的可重复部分及其功能提取到可重用的代码段中。就维护性和灵活性而言,仅此一项就可以使我们的应用程序发展得相当远。

    但是,经过大量的开发经验证明,仅凭这一项可能还不够,特别是当你的应用程序变得非常大时。

    想象一下数百个组件的项目,在处理如此大的应用程序时,共享和重用代码变得尤为重要。

    摘要自:https://v3.vuejs.org/guide/composition-api-introduction.html#why-composition-api

    但是因为 Vue 2.x 中,以 组件 为最小颗粒的原因(PS:mixin 虽然可以达到复用的效果,但是它依然缺少独立性。比如:命名冲突、隐式依赖的问题),导致组件中的逻辑无法被进行 共享重用

    Composition API 概念

    Composition API组合式 API) 是一个概念,而非具体的实现。

    在组件中,实际使用 Composition API 的地方,是 setup 函数。在它内部,我们可以描述一个组件所需要的 所有逻辑

    setup

    简介

    setup 函数是Composition API 的入口函数,也是它的核心函数。

    但是要注意:setup 函数执行时,尚未创建组件实例,所以 this 中没有任何内容。这意味着,除了props,你将无法访问通过 this 来访问组件中声明的任何属性、本地状态、计算属性、方法。

    参数

    setup 函数有两个参数:

    1. {Data} props
      1. props 是响应式的
      2. 由于props是反应性的,你不能使用ES6解构,详见 对象的响应式
    2. {SetupContext} context
      1. context 是普通的 js 对象,所以他不是响应式的
      2. context 下有三个属性:
        1. attrs:包含父组件属性绑定、未识别出的为组件属性或自定义事件的事件
        2. slots:插槽
        3. emit:通知(发出的事件)

    下面是官方的示例代码:

    // Data 为  key:value 结构的对象
    interface Data {
      [key: string]: unknown
    }
    // context 为上下文,包含:
    // attrs:包含父组件属性绑定、未识别出的为组件属性或自定义事件的事件
    // slots:插槽
    // emit:通知
    interface SetupContext {
      attrs: Data
      slots: Slots
      emit: (event: string, ...args: unknown[]) => void
    }
    
    function setup(props: Data, context: SetupContext): Data
    

    可访问的组件属性

    setup被执行时,该组件实例尚未建立。如此一来,您将只能访问以下属性:

    • props
    • attrs
    • slots
    • emit

    换句话说,您将无权访问以下组件选项:

    • data
    • computed
    • methods

    模板使用 setup 中的数据

    如果setup返回对象,则可以在组件的模板中访问对象的属性(注意代码中的备注):

    <!-- MyBook.vue -->
    <template>
      <div>{{ readersNumber }} {{ book.title }}</div>
    </template>
    
    <script>
      import { ref, reactive } from 'vue'
    
      export default {
        setup() {
          // 通过 ref 或 reactive 创建响应式数据,现在你可以先不需要理解什么是 ref 和 reactive。
          // 你只需要知道此时 readersNumber 和 book 为响应式的
          const readersNumber = ref(0)
          const book = reactive({ title: 'Vue 3 Guide' })
    	 // return 的对象,可以直接在 模板中直接访问(不需要 .value)
          return {
            readersNumber,
            book
          }
        }
      }
    </script>
    

    渲染功能的实现

    setup 还可以返回一个渲染函数,该函数可以直接使用在同一作用域中(setup 函数中)声明的反应状态 :

    import { h, ref, reactive } from 'vue'
    
    export default {
      setup() {
        const readersNumber = ref(0)
        const book = reactive({ title: 'Vue 3 Guide' })
        // Please note that we need to explicitly expose ref value here
        return () => h('div', [readersNumber.value, book.title])
      }
    }
    

    this 指向问题

    setup 函数中,thisundefined 而不是 组件的引用。因为 setup 函数执行时,尚未创建组件实例。所以 thissetup 中无法正常使用。

    setup 函数和其他的 Options API 一起使用时,可能会出现无法预知的错误,所以一定要谨慎。

    生命周期钩子

    setup 中,可以通过 onX 的方式注册 生命周期钩子

    import { onMounted, onUpdated, onUnmounted } from 'vue'
    
    const MyComponent = {
      setup() {
        onMounted(() => {
          console.log('mounted!')
        })
        onUpdated(() => {
          console.log('updated!')
        })
        onUnmounted(() => {
          console.log('unmounted!')
        })
      }
    }
    

    Options API(Vue 2.x) 生命周期选项和 Composition API(Vue 3.x) 之间的映射

    • beforeCreate ->使用 setup()
    • created ->使用 setup()
    • beforeMount -> onBeforeMount
    • mounted -> onMounted
    • beforeUpdate -> onBeforeUpdate
    • updated -> onUpdated
    • beforeUnmount -> onBeforeUnmount
    • unmounted -> onUnmounted
    • errorCaptured -> onErrorCaptured
    • renderTracked -> onRenderTracked
    • renderTriggered -> onRenderTriggered

    提供 provide / 注入 inject

    首先必须要明确:提供 provide / 注入 inject 的功能都只能在 setup 函数中进行使用。

    如果你希望在 父组件 中提供一个值,然后在 子组件 中可以使用。那么你就应该考虑 提供 provide / 注入 inject 的功能。

    // 父组件
    setup() {
        // 为子组件提供一个值,并且这个值是响应式的(ref)
        // 则代表:子组件可以修改该值(book.value),并且会 响应式的 作用于父组件的变量中
        let book = ref('父组件的book');
        // 为子组件提供一个值,并且这个值不是响应式的
        // 则代表:子组件获取到了 非响应式的 数据。
        // 此时:子组件可以通过 ref(inject('book', '默认值')) 的方式,把该数据变为 响应式的 ,但是要注意,此时的响应式仅在 子组件中生效
        let book = '父组件的book';
        provide('book', book);
        return {
            book,
        };
    },
        
    // 子组件
    setup () {
        // 利用 inject 函数,获取父组件提供的值
        let book = inject('book', '默认值');
        // 利用 inject 函数,获取父组件提供的值,同时把它变为响应式的。但是要注意,此时的响应式仅在 子组件中生效
        let book = ref(inject('book', '默认值'))
    }
    
    

    新的响应式

    代理对象

    当我们把 JavaScript 对象作为 data 选项传递给 Vue 实例的时候,Vue 会遍历对象的所有属性,并且会把它们转化成带有 gettersetter 函数的 Proxies(代理对象)

    同时为了兼顾低版本的浏览器,对于较久的版本,Vue 依然使用 Object.defineProperty 来进行支持。

    两者之间在使用中并没有区别,只不过 代理对象 会提供更好的性能。

    响应式数据的声明 - reactive 函数

    想要在 setup函数中 创建响应式数据,可以使用 reactive方法(注意:需要主动导入 reactive

    <template>
      <div>
      	<h1>Vue 3</h1>
      	<button @click="state.count++">count is: {{ state.count }}</button>  
      </div>
    </template>
    
    <script>
    import { reactive } from 'vue';
    export default {
      name: 'HelloWorld',
      setup() {
         // 创建的响应式数据对象
        const state = reactive({
          count: 0,
        });
        return {
          // 直接放回创建的响应式对象
          state,
        };
      },
    };
    </script>
    
    

    注意:Vue 3 中并没有取消 data 声明,也就是说,我们依然可以使用 data 函数来创建响应式数据。以下两种写法在响应式效果 中等效

    // setup() {
      //   const state = reactive({
      //     count: 0,
      //   });
      //   return {
      //     state,
      //   };
      // },
      // 效果等效
      data() {
        return {
          state: {
            count: 0,
          },
        };
      },
    

    将一个非响应式数据转化为响应式数据 - ref 函数

    Vue 3 对 ref 函数进行了改变,使 ref 具备了两种能力:

    1. 使用 ref 获取 元素 或 组件实例
    2. 可以把一个非响应式的数据改变为响应式的

    我们在这里探讨的就是 ref 函数的第二个能力:

    <template>
      <h1>Vue 3</h1>
      <button @click="count++">count is: {{ count }}</button>
    </template>
    
    <script>
    import { ref } from 'vue';
    export default {
      setup() {
        // ----- 利用 setup 函数返回 ------
        let count = 0;
         return {
          count,
        };
        // ----- 利用 reactive 函数 ------
        const state = reactive({
          count: 0,
        });
        return {
          // count 值的改变,将不会影响视图的变化,原因请查看 《对象的响应式》  
          count: state.count,
        };
        // ----- 利用 ref 函数 ------
        let count = ref(0);
        return {
          count,
        };
      }
    };
    </script>
    
    

    以上三种方式,貌似可以达到同样的效果。

    那么 ref 的作用是什么呢?再来回顾一下:ref 函数可以将一个非响应式数据转化为响应式数据。即:当数据发生了变化的时候,视图也理应发生变化。我们来看下面的代码:

    setup() {
        // ----- 利用 setup 函数返回 ------
        let count = 0;
        setTimeout(() => {
        // 视图并没有发生变化
          count = 1;
        }, 1000);
        return {
          count,
        };
        // ----- 利用 reactive 函数 ------
        et state = reactive({
          count: 0,
        });
        setTimeout(() => {
        // 视图并没有发生变化
           state.count = 1;
        }, 1000);
        return {
          count: state.count,
        };
        // ----- 利用 ref 函数 ------
        let count = ref(0);
        setTimeout(() => {
          // 访问 count 的值,需要使用 value 属性
          // 注意:在模板中,我们不需要手动写入 value
          // 视图发生了变化
          count.value = 1;
        }, 1000);
        return {
          count,
        };
      },
    

    在上面的代码中,我们通过 setTimeout 延迟 1 秒钟之后改变数据源 count 的值,从结果中,我们可以发现,只有被 ref 函数声明的 count 才会直接影响视图的变化。

    对象的响应式

    通常情况下,我们希望利用 解构赋值 的方式来获取到响应式数据:

    <template>
      <h1>Vue 3</h1>
      <button @click="count++">count is: {{ count }}</button>
    </template>
    
    <script>
    import { reactive } from 'vue';
    export default {
      setup() {
        // ----- 利用 reactive 函数 ------
        let state = reactive({
          count: 0,
        });
        let { count } = state;
        setInterval(() => {
          // 视图并没有发生变化
          count++;
        }, 1000);
        return {
          count,
        };
      },
    };
    </script>
    
    

    但是很遗憾,这种方式将会让 count 失去响应性

    如果我们想要解决这个问题,那么需要借助一个函数 toRefs。同样的,我们需要先 导入 这个函数。

    // 不要忘记,我们需要导入 toRefs
    import { toRefs } from 'vue';
    
    let state = reactive({
        count: 0,
    });
    // 借助 toRefs 函数,让数据保持响应性
    let { count } = toRefs(state);
    setInterval(() => {
        // 同样需要是使用 value 来访问到数据源
        count.value++;
    }, 1000);
    return {
        count,
    };
    

    只读的响应式数据

    有时我们希望 数据为响应式 的同时,该数据不被其他的组件所修改 (即:我们想要其他组件 享受 响应数据(refreactive )的变化,同时也想要防止其他的组件修改响应式数据),那么我们需要给其他组件 只读的响应式数据 - readonly

    <!-- state.count 发生改变,readonlyState.count 会同步跟随变化 -->
    <button @click="state.count++">count is: {{ state.count }}</button> 
    <!-- 如果想要直接修改 readonlyState.count 的值,那么会得到一个警告:Set operation on key "count" failed: target is readonly -->
    <button @click="readonlyState.count++">count is: {{ readonlyState.count }}</button>
    
    <script>
    import { reactive, readonly } from 'vue';
    export default {
    setup() {
          // 响应式数据对象 state
          const state = reactive({
            count: 0
          })
          // 只读数据 readonlyState
          // state 称为 readonlyState 源数据
          const readonlyState = readonly(state)
          return {
            state,
            readonlyState
          }
        }
    </script>
    

    这样我们就获得了一个只读的响应式数据 readonlyState 和它的源数据 state 。如果我们想要修改 readonlyState 的值,那么唯一的方式是 修改state

    对于 readonly 来说,源数据的变化会响应式的作用于 readonly

    计算属性与侦听器

    计算属性

    基本用法

    Vue 计划使用 computed 函数 来定义 计算属性 (这并不代表 Options API 被完全丢弃),看下面的示例:

    <template>
      <input type="text" v-model="str" />
      <h2>{{ comStr }}</h2>
    </template>
    
    <script>
    import { ref, computed } from 'vue';
    export default {
      setup() {
        const str = ref('Hello');
        // Vue 3 中推荐写法,完全等效于 computed 属性中函数定义
        const comStr = computed(() => str.value.split('').reverse().join(''));
        return {
          str,
          comStr,
        };
      },
      /*  Vue 2.x 的写法并没有被废弃,只是不再被推荐使用。
      以下写法完全等效于 Vue 3 中的 computed 函数 */
      computed: {
        comStr() {
          return this.str.split('').reverse().join('');
        },
      },
    };
    </script>
    
    

    set 和 get

    computed 函数 包含了 getset 方法:

    const count = ref(1)
    // 此代码等于使用了 getter 函数
    const plusOne = computed(() => count.value++)
    // 当我们获取 plusOne 的值时,等于调用了 get
    console.log(plusOne.value) // 2
    // 但是因为没有实现 setter 函数,所以无法设置新值
    // err:setter is not a function
    plusOne.value++ 
    

    我们可以使用具有 getset 功能的对象来创建可写的 ref 对象

    const count = ref(1)
    const plusOne = computed({
      get: () => count.value + 1,
      set: val => {
         count.value = val - 1;
      }
    })
    plusOne.value = 1;
    console.log(count.value); // 0
    

    此时对 plusOneset 操作会回调到 传入对象的 set 方法中。

    监听函数:watchEffect

    如果你想要监听响应式数据的变化,那么可以使用 watchEffect 函数

    watchEffect 函数 的运行时机有两个:

    1. 调用函数时,立刻运行
    2. 依赖项的数据发生变化时,会立刻运行
    const count = ref(0);
    // 立刻打印:0
    watchEffect((v) => {
        // 依赖数据发生变化时,依次打印 1.2.3.4....
        console.log(count.value);
    });
    
    setInterval(() => {
        count.value++;
    }, 1000);
    return {
        count,
    };
    

    如果你想要停止 watcher 的话,那么可以返回方法进行停止

    const stop = watchEffect(() => {
      /* ... */
    })
    
    // 调用返回的停止函数
    stop()
    

    watch

    watch API完全等同于组件 watch 属性。

    watch需要查看特定的数据源,并在单独的回调函数中应用副作用。

    默认情况下,它也是惰性的。即仅在监视的源已更改时才调用回调。

    参数:

    • {string | Function} source
    • {Function | Object} callback
    • {Object} [options]
      • {boolean} deep
      • {boolean} immediate

    监听单一的数据源变化

    watcher 的数据源可以有两种:

    1. 返回值的 getter 函数
    2. ref
    // 监听 返回值的 getter 函数
    const state = reactive({ count: 0 })
    watch(
      () => state.count,
      (count, prevCount) => {
        /* ... */
      }
    )
    
    // 监听 ref
    const count = ref(0)
    watch(count, (count, prevCount) => {
      /* ... */
    })
    

    监听多个数据源的变化

    使用数组的方式可以监听多个数据源

    watch([fooRef, barRef], ([foo, bar], [prevFoo, prevBar]) => {
      /* ... */
    })
    

    options 参数对象

    options 参数对象主要有两个属性:

    1. deep:监听对象内部嵌套值的改变。注意:你不需要制定 deep 既可以监听到 Array 的变化
    2. immediate:立刻触发回调

    teleport (传送)

    在 Vue 的技术体系中,我们一直以来都是根元素中做事情(<div id="app" ></div>),这个逻辑是没有问题的。

    但是在 Vue 3 中提出了一个新的概念 teleport

    它是一个组件,使用它可以让我们的渲染区 脱离 根元素。这也是 传送 所代表的意思:将视图传送出渲染区(同时视图将保持响应式的渲染)

    <body>
      <!-- 渲染区 -->
      <div id="app">
      </div>
      <!-- 
        转移区。
        注意:目标元素必须在组件挂在前就已经存在。
        即目标不能由组件本身渲染,并且理想情况下应位于整个Vue组件树之外。 
      -->
      <div id="endofbody"></div>
    </body>
    
    <script>
      const app = Vue.createApp({
        template: `
        <h1>根组件</h1>
        <parent-component />
      `
      })
    
      app.component('parent-component', {
        template: `
        <h2>父组件</h2>
        <teleport to="#endofbody">
          <child-component :name="name" />
        </teleport>
      `,
        data() {
          return {
            name: '张三'
          }
        },
        created: function () {
          setTimeout(() => {
            this.name = '李四'
          }, 1000)
        }
      })
    
      app.component('child-component', {
        props: ['name'],
        template: `
        <h4>被转移的子组件,它将出现在 app 之外</h4>
        <h4>同时享受响应式数据改变带来的视图变化,不信?你刷新页面,等一秒钟看一下</h4>
        <div>Hello, {{ name }}</div>
      `
      })
      app.mount('#app')
    </script>
    
    

    并且,你需要知道,传送是可以支持多个的。即:可以存在多个 teleport 组件指向同一个 目标区域

    <teleport to="#modals">
      <div>A</div>
    </teleport>
    <teleport to="#modals">
      <div>B</div>
    </teleport>
    
    <!-- 结果-->
    <div id="modals">
      <div>A</div>
      <div>B</div>
    </div>
    

    Fragment

    组件不再强制单个根元素,这个特性 Vue 3 称为 Fragment(碎片)

    以下代码可以正常运行(虽然会有 ESLint 警告)

    <template>
      <header>...</header>
      <main v-bind="$attrs">...</main>
      <footer>...</footer>
    </template>
    

    自定义事件

    Vue 3 建议对组件中所有发出的事件 emit 进行记录 emits 。如果你声明了 emits 选项,并且发送的事件没有被 emits 记录,则会收到一个警告:

    app.component('custom-form', {
        template: `
          <form>
    		<!-- 此处会收到警告:
        [Vue warn]: Component emitted event "submit" but it is neither declared in the emits option nor as an "onSubmit" prop 
    -->
            <input type="button" value="submi" @click="$emit('submit')"/>
          </form>
        `,
        emits: {
        }
      })
    

    记录的形式分为两种:

    1. 数组:如果使用数组进行记录,那么可以只可以进行声明,而不可以进行验证(参考 prop 机制)
    2. 对象:对象语法可以对 发送的事件 进行验证

    以下为对象验证:

      app.component('custom-form', {
        template: `
          <form>
            <input type="button" value="submi" @click="$emit('submit', {email: 'aa@163.com', password: 'aaa'})"/>
          </form>
        `,
        emits: {
          // 无验证
          click: null,
    
          // 为 submit 事件添加验证规则
          // 如果不符合验证规则,你会收到一个警告
          submit: ({ email, password }) => {
            if (email && password) {
              console.log('验证通过');
              return true
            } else {
              console.warn('这是一个无效的提交事件!')
              return false
            }
          }
        }
      })
    

    组件中的 v-model

    Vue2.2.0 的版本中新增了 自定义组件的 v-model2.3.0 中新增了 .sync 修饰符。 在功能上 sync 更像是 自定义组件的 v-model 的增强。

    Vue 3 中,自定义组件的 v-model 进行了进一步的增强,使其更像是 v-bind:foo.sync 的另一种写法:

    // 子组件声明
    app.component('my-component', {
      props: {
        foo: String
      },
      template: `
        <input 
          type="text"
          :value="foo"
          @input="$emit('update:foo', $event.target.value)">
      `
    })
    
    // 父组件调用
    <my-component v-model:foo="bar"></my-component>
    
    

    同时,自定义组件的 v-model 支持了 多重绑定

    // 子组件声明
    app.component('user-name', {
      props: {
        firstName: String,
        lastName: String
      },
      template: `
        <input 
          type="text"
          :value="firstName"
          @input="$emit('update:firstName', $event.target.value)">
    
        <input
          type="text"
          :value="lastName"
          @input="$emit('update:lastName', $event.target.value)">
      `
    })
    
    // 父组件调用
    <user-name
      v-model:first-name="firstName"
      v-model:last-name="lastName"
    ></user-name>
    
    展开全文
  • Vue3中的Vue Router初探

    千次阅读 2020-05-07 17:13:12
    对于大多数单页应用...Vue3中的许多更改都会稍微改变我们访问插件和库的方式,其中包括Vue Router。我们将结合使用Alpha版本的Vue Router和当前的Vue3 Alpha版本进行研究。 本文告诉你如何将Vue Router添加到Vue3...
  • Vue3新特性

    千次阅读 多人点赞 2020-03-22 14:10:48
    vue3新增了很多新的特性,目前可以使用 安装 vue-compisition-api 包进行尝鲜,vue3将会对vue2进行向下兼容,因此不必担心因为使用vue3 后 vue2的特性不能够使用 安装包、使用包 npm install @vue/composition-api -...
  • Vue3+与Vue2共存

    千次阅读 2020-05-04 21:57:53
    目前大多数新项目都会采用Vue3+进行开发,然而在公司还需要维护一些之前使用老旧版本Vue2开发的项目,此时则需要我们在电脑上安装vue2与vue3+了。 1、 先来说说npm安装命令的参数-g -g参数可以将js包进行全局安装,...
  • Vue3项目的创建 使用vue create proName vue create vue3-pro 自动下载安装包 或者 npm init vite-app vue3-pro 不会自动下载安装包 然后选中 Vue3,回车即可,自动下载安装包 ? Please pick a preset: Default ...
  • 一.vue cli2升级到vue cli3 1.先升级npm的版本 npm install -g npm 2.再卸载之前的vue cli 2.9.6 npm uninstall -g @vue/cli ...二.vue3,0版本创建项目 1、vue create myproject 2、默认选择default方...
  • 使用 @vue/cli 创建 Vue 3 项目

    千次阅读 2020-09-21 13:21:39
    vue create hello-world-vue3 选择:Default (Vue 3 Preview) ([Vue 3] babel, eslint) 运行项目: cd hello-world-vue3 npm run serve 启动 vue ui: vue ui 添加路由及缓存: 成功添加后:...
  • 带你体验Vue2和Vue3开发组件有什么区别

    千次阅读 多人点赞 2020-03-08 21:59:18
    随着Vue3的来临,很多童鞋会疑惑到底Vue3和Vue2有什么区别。
  • vue3使用vue-count-to组件

    千次阅读 热门讨论 2020-12-22 11:20:14
    数据可视化大屏开发的过程中,需要实现一种滚动数字的效果,在使用vue2时,使用vue-count-to完全没有问题,功能也比较完善(滚动时长,开始值,结束值,前缀,后缀,千分隔符,小数分隔符等等),但是在vue3中使用会...
  • Vue3中文文档

    千次阅读 2020-10-12 17:41:32
    Vue3中文文档 - vuejs https://www.vue3js.cn/docs/zh/guide/computed.html#
  • 大家都知道,现在Vue3的各个版本已经陆续发布了,并且有很多的团队已经着手各个库的开发与Vue2向Vue3的升级,我们当然也不能落后,所以赶紧将你手中的Vue2升级到Vue3,跟着本文一起学习新的API吧
  • 更新了什么还不清楚,但是告知了基于vue3.x版本的 element-plus 已经出来了。 先来上手体验一下 首先安装一个最新的@vue-cli,搭建一个vue3.x的项目,脚手架创建流程已经很简洁了,这里就不多说了。建好之后,直接...
  • Vue(二):Vue3安装

    千次阅读 2019-08-19 17:47:49
    Vue3安装 Node 版本要求 Vue CLI 需要 Node.js 8.9 或更高版本 (推荐 8.11.0+)。你可以使用 nvm 或 nvm-windows 在同一台电脑中管理多个 Node 版本。 可以在cmd命令窗口查看node.js的版本,执行node -v 开始安装,...
  • vue3 常见问题汇总

    千次阅读 2020-04-25 18:56:58
    vue3 常见问题汇总 简介:vue3 beta 已经出来一段时间了,最近刚好有时间,就练了练手,练手过程中遇到的问题,总结如下 本文 github 源码地址 下面是问题 vue3 如何注册全局组件 import { createApp } from 'vue' ...
  • Vue 3 源码公布

    千次阅读 2019-10-06 23:26:15
    10 月 5 日凌晨,Vue.js 框架的作者兼核心开发者尤雨溪公布了尚处于 Pre-Alpha 状态的 Vue 3 源码(https://github.com/vuejs/vue-next)。 (说学不动的童鞋抓紧剩余的国庆假期撸一遍源码吧 : D) 作者表示,...
  • Vue3 深度解析

    千次阅读 2019-11-27 08:26:35
    距离尤雨溪首次公开 Vue3 (vue-next)源码有一个多月了。青笔观察到,刚发布国庆期间,出现不少解读 Vue3 源码的文章。当然不少有追风蹭热之嫌,文章草草讲讲响应式原理,或者只是做了一些上层的导读,告诉读者应该先...
  • Vue数据双向绑定原理(vue2向vue3的过渡)

    万次阅读 多人点赞 2019-11-13 15:13:40
    众所周知,Vue的两大重要概念: 数据驱动 组件系统 接下来我们浅析数据双向绑定的原理 一、vue2 1、认识defineProperty vue2中的双向绑定是基于defineProperty的get操作与set操作,那么我们简单认识下...
  • 寻寻觅觅冷冷清清,凄凄惨惨戚戚。Vue 3 发布以后,最近也在学习和写一些 Vue3 的 demo 和项目,我也一直想着什么时候能在小程序里使用新特性?于是我翻遍了市面上的小程序框架,如...
  • 官方文档 vue https://cn.vuejs.org/v2/guide/vue-cli https://cli.vuejs.org/zh/ vue2 vue3 基于 vue-cli 基于 @vue/cli 初始化项目 ...
  • vue3创建项目

    千次阅读 2020-04-28 11:12:14
    vue3创建项目 vue create 项目名称 //回车 default默认配置,manually手动配置,如果选择默认一直回车即可,选择手动需要进行相应的配置如下图 根据自己项目需求选择相应的选项,空格选择,a全选 babel---...
  • Vue3 的新特性

    千次阅读 2020-07-31 17:48:26
    这意味着 Vue3 内核的 API 和实现已到达稳定状态,在最终版本发布前,不会提出新功能或者做重大更改。看来距离 Vue3.0 正式版与我们见面已经不远了! 那么本篇文章,就带大家来了解一下 Vue3 ,体验一下它的新特性。...
  • 使用 Vue3 开发小程序

    千次阅读 多人点赞 2020-10-09 09:23:17
    9 月 19 日凌晨,Vue3 在经过多个开发版本的迭代后,终于迎来了它的正式版本,「One Piece」的代号也昭示了其开拓伟大航路的野心。 Vue3 的新特性主要有 Composition API、Teleport、Fragments 和 <script setup ...
  • Vue 3 系列教程目录

    千次阅读 多人点赞 2020-12-02 20:29:23
    Vue3 系列教程目录 最近总是有人在后台,或者评论区问作者我啊,我想学习 Vue3 啊,我看专栏挺好的,挺贵的,免费的都挺便宜的,免费的还有很多坑,然后都在问我,有没有目录可以看下,今天呢,作者我特地为你们辛苦...
  • Vue3项目整合Electron

    千次阅读 2019-08-31 15:15:14
    Vue3项目整合Electron 第一步安装:VUE3 安装vue3脚手架 npm install -g @vue/cli 安装 yarn,并设置淘宝源 npm install -g cnpm --registry=https://registry.npm.taobao.org 设置ELECTRON_MIRROR,加速electron的...
  • vue2.x 和 vue3.x 源码编译

    千次阅读 2020-09-18 11:14:54
    vue2.x 和 vue3.x 源码编译   1. vue2.x源码编译错误解决 错误信息: error D:\Code\vue\node_modules\phantomjs-prebuilt: Command failed. 解决方案,参考log提示。 github下载,由于网络问题,zip包...
  • Vue(发音为/vjuː/,类似于view)是用于构建用户界面的渐进式框架。与其他整体框架不同,Vue从头开始设计以逐渐采用。核心库仅集中在视图层,并且易于拾取并与其他库或现有项目集成。另一方面,当与现代工具和支持...
  • vue 全局组件注册With the new versions of Vue3 out now, it’s useful to start learning how the new updates will change the way we write code. One example is the changes in the way we write our index.js...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 77,352
精华内容 30,940
关键字:

vue3

vue 订阅