1、Vue3
- 初始化写法变了
- data写法改了,函数式写法
<div id="box">
{{10+20}}
</div>
//vue2
new Vue({
el: "#box",
data: {
},
methods: {
}
})
//vue3 初始化
Vue.createApp({
data() {
return {
myname: "abc"
}
},
methods: {
}
}).mount("#box")
2、router
路由重定向写法
//vue2
{
path: '/',
redirect: 'films'
}
//vue3
{
path: 'films',
component: Film,
name: 'film' // 命名路由
},
{
path: '/:aaa',
redirect: {
name: 'film' // 命名路由写法
}
}
3、Composition API介绍(hooks写法)
起初定义的是Vue-Function-API,后经过社区意见搜集,更名为Vue-Composition-API.
3.1 函数式写法
reactive 作用:创建响应式对象,非包装对象,可以认为式模板中的状态。
- template可以放兄弟节点
- reactive类似useState,如果参数是字符串,数字,会报警告,value cannot be made reactive, 所以应该设置对象,这样可以数据驱动页面
<template>
<div>
hello3- 新写法
{{obj.myname}}
<button @click="handleClidk()">change</button>
</div>
</template>
<script>
import {reactive} from 'vue'
export default {
//vue3老写法(或者vue写法)中 beforeCreate,created 生命周期 === setup
setup(){
//定义状态
const obj = reactive({
myname: 'wang',
myage: 100
})
//reactive 可以定义多个
const obj2 = reactive({
dataList: []
})
const mylist = reactive([])
const handleClidk = ()=> {
obj.myname = "xiaoming"
}
return {
obj,
obj2,
mylist,
handleClidk
}
}
}
</script>
3.2、ref
作用:创建一个包装式对象,含有一个响应式属性value。它和reactive的差别,就是reactive没有包装属性value const count = ref(0),可以接收普通数据类型,count.value++
vue2写法
<template>
<div>
<input type="text" ref="mytextref"/>
<button @click="handleAdd">add</button>
</div>
</template>
<script>
export default {
//vue2写法
data() {
return {
myname: 'chwang'
}
},
mounted() {
console.log('mounted', this.$refs.mytextref)
},
}
</script>
vue3写法 :ref访问dom或者组件
<template>
<div>
<input type="text" ref="mytextref"/>
<button @click="handleAdd">add</button>
</div>
</template>
<script>
import {reactive,ref} from 'vue'
export default {
setup() {
const obj = reactive({
mytext: '',
dataList: []
})
const mytextref = ref()
const handleAdd = () => {
console.log(mytextref.value)//input dom节点
console.log(mytextref.value.value)//input框的值
}
return {
obj,
mytextref,
handleAdd,
}
}
}
</script>
reactive类似useState,如果参数是字符串,数字,会报警告,value cannot be made reactive, ,可以使用ref替代方案
<template>
<div>
hello vue3 - 新写法
{{myname}}
<button @click="handleClidk()">change</button>
</div>
</template>
<script>
import {ref} from 'vue'
export default {
setup() {
//对字符串拦截,实质还是对属性进行拦截(.value)
const myname = ref('chwang')
const handleClidk = ()=> {
myname.value = "xiaoming"
}
return {
myname,
handleClidk
}
}
}
</script>
3.3、toRefs & toRef
toRefs
toRefs 函数的作用是将响应式对象中的所有属性转换为单独的响应式数据,对象成为普通对象,并且值是关联的。在这个过程中toRefs会做以下两件事:
- 把一个响应式对象转换成普通对象
- 对该普通对象的每个属性都做一次ref操作,这样每个属性都是响应式的
注意:
- 响应式对象的处理,是加给对象的,如果对对象做了展开操作,那么就会丢失响应式的效果。所以上面代码直接展对象,单击button时,不能改变页面显示效果。
- 它只会解析对象的第一层属性
说明:
- reactive 对象取出的所有属性值都是非响应式的,而利用 toRefs 可以将一个响应式 reactive 对象的所有原始属性转换为响应式的 ref 属性。
- reactive的响应式功能是赋值给对象,如果展开对象,会让数丢失响应的能力
- 使用toRefs可以保证对象展开的每个属性都是响应式的
应用场景:
展开响应式对象时,想使用响应式对象中的多个或者所有属性做为响应式数据。 当函数返回响应式对象时,toRefs非常有用,这样消费组件就可以在不丢失响应式的情况下对返回的对象进行分解使用。
<template>
<div>
hello vue3 - 新写法
{{myname}} - {{age}}
<button @click="handleClidk()">change</button>
</div>
</template>
<script>
import {reactive,toRefs} from 'vue'
export default {
setup() {
const obj = reactive({
myname: 'chwang',
age: 18
})
const handleClidk = ()=> {
obj.myname = "xiaoming"
}
return {
...toRefs(obj),// 展开
//...obj,//直接展开会丢失响应式的效果
handleClidk
}
}
}
</script>
点击按钮之后
toRef
要将响应式对象中的某个属性单独提供给外部使用时。
<template>
<div>
hello vue3 - 新写法
{{myname}} - {{age}}
<button @click="handleClidk()">change</button>
</div>
</template>
<script>
import {reactive,toRefs, toRef} from 'vue'
export default {
setup() {
const obj = reactive({
myname: 'chwang',
age: 18
})
const handleClidk = ()=> {
obj.myname = "xiaoming"
}
return {
// ...toRefs(obj),
myname: toRef(obj, 'myname'),
age: toRef(obj, 'age'),
handleClidk
}
}
}
</script>
3.4、props&emit
- 父组件: props.vue
- 子组件:naver.vue,slider.vue
点击naver.vue的按钮控制slider.vue是否显示
props.vue
<template>
<div>
通信
<naver
myname="home"
myid="111"
@hhh="change"></naver>
<slider
:show="isShow"
></slider>
</div>
</template>
<script>
import {reactive, toRef} from 'vue'
import naver from './components/naver.vue'
import slider from './components/slider.vue'
export default {
components: {
naver,
slider
},
setup() {
const obj = reactive({
isShow: true,
})
const change = (value) => {
obj.isShow = value
}
return {
isShow: toRef(obj, 'isShow'),
change
}
}
}
</script>
naver.vue
<template>
<div>
<button @click="handleShow">left</button>
naverbar
<button>right</button>
{{myname}}
</div>
</template>
<script>
export default {
props: {
myname: {
type: String,
default: 'hh'
},
myid: {
type: String,
default: 'hh'
}
},
setup(props, {emit}) {//props接收父组件传入的属性,第二个参数接受一些
const handleShow = () => {
emit('hhh', false)
}
return {
props,
handleShow
}
}
}
</script>
setup第一个参数:
props,是一个对象,包含父组件传递给子组件的所有数据。 在子组件中使用props进行接收,包含配置声明并传入的所有的属性的对象,也就是说:如果你想通过props的方式输出父组件传递给子组件的值。
你需要使用props进行接收配置。即props:{......} 如果你未通过Props进行接受配置,则输出的值是undefined
setup第二个参数:
context,是一个对象。
1.有attrs(获取当前标签上的所有属性的对象) 但是该属性是props中没有声明接收的所有的对象。 如果你使用props去获取值,同时props中你声明了你要获取的值 则获取的值是undefined 。注意点: attrs获取值是不需要props中没有声明接收。 第一个参数props获取值是需要props中声明接收的 1.有emit事件分发,(传递给父组件需要使用该事件)
- 有slots插槽
slider.vue
<template>
<div v-show="show" class="slider-content">
slider
</div>
</template>
<script>
export default {
props: {
show: {
type: Boolean,
default: false
}
},
}
</script>
<style lang="less" scoped>
.slider-content {
width: 100px;
height: 200px;
background: red;
}
</style>
3.5、生命周期
| 原方法 | hooks方法(setup写法) | |
|---|---|---|
| beforeCreate | setup | |
| created | setup | 实例已经创建完成之后,可以操作vue中的数据和方法,不能操作dom节点 |
| beforeMount | onBeforeMount | 组件挂载到节点上之前执行的函数。 |
| mounted | onMounted | 组件挂载完成之后执行的函数。 |
| beforeUpdate | onBeforeUpdate | 组件更新之前执行的函数。 |
| updated | onUpdated | 组件更新完成之后执行的函数。 |
| beforeDestroy | onBeforeUnmount | 组件卸载之前执行的函数。 |
| destroyed | onUnmounted | 组件卸载完成之后执行的函数。 |
import { onUnmounted, onMounted } from 'vue'
setup () {
const obj = reactive({
list: []
})
...
onMounted(() => {
//dom上树
//axios,事件监听等
console.log('onMounted')
//模拟ajax请求
setTimeout(()=>{
obj.list = ['aa','bb','cc']
}, 2000)
})
...
return {
obj
}
}
3.6、计算属性
首先,使用 computed 需要引入。
import { computed } from 'vue'
<template>
<div>
<input type="text" v-model="obj.mytext"/>
<ul>
<li v-for="data in computedList" :key="data">
{{data}}
</li>
</ul>
</div>
</template>
<script>
import { reactive, computed } from 'vue'
export default {
setup() {
const obj = reactive({
mytext: '',
datalist: ['aaa','abb','abc','bbb','bcc','add','bcd']
})
const computedList = computed(() => {
return obj.datalist.filter(item=>item.includes(obj.mytext))
})
//计算属性的好处,有缓存
return {
obj,
computedList
}
}
}
</script>
3.7 watch监听属性
共有三个参数,分别为:
- text:需要帧听的属性;
- (newVal,oldVal)=>{ //业务处理 } 箭头函数,是监听到的最新值和本次修改之前的值,此处进行逻辑处理。
- options :配置项,对监听器的配置,如:是否深度监听。
import { watch } from "vue"
watch( text , ( newVal , oldVal )=>{ //业务处理 }, options );
监听普通类型
const name = ref('hh')
const age = ref(22)
// 监听单个普通类型
watch(name, (newVal, oldVal) => {
console.log(newVal)
})
// 监听多个普通类型,返回数组
watch([name, age], (newVal, oldVal) => {
console.log(newVal)
})
监听整个对象
const person = reactive({
name: 'hh',
infos: {
age: 21,
address: '上海'
}
})
// 监听对象person时,vue3将强制开启deep深度监听
watch(person, (newVal, oldVal) => {
console.log(newVal)
})
watch(() => person, (newVal, oldVal) => {
console.log(newVal)
}, { deep: true })
监听对象中的属性
<template>
<div>
<input type="text" v=modal="obj.mytext" @input="handleInput"/>
<ul>
<li v-for="data in obj.datalist" :key="data">
{{data}}
</li>
</ul>
</div>
</template>
<script>
import { reactive, watch } from 'vue'
setup(){
const obj = reactive({
mytext: '',
datalist: ['aaa','abb','abc','bbb','bcc','add','bcd'],
oldlist: ['aaa','abb','abc','bbb','bcc','add','bcd'],
infos: {
age: 21,
address: '上海'
}
})
//当只有对象obj的属性mytext发生变化的时候,才会触发watch
watch(
()=>obj.mytext,
()=>{
obj.datalist = obj.oldlist.filter(item=>item.includes(obj.mytext))
}
)
// 注意:监听对象的属性为复杂数据类型时,需要开启deep深度监听
watch(
() => obj.infos,
(newVal, oldVal) => {
console.log(newVal)
},
{ deep: true }
)
return {
obj,
}
}
</script>