Vue3.2相关语法

148 阅读2分钟
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() 函数中,无需 returntemplate 可直接使用。

一、文件结构

<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>