3.0的目标
- 更小
- 更快
- 加强 TypeScript 支持
- 加强 API 设计一致性
- 提高自身可维护性
- 开放更多底层功能
什么是Hooks?
hooks翻译过来是钩子的意思,这个可能有一些模糊,简单点说hooks就是一个函数(可以复用的函数)例如:业务中很难避免的一个问题就是-- 逻辑复用,同样的功能,同样的组件,在不一样的场合下,我们有时候不得不去写2+次,为了避免耦合我们出现了一些概念(mixin,高级组件,slot插槽)。
上述这些方法都可以实现逻辑上的复用,但是都有一些额外的问题:
mixin的问题:
- 不同的mixin中的方法,属性可能会相互冲突(命名空间冲突);
- mixin非常多时,会造成数据来源不清晰
HOC的问题:
- 需要在原组件上进行包裹或者嵌套,将会产生非常多的嵌套,调试起来不容易;
- props命名空间冲突(多个高级组件的props冲突)
- props 数据来源不清晰(不知道这个属性到底是那个高级组件传递的)
- 额外的组件实例消耗性能
作用域插槽:
没有命名冲突和数据来源不清晰的问题,但是创建了额外的组件
所以,hook的出现是划时代的,它通过function抽离的方式,实现了复杂逻辑的内部封装在vue中的hooks主要是为了逻辑代码的复用不存在命名冲突,数据来源不清晰的问题减小了代码体积:因为在打包时候我们用了那些函数就会打包那些不用的不会打包,而且在打包的时候会对函数进行混淆压缩变得更小没有this的烦恼,不需要通过this访问一些内容了。
什么是TypeScript?
其实TypeScript并不是一门新的语言,它是 JavaScript 类型的超集,typeScript那并不是一个新语言,可以理解为加强JavaScript的buff,TypeScript最大的优势源于强大的类型系统,还有就是在编写代码的时候就可以检测出我们可能因为粗心造成的不必要的错误。
为什么要学习TypeScript ?
- 未来趋势,目前来看发展,和应用趋势很快
- vue3.0发布后,基本就离不开ts了
- 使用 TypeScript 可以帮助我们防止在编写 JavaScript 代码时因为数据类型的转换造成的意想不到的错误。提前帮我们发现代码出现错的风险。
- 团队成员使用 JavaScript 时很容易瞎写,不受规范约束。但是如果使用TypeScript那大家都不得不遵守规范。
- TypeScript 紧跟 JavaScript 的发展,ES7 、ES8、ES9 相关语言的新特性都支持,比浏览器支持的速度更快。
什么样的项目需要TypeScript ?
- 团队多人开发的大项目
- 开源项目
- 企业对代码有高质量要求的项目
如何使用Ts:
Vue3.0 最重要的就是 RFC,即 Function-based API。Vue3.0 将抛弃之前的 Class API 的提案,选择了 Function API。目前,vue 官方 也提供了 Vue3.0 特性的尝鲜版本,前段时间叫 vue-function-api,目前已经改名叫 composition-api。
使用官方脚手架Vue-cli创建一个ts项目
npm install -g @vue/cli
yarn global add @vue/cli
新的 VueCLI工具允许开发者 使用 TypeScript 集成环境 创建新项目。只需运行 vue create tsvue3demo。然后,命令行会要求选择预设。使用箭头键选择 Manually select features。
这样一个可以使用ts的vue基础架构就构建完成了
目录架构
.
├── README.md
├── babel.config.js
├── package.json
├── postcss.config.js
├── public
│ ├── favicon.ico
│ └── index.html
├── src
│ ├── App.vue
│ ├── assets
│ │ └── logo.png
│ ├── components
│ │ └── HelloWorld.vue
│ ├── main.ts
│ ├── router
│ │ └── index.ts
│ ├── shims-tsx.d.ts 允许你以 .tsx结尾的文件,在 Vue项目中编写 jsx代码
│ ├── shims-vue.d.ts 主要用于 TypeScript 识别 .vue 文件
│ ├── store
│ │ └── index.ts
│ └── views
│ ├── About.vue
│ └── Home.vue
├── tsconfig.json
└── yarn.lock
在这个创建好的目录中我们打开 HelloWord.vue 文件可以看到不一样的组件写法
<template>
<div class="hello">
<h1>{{ msg }}</h1>
...
</div>
</template>
<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator'
@Component
export default class HelloWorld extends Vue {
@Prop() private msg!: string;
}
</script>
以上的写法是在vue3.0以前,强化Vue组件使用typeScript的写法
需要引入:
vue-class-component:强化 Vue 组件,使用 TypeScript/装饰器 增强 Vue 组件vue-property-decorator:在 vue-class-component 上增强更多的结合 Vue 特性的装饰器ts-loader:TypeScript 为 Webpack 提供了 ts-loader,其实就是为了让webpack识别 .ts .tsx文件tslint-loader跟tslint:我想你也会在.ts .tsx文件 约束代码格式(作用等同于eslint)tslint-config-standard:tslint 配置 standard风格的约束
但是在vue3.0里面废弃了class component
Vue3.0的用法
Vue3.0还没有正式发布,但是官方提供了Vue 2.x 能够提前体验此API的库@vue/composition-api
安装
npm i @vue/composition-api -S
使用
import Vue from 'vue'
import VueCompositionApi from '@vue/composition-api'
Vue.use(VueCompositionApi)
如果项目是用的 TS,需要使用 createComponent 来定义组件,这样你才能使用类型推断,如果没有使用,可直接抛出一个对象
<template>
<div id="app">
</div>
</template>
<script lang="ts">
import { createComponent } from '@vue/composition-api'
export default createComponent({
...
})
</script>
实例:这是VueConf 2019尤大大在介绍的时候给出的一个例子,改成ts版本
<template>
<div id="app">
<div class="hooks-one">
<h2>{{ msg }}</h2>
<p>count is {{ count }}</p>
<p>plusOne is {{ plusOne }}</p>
<button @click="increment">count++</button>
</div>
<!-- <router-view/> -->
</div>
</template>
<script lang="ts">
import { ref, computed, watch, onMounted, Ref, createComponent } from '@vue/composition-api'
interface Props {
name: string
}
export default createComponent({
props: {
name: {
type: String,
default: 'ssss'
}
},
components: {},
setup (props: Props, context) {
const count: Ref<number> = ref(0)
// computed
const plusOne = computed(() => count.value + 1)
// method
const increment = () => {
count.value++
}
// watch
watch(() => count.value * 2, val => {
console.log(`count * 2 is ${val}`)
})
// 生命周期
onMounted(() => {
console.log('onMounted')
})
// expose bindings on render context
return {
count,
plusOne,
increment,
msg: `hello ${props.name}`
}
}
})
</script>
详解:setupsetup函数是Vue Function API 构建的函数式写法的主逻辑,当组件被创建时,就会被调用,函数接受两个参数,分别是父级组件传入的props和当前组件的上下文context。context上下文(this的替代者可以理解为),setup 是在组件实例被创建时, 初始化了 props 之后调用,处于 created 前。setup() 和 data() 很像,都可以返回一个对象,而这个对象上的属性则会直接暴露给模板渲染上下文:
<template> <div id="app"> {{ msg }} {{ count }} </div></template><script lang="ts">import { createComponent } from '@vue/composition-api'export default createComponent({ props: { name: String }, setup (props) { const count: Ref<number> = ref(0) return { msg: `hello ${props.name}`, count } }})</script>
组件 API(Composition API)
组件 API 是 Vue 的下一个主要版本中最常用的讨论和特色语法。这是一种全新的逻辑重用和代码组织方法。当前,我们使用所谓的 Options API 构建组件。为了向 Vue 组件添加逻辑,我们填充(可选)属性,例如 data、methods、computed等。这种方法的最大缺点是其本身并不是有效的 JavaScript 代码。你需要确切地知道模板中可以访问哪些属性以及 this 关键字的行为。在后台,Vue 编译器需要将此属性转换为工作代码。因此我们无法从自动建议或类型检查中受益。组件 API 旨在通过将组件属性中当前可用的机制公开为 JavaScript 函数来解决这个问题。Vue 核心团队将组件 API 描述为 “一组基于函数的附加 API,可以灵活地组合组件逻辑。” 用组件 API 编写的代码更具有可读性
reactive和ref
reactive(): 转换响应式对象
ref(): 转换原始类型为响应式对象
两者的区别reactive 代理初始化一个对象,ref 只是一个 .value 值,在函数中使用都要一直使用 .value 引着
<template>
<div id="app">
<div class="hooks-one">
{{state.double}}
{{state.count}}
<p>count is {{ count }}</p>
<button @click="increment">count++</button>
</div>
<!-- <router-view/> -->
</div>
</template>
<script lang="ts">
import { ref, computed, reactive, Ref, createComponent } from '@vue/composition-api'
interface State {
count: number,
double: number
}
export default createComponent({
setup (props, context) {
const count: Ref<number> = ref(0)
const state: State = reactive({
count: 0,
double: computed(() => state.count * 2)
})
// method
const increment = () => {
count.value++ // 需要.value获取,改变
state.count++
}
// expose bindings on render context
return {
increment,
state
}
}
})
</script>
watch & computed
watch和computed的基本概念与 Vue 2.x 的watch和computed一致,watch可以用于追踪状态变化来执行一些后续操作,computed用于计算属性,用于依赖属性发生变化进行重新计算。computed返回一个只读的包装对象,和普通包装对象一样可以被setup函数返回,这样就可以在模板上下文中使用computed属性。可以接受两个参数,第一个参数返回当前的计算属性值,当传递第二个参数时,computed是可写的。=
生命周期
所有现有的生命周期都有对应的钩子函数,通过onXXX的形式创建,但有不同的是,destoryed钩子函数需要使用unmounted代替,删除了onBeforeCreate和onCreated:
import { onMounted, onUpdated, onUnmounted, createComponent } from '@vue/composition-api';export default createComponent({ setup() { onMounted(() => { console.log('mounted!'); }); onUpdated(() => { console.log('updated!'); }); // destroyed 调整为 unmounted onUnmounted(() => { console.log('unmounted!'); }); },});
参考:
https://zhuanlan.zhihu.com/p/68477600
https://www.yuque.com/vueconf/2019
https://vue-composition-api-rfc.netlify.com/api.html
https://juejin.im/post/5dca71f8f265da4cef191581
https://juejin.im/post/5d836458f265da03d871f6e9
https://segmentfault.com/a/1190000020205747?utm_source=tag-newest