值得注意的新特性

组合式 API
Teleport
片段
触发组件选项
createRenderer API 来自 @vue/runtime-core 创建自定义渲染器
单文件组件组合式 API 语法糖 (< script setup>) 实验性
单文件组件状态驱动的 CSS 变量 (< style vars>) 实验性
单文件组件

合成型API(Composition)

1、data

Vue2采用了选项类型API(Options API),而Vue3采用的是合成型API。
旧的选项型API在代码里分割了不同的属性(properties):data,computed属性,methods,等等。新的合成型API能让我们用方法(function)来分割,相比于旧的API使用属性来分组,这样代码会更加简便和整洁。

import { reactive } from 'vue'

export default {
  props: {
    title: String
  },
  setup () {
    const state = reactive({
      username: '',
      password: ''
    })

    return { state }
  }
}

为了可以让开发者对反应型数据有更多的控制,我们可以直接使用到 Vue3 的反应API(reactivity API)。
使用以下三步来建立反应性数据:
1、从vue引入reactive
2、使用reactive()方法来声明我们的数据为反应性数据
3、使用setup()方法来返回我们的反应性数据,从而我们的template可以获取这些反应性数据
这里构造的反应性数据就可以被template使用,可以通过state.username和state.password获得数据的值。

2、methods

export default {
  props: {
    title: String
  },
  setup () {
    const login = () => {
      // 登陆方法
    }
    return { 
      login
    }
  }
}

Vue3 的合成型API里面的setup()方法也是可以用来操控methods的。创建声明方法其实和声明数据状态是一样的。— 我们需要先声明一个方法然后在setup()方法中返回(return), 这样我们的组件内就可以调用这个方法了。

3、生命周期

生命周期也可以声明在setup函数里,但是Vue3的生命周期钩子不是全局可调用的了,需要单独引入。另外setup在beforeCreated内调用,没有this

import { reactive, onMounted } from 'vue'

export default {
  props: {
    title: String
  },
  setup () {
    // ..
    onMounted(() => {
      console.log('组件已挂载')
    })
    // ...
  }
}

注意destroy那一对生命周期变成了unmount,同时每个生命周期都增加了"on"

<template>
  子组件
  {{stu}}
</template>

<script>
import { onBeforeMount, onBeforeUnmount, onBeforeUpdate, onMounted, onUnmounted, onUpdated, ref } from '@vue/runtime-core'
export default {
  props: {
    list: {
      type: String,
      default: '1'
    }
  },
  setup (props) {
    const stu = ref(props.list)
    onBeforeMount(() => {
      console.log('DOM渲染前onBeforeMount', document.querySelector('.container'))
    })
    onMounted(() => {
      console.log('DOM渲染后1onMounted', document.querySelector('.container'))
    })
    onMounted(() => {
      console.log('DOM渲染后2onMounted', document.querySelector('.container'))
    })
    onBeforeUpdate(() => {
      console.log('更新组件前,onBeforeUpdate')
    })
    onUpdated(() => {
      console.log('更新组件后,onUpdated')
    })
    onBeforeUnmount(() => {
      console.log('销毁组件前,onBeforeUnmount')
    })
    onUnmounted(() => {
      console.log('销毁组件后,onUnmounted')
    })
    return { stu }
  },
}
</script>

vue axios 添加不上cookie vue3新增api_vue.js

4、计算属性

Vue3 的设计模式给予开发者们按需引入需要使用的依赖包。这样一来就不需要多余的引用导致性能或者打包后太大的问题。Vue2就是有这个一直存在的问题(比如小项目中生命周期很少用全,还有一些其他的特性也很少用到)
注意computed的写法变了。

import { reactive, onMounted, computed } from 'vue'

