Vue3.0什么时候发布的**
2020年09月18日,Vue.js 3.0 正式发布。本次发布框架本身带来了几个大点的改进,以及功能和历程的一些总结!
1.性能方面的优化
- 路由懒加载
- keep-alive缓存页面
- 使用v-show复用DOM
- v-for 遍历避免同时使用 v-if
- 长列表性能优化
- 事件的销毁
- 图片懒加载
- 第三方插件按需引入
- 无状态的组件标记为函数式组件
- 子组件分割
- 变量本地化
- SSR
起初 Vue3.0 暴露变量必须 return 出来,template 中才能使用,Composition API写法:
<template>
</template>
<script>
import { setup,watch,reactive,toRefs,onMounted } from 'vue'
export default {
name:'Login',
components:{},
setup(props, context) {
//在setup()里不能用this
//context是对这些参数的集合
//context.attrs
//context.slots
//context.parent 相当于2.0里 this.$psrent
//context.root 相当于2.0里 this
//context.emit 相当于2.0里 this.$emit
//context.refs 相当于2.0里 this.$refs
const state = reactive({
userName:'111',
list:[]
})
onMounted( () => {
})
watch(
()=> state.userName
)
return{
...toRefs(state)
}
}
}
</script>
Vue3.2 中 只需要在 script 标签上加上 setup 属性,组件在编译的过程中代码运行的上下文是在 setup() 函数中,无需 return,template 可直接使用。
一、文件结构
<template>
// ...
</template>
<script setup>
// ...
</script>
<style lang="scss" scoped>
// 支持CSS变量注入v-bind(color)
</style>
二、data
<script setup>
import { reactive, ref, toRefs } from 'vue'
// ref声明响应式数据,用于声明基本数据类型
const name = ref('Jerry')
// 修改
name.value = 'Tom'
// reactive声明响应式数据,用于声明引用数据类型
const state = reactive({ name: 'Jerry', sex: '男' })
// 修改
state.name = 'Tom' // 使用toRefs解构
const {name, sex} = toRefs(state) // template可直接使用{{name}}、{{sex}}
</script>
三、method
<template>
// 调用方法
<button @click='changeName'>按钮</button>
</template>
<script setup>
import { reactive } from 'vue'
const state = reactive({ name: 'Jery' })
// 声明method方法
const changeName = () => { state.name = 'Tom' }
</script>
四、computed
<script setup>
import { computed, ref } from 'vue'
const count = ref(1)
// 通过computed获得doubleCount
const doubleCount = computed(() => {
return count.value * 2
})
// 获取
console.log(doubleCount.value)
</script>
五、watch
<script setup>
import { watch, reactive } from 'vue'
const state = reactive({ count: 1 })
// 声明方法
const changeCount = () => {
state.count = state.count * 2
}
// 监听count
watch(
() => state.count,
(newVal, oldVal) => {
console.log(state.count)
console.log(`watch监听变化前的数据:${oldVal}`)
console.log(`watch监听变化后的数据:${newVal}`)
},
{
immediate: true, // 立即执行
deep: true // 深度监听
}
)
</script>
六、props父传子
子组件
<template>
<span>{{props.name}}</span>
// 可省略【props.】
<span>{{name}}</span>
</template>
<script setup>
// import { defineProps } from 'vue'
// defineProps在<script setup>中自动可用,无需导入
// 需在.eslintrc.js文件中【globals】下配置【defineProps: true】
// 声明props
const props = defineProps({
name: { type: String, default: '' }
})
</script>
父组件
<template>
<child name='Jerry'/>
</template>
<script setup>
// 引入子组件
import child from './child.vue'
</script>
七、emit子传父
子组件
<template>
<span>{{props.name}}</span>
// 可省略【props.】
<span>{{name}}</span>
<button @click='changeName'>更名</button>
</template> <script setup>
// import { defineEmits, defineProps } from 'vue'
// defineEmits和defineProps在<script setup>中自动可用,无需导入
// 需在.eslintrc.js文件中【globals】下配置【defineEmits: true】、【defineProps: true】
// 声明props
const props = defineProps({
name: { type: String, default: '' }
})
// 声明事件
const emit = defineEmits(['updateName'])
const changeName = () => {
// 执行
emit('updateName', 'Tom')
}
</script>
父组件
<template>
<child :name='state.name' @updateName='updateName'/>
</template>
<script setup>
import { reactive } from 'vue'
// 引入子组件
import child from './child.vue'
const state = reactive({ name: 'Jerry' })
// 接收子组件触发的方法
const updateName = (name) => {
state.name = name
}
</script>
八、v-model
子组件
<template>
<span @click="changeInfo">我叫{{ modelValue }},今年{{ age }}岁</span>
</template>
<script setup>
// import { defineEmits, defineProps } from 'vue'
// defineEmits和defineProps在<script setup>中自动可用,无需导入
// 需在.eslintrc.js文件中【globals】下配置【defineEmits: true】、【defineProps: true】 defineProps({ modelValue: String, age: Number })
const emit = defineEmits(['update:modelValue', 'update:age'])
const changeInfo = () => {
// 触发父组件值更新
emit('update:modelValue', 'Tom')
emit('update:age', 30)
}
</script>
父组件
<template>
// v-model:modelValue简写为v-model
// 可绑定多个v-model
<child v-model="state.name" v-model:age="state.age" />
</template>
<script setup>
import { reactive } from 'vue'
// 引入子组件 import child from './child.vue'
const state = reactive({
name: 'Jerry',
age: 20
})
</script>
九、nextTick
<script setup>
import { nextTick } from 'vue'
nextTick(() => {
// ...
})
</script>
十、ref子组件实例和defineExpose
-
在标准组件写法里,子组件的数据都是默认隐式暴露给父组件的,但在 script-setup 模式下,所有数据只是默认 return 给 template 使用,不会暴露到组件外,所以父组件是无法直接通过挂载 ref 变量获取子组件的数据。
-
如果要调用子组件的数据,需要先在子组件显示的暴露出来,才能够正确的拿到,这个操作,就是由 defineExpose 来完成。
子组件
<template>
<span>{{state.name}}</span>
</template>
<script setup>
import { reactive, toRefs } from 'vue'
// defineExpose无需引入
// import { defineExpose, reactive, toRefs } from 'vue'
// 声明state
const state = reactive({
name: 'Jerry'
})
// 将方法、变量暴露给父组件使用,父组件才可通过ref API拿到子组件暴露的数据
defineExpose({
// 解构state
...toRefs(state),
// 声明方法
changeName () { state.name = 'Tom' }
})
</script>
子组件
<template>
<span>{{state.name}}</span>
</template>
<script setup>
import { reactive, toRefs } from 'vue'
// defineExpose无需引入
// import { defineExpose, reactive, toRefs } from 'vue'
// 声明state
const state = reactive({
name: 'Jerry'
})
// 将方法、变量暴露给父组件使用,父组件才可通过ref API拿到子组件暴露的数据
defineExpose({
// 解构state
...toRefs(state),
// 声明方法
changeName () {
state.name = 'Tom'
}
})
</script>
父组件
1. 获取一个子组件实例
<template>
<child ref='childRef'/>
</template>
<script setup>
import { ref, nextTick } from 'vue'
// 引入子组件
import child from './child.vue'
// 子组件ref(TypeScript语法)
const childRef = ref<InstanceType<typeof child>>()
// nextTick
nextTick(() => {
// 获取子组件name
console.log(childRef.value.name)
// 执行子组件方法
childRef.value.changeName()
})
</script>
2. 获取多个子组件实例:在 v-for 中获取子组件实例
这种情况仅适用于 v-for 循环数是固定的情况 ,因为如果 v-for 循环数 在初始化之后发生改变,那么就会导致 childRefs 再一次重复添加,childRefs 中会出现重复的子组件实例
<template>
<div v-for="item in 3" :key="item">
<child :ref='addChildRef'/>
</div>
</template>
<script setup>
// 省略...
// 子组件实例数组
const childRefs = ref([])
// 通过 addChildRef 方法向 childRefs 添加子组件实例
const addChildRef = (el) => {
childRefs.value.push(el)
}
</script>