简介
- Vue2 + 修饰器模式【支持TS】需要安装以下插件
- Vue2 + 修饰器模式其实是向Vue3过渡的版本
npm i -S vue-property-decorator
npm install --save vue-class-component
- 修饰写法告警
- 解决
搜素:experimentalDecorators
main.js 文件的区别
Vue2
Vue2 + 装饰器
VUe3
- 一改之前的new Vue 和 render 方法。通过引入createApp代替
- 支持链调用
模板的区别
Vue3 取消了跟标签的限制
Vue2
Vue2 + 装饰器
VUe3
- Vue3 将组建标签都放到了内置的Fragment组件中,减少嵌套
组件暴露
Vue2
<script>
export default {
name: 'app',
}
</script>
Vue2 + 装饰器
<script>
import {Vue} from 'vue-property-decorator'
export default class Home extends Vue {
}
</script>
VUe3
<script>
export default {
name: "App",
}
</script>
组件名
Vue2
<script>
export default {
name: 'app',
}
</script>
Vue2 + 装饰器
<script>
import {Vue,Component} from 'vue-property-decorator' // 要引入 Component
@Component({ // 注意书写位置不在组件配置里
name:'app'
})
export default class Home extends Vue {
}
</script>
VUe3
<script>
export default {
name: "App",
};
</script>
操作属性的舞台
Vue2
<script>
export default {
name: 'app',
components:{},
props:{},
data(){
return {}
},
computed: {},
created() {},
mounted() {},
methods: {},
}
</script>
Vue2 + 装饰器
<script>
import {Component, Vue} from 'vue-property-decorator'
@Component({
name:'app'
})
export default class Home extends Vue {
// 直接操作
}
</script>
VUe3
<script>
export default {
name: "App",
setup(){
// 在setUp方法中操作
return {
}
}
};
</script>
组件中的data【响应式数据】
Vue2
<script>
export default {
name: 'app',
data(){ // data中的数据就是响应式数据
return {
name:'小明'
}
},
}
</script>
Vue2 + 装饰器
<script>
import {Vue,Component} from 'vue-property-decorator' // 要引入 Component
@Component({
name:'app'
})
export default class Home extends Vue {
name = '小明' // 直接定义即可且为响应式
}
</script>
Vue3
基本数据类型变成响应式数据
方法:
ref()
特点:
- 模板直接使用
- setUp()内使用,因为它做了包装,所以要用 xxx.value 形式获取
export default {
name: 'home',
setup(props,{attrs,slots,emit}){
let id = ref(1003)
return {
id,
}
}
}
响应式基本数据类型变成非响应式
- unref():是 val = isRef(val) ? val.value : val 的语法糖。
- 当发送请求时,我们不希望数据被包装过所以要用到该方法
unref()
复合数据类型变成响应式数据[深度响应式(proxy)]
注意点:
- 页面模板只用通过对象点属性的形式去拿取相应的数据
- reactive()定义的响应式对象setUp中获取该对象无需进行 .value 获取。可直接使用
- ref()定义的响应式对象setUp中获取该对象需进行.value获取
ref() // 当传入对象时代用的还是reactive()
reactive() // 只收对象形式否则会报错且能成为响应式数据
响应式复合数据类型变为非响应式
ref()定义的
toRaw(userInfo.value)
reactiv()定义的
toRaw(userInfo)
抛出对象类型的响应式数据【方便模板取值】
toRef(Object,key)
setup(props, { attrs, slots, emit }) {
let userInfo = reactive({
name: "迪丽热巴",
age: 18,
});
return {
name:toRef(userInfo,'name'),
age:toRef(userInfo,'age'),
handler,
};
},
toRefs(object) // toRef()升级版 toRefs()返回值,是一个对象形式的代理对象
setup(props, { attrs, slots, emit }) {
let userInfo = reactive({
name: "迪丽热巴",
age: 18,
});
return {
...toRefs(userInfo),
};
},
只读的响应式对象数据
readonly(Object)
自定义的响应式函数
- 可以定义特殊的响应式
customRef()
<input v-model="text" />
function useDebouncedRef(value, delay = 200) {
let timeout
return customRef((track, trigger) => {
return {
get() {
track()
return value
},
set(newValue) {
clearTimeout(timeout)
timeout = setTimeout(() => {
value = newValue
trigger()
}, delay)
}
}
})
}
export default {
setup() {
return {
text: useDebouncedRef('hello',300) // 数据改变后300ms才渲染页面
}
}
}
组件中的methods
Vue2
methods:{
click(){
this.obj.name.test = '30'
}
},
Vue2 + 装饰器
export default class Home extends Vue {
name = '小明'
click(){
this.name = '小白'
}
}
Vue3
setup(props, { attrs, slots, emit }) {
function handler() {
userInfo.name = '贾玲'
}
return {
handler, // 一定要吐出来才能用
};
},
组件中的computed
Vue2
简便写法
computed:{ // 当修改该值时无法修改
price(){
return this.age
}
},
可修改的写法
computed:{
price:{
get(){
return this.age
},
set(value){
this.age = value
}
}
},
Vue2 + 装饰器
export default class Home extends Vue {
age = 20
get price(){
return this.age
}
set price(value){
this.age = value
}
}
Vue3
简便写法
setup(props, { attrs, slots, emit }) {
let age = ref(20)
let price = computed(()=>{
return age.value
})
return {
price,
};
},
可修改的写法
setup(props, { attrs, slots, emit }) {
let age = ref(20)
let price = computed({
get(){
return age.value
},
set(value){
age.value = value
}
})
return {
price,
};
},
组件中的Watch
Vue2
基本数据类型监视
watch:{
age(newData,oldData){
}
},
复合数据类型监视
watch:{
userInfo:{
immediate:true,
deep:true,
handler(newData,oldData){
}
}
},
Vue2 + 装饰器
@Watch('info',{immediate:true,deep:true}) handler(newData,oldData){
console.log(newData)
}
Vue3
- Vue3 reactive()代理的对象进行监视时,新旧数据都为新的数据【Vue3 BUG】
- 当要监视某个对象的某个属性的属性值扔是对象时,需要开始深度监视。否则所有的深度监视是无效的。
- ref()包裹的对象,监视时需要使用 .value 且要开启深度监视
单个监视对象
watch(userInfo,()=>{
console.log('userInfo');
},{
immediate:true,
deep:true, // Vue3 默认开启的是深度监视
})
多个监视对象
watch([userInfo,carInfo],(newData,oldData)=>{
console.log(newData,oldData);
},{
immediate:true,
deep:true, // Vue3 默认开启的是深度监视
})
监视某一个对象的某一个属性【利用函数返回】
watch(userInfo.age,(newData,oldData)=>{ // 无效【错误写法】
console.log(newData,oldData);
})
watch(() => userInfo.age,(newData,oldData)=>{ // 正确
console.log(newData,oldData);
})
监视某个对象中的某个属性的属性值仍然是对象【要开深度监视】
watch(() => userInfo.desc,(newData,oldData)=>{
console.log(newData,oldData);
},{deep:true})
升级版的监视【watchEffect】
- 当依赖的数据发生变化,就执行回调。【类似于计算属性】
watchEffect(() => {
let num = userInfo.age
console.log('执行了')
})
组件中的props
Vue2
组件内定义接收的props
props:['age']
props:{
age:{
type:Number,
require:true,
default:() => (20)
}
},
Vue2 + 装饰器
@Prop([Number]) age
@Prop({type:Number,required:true,default:() => 20}) age
Vue3
- 定义
props:['age']
props:{
age:{
type:Number,
require:true,
default:() => (20)
}
},
- 使用
export default {
name: "home",
props:{
age:{
type:Number,
require:true,
default:() => (20)
}
},
setup(props, { attrs, slots, emit }) { // setUp函数接收到两个参(props,context)
console.log(props.age) // props 中存放了定义的props
},
};
组件中的emit
Vue2
handler(){
this.$emit('showBtn',false)
}
Vue2 + 装饰器
- 使用 @Emit() 方法,该方法中传入的事件名就是emit名字
- @Emit() 方法 后紧随的方法是触发emit的方法,且必须传入值,并将该值返回
// 子组件
<template>
<div>
<button @click="showBtn(false)">emit</button>
</div>
</template>
<script>
import {Component, Emit, Vue,} from 'vue-property-decorator'
export default class Home extends Vue {
@Emit('showBtn') showBtn(a){return a} // 必须传入参数值否则报错
}
// 父组件使用
<Home @showBtn="handler"></Home>
Vue3
setup(props, { attrs, slots, emit }) {
function handler(){
emit('showBtn',false)
}
return {
handler
}
},
组件中的ref
Vue2
<Home ref="home"></Home>
handler(){
this.$refs.home
}
Vue2 + 装饰器
<Home ref="home"></Home>
handler(){
this.$refs.home
}
Vue3
- 子父组件中借助于 getCurrentInstance()方法获取组件实例
- 组件实例身上有ref属性存放着打了ref则组件
setup(props,context){
const vm = getCurrentInstance(); //获取当前组件实例
function handler(flg) {
vm.refs.home.change()
}
return {
handler
}
}
组件中的slots
Vue2
- 组件内部传入的标签会默认放置到$slots上,没有名字则默认为default
- 传入名称的插槽后也会对应生产相应名称的插槽
子组件中的 this.$slots 属性
Vue2 + 装饰器
- 组件内部传入的标签会默认放置到$slots上,没有名字则默认为default
- 传入名称的插槽后也会对应生产相应名称的插槽
子组件中的 this.$slots 属性
Vue3
- 放置在setUp()参数中的 sloat
- 命名插槽要使用 v-slot:xxx
// 使用插槽
<Home>
<template v-slot:title>sdfsfsfdsfs</template> // v-slot:title [只有该属性生效]
</Home>
// 创建插槽
<slot name="title"></slot>
// 获取插槽信息
setup(props, { attrs, slots, emit }) {
console.log(slots)
}
mixin
Vue2
export default {
name: 'home',
mixins:[form],
}
Vue2 + 装饰器
@Component({
name:'app',
components:{Home},
mixins:[from]
})
Vue3
- hook函数
创建hook函数
使用hook函数
生命周期不同
Vue2
beforeCreate: function() {
alert('Before Create');
},
created: function() {
alert('Created');
},
beforeMount: function() {
alert('Before Mount');
},
mounted: function() {
alert('Mounted');
},
beforeUpdate: function() {
alert('Before Update');
},
updated: function() {
alert('Updated');
},
beforeDestroy: function() {
alert('Before Destroy');
},
destroyed: function() {
alert('Destroyed');
}
Vue3
setUp() 外书写的生命周期
- 对标Vue2只有 beforeDestroy 改为 beforeUnMount()
- destroyed 改为 unMounted()
- setUp() 在 beforeCreate() 前创建所以在setup中没有this
setUp() 中的生命周期
- setUp() 中没有beforeCreate,created
- setUp() 中的生命周期构造都是带On的
- setUp() 中的生命周期钩子使用的是回调形式的
onBeforeMount,
onMounted,
onBeforeUpdate,
onUpdated,
onBeforeUnmount,
onUnmounted,
onRenderTracked,
onRenderTriggered,
onMounted(() => { // 回调形式
console.log(obj)
})
内置的组建
Vue2
component [动态渲染组件]
// is 可以是 组件名称或组件实例
<component v-bind:is="currentTabComponent"></component>
transition
<transition> <div v-if="ok">toggled content</div> </transition>
transition-group
<transition-group tag="ul" name="slide"> <li v-for="item in items" :key="item.id"> {{ item.text }} </li> </transition-group>
keep-alive
- props : includes(包含)[字符串或正则或字符串数组] exclude(不包含)[字符串或正则或字符串数组]
<keep-alive> <component :is="view"></component> </keep-alive>
slot
Vue3
Teleport[传送门组件]
- props : to
<teleport to="#some-id" />
<teleport to=".some-class" />
<teleport to="[data-teleport]" />
Suspence [异步组件]
- 引入异步组件
- 利用Suspence组件处理异步组件
import {defineAsyncComponent} from 'vue'
const Child = defineAsyncComponent(()=>import('./components/Child.vue'))
<template>
<div class="app">
<h3>我是App组件</h3>
<Suspense>
<template v-slot:default>
<Child/>
</template>
<template v-slot:fallback>
<h3>加载中.....</h3>
</template>
</Suspense>
</div>
</template>