export default {
  props: {
    title: String
  },
  setup () {
    const state = reactive({
      username: '',
      password: '',
      lowerCaseUsername: computed(() => state.username.toLowerCase())
    })

    // ...
  }

5、Props

又出现了一个Vue3和Vue2的重大区别:this在vue3中与vue2代表着完全不一样的东西
在 Vue2,this代表的是当前组件,不是某一个特定的属性。
但是在 Vue3 中,this无法直接拿到props属性,emit events(触发事件)和组件内的其他属性。不过全新的setup()方法可以接收两个参数:
1、props - 不可变的组件参数
2、context - Vue3 暴露出来的属性(emit,slots,attrs)
就可以使用这两个参数代替this,来访问相应的变量了

6、事件

在 Vue2 中自定义事件是非常直接的,但是在 Vue3 的话,我们会有更多的控制的自由度。

setup (props, { emit }) {
    // ...

    const login = () => {
      emit('login', {
        username: state.username,
        password: state.password
      })
    }

    // ...
}

7、带 ref 的响应式变量

在 Vue 3.0 中,我们可以通过一个新的 ref 函数使任何响应式变量在任何地方起作用,如下所示:

import { ref } from 'vue'
const counter = ref(0)
console.log(counter) // { value: 0 }
console.log(counter.value) // 0

counter.value++
console.log(counter.value) // 1

ref 接受参数并返回它包装在具有 value property 的对象中,然后可以使用该 property 访问或更改响应式变量的值
在对象中包装值似乎不必要,但在 JavaScript 中保持不同数据类型的行为统一是必需的。这是因为在 JavaScript 中,Number 或 String 等基本类型是通过值传递的,而不是通过引用传递的
在任何值周围都有一个包装器对象,这样我们就可以在整个应用程序中安全地传递它,而不必担心在某个地方失去它的响应性。
换句话说,ref 对我们的值创建了一个响应式引用。使用引用的概念将在整个组合式 API 中经常使用。

8、总结

来自这篇文章

composition API:
	setup():
		是composition API 的入口函数
		仅初始化时执行一次。(具体是在beforecreate之前执行。此时的this为undefined,所以在setup()		   无法使用this获取数据)
		所有的compostion API都写在 setup() 中。
		参数有props和context,说明如下:
			props:作用是 父组件向子组件传递的数据
			context:上下文对象。可以解构成{attrs,slot,emit},分别对应vue2中的是:this.$attrs 、 this.$slot 、 this.$emit
		返回值为对象,可以在模版中使用。
		如果混合了vue2语法,
			setup中定义的方法会和method合并,setup中定义的变量会和data合并。
			setup中定义的变量和方法优先级更高。
			method和data可以使用setup中定义的变量和方法。

Teleport

Teleport 提供了一种干净的方法,允许我们控制在 DOM 中哪个父节点下呈现 HTML,而不必求助于全局状态或将其拆分为两个组件。

<body>
  <div style="position: relative;">
    <h3>Tooltips with Vue 3 Teleport</h3>
    <div>
      <modal-button></modal-button>
    </div>
  </div>
</body>

我们设想这样一个问题——模态是在深度嵌套的 div 中渲染的,而模态的 position:absolute 以父级相对定位的 div 作为引用。
Teleport 提供了一种干净的方法,允许我们控制在 DOM 中哪个父节点下呈现 HTML,而不必求助于全局状态或将其拆分为两个组件。

app.component('modal-button', {
  template: `
    <button @click="modalOpen = true">
        Open full screen modal! (With teleport!)
    </button>

    <teleport to="body">
      <div v-if="modalOpen" class="modal">
        <div>
          I'm a teleported modal! 
          (My parent is "body")
          <button @click="modalOpen = false">
            Close
          </button>
        </div>
      </div>
    </teleport>
  `,
  data() {
    return { 
      modalOpen: false
    }
  }
})

一旦我们单击按钮打开模式,Vue 将正确地将模态内容渲染为 body 标签的子级。
使用 < teleport>标签,并给其to属性赋值,保证挂在的位置。

片段

在 3.x 中,组件现在可以有多个根节点!但是,这确实要求开发者明确定义属性应该分布在哪里。

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

————————————暂时写到这里