创建vue3项目
npm init vite-app 项目名称
-
setup函数
- 是组合api的起点 是个函数
- 在beforeCreate前执行,组件创建前,这里访问不到组件实例
- setup函数中没有this
- 提供模版中的数据和函数,需要在setup中返回
<script>
export default {
setup(){
const msg = 'hello vue3'
}
return { msg }
}
</script>
2.组件生命周期函数
- 和vue2.x版本使用基本差不多 我们在使用的时候需要从vue中引入
import { onBeforeMount,onMounted } from 'vue'
export default {
// DOM渲染前的钩子
onBeforeMount(()=>{
console.log('DOM渲染前的钩子',document.getElementsByClassName('main'))
})
//DOM渲染后的钩子函数
onMounted(()=>{
console.log('DOM渲染后的钩子',document.getElementsByClassName('main'))
})
}
3.reactive函数 定义复杂数据类型的响应式数据
<div>
<h1>{{data.name}}</h1>
<button @click='change'>修改名字</button>
</div>
import { reactive } from 'vue'
setup(){
// 通常来定义响应式对象 从响应式数据中解构出来的数据不是响应式数据
const data = reactive({
name: 'ls',
age: 18
})
const change = ()=>{
data.name = 'zs'
}
return { data, change }
}
4.toRef是函数,是可以将响应式数据中的某个属性转化为单独的响应式数据,并且值是关联的
<div>
<h1>{{name}}</h1>
<button @click='change'>修改名字</button>
</div>
import { reactive, toRef } from 'vue'
setup(){
// 通常来定义响应式对象 从响应式数据中解构出来的数据不是响应式数据
const data = reactive({
name: 'ls',
age: 18
})
// toRef的参数 第一个是需要修改属性值的对象本身,第二个是需修改的属性名 是字符串
const name = toRef(data,'name')
const change = ()=>{
name.value = 'zs'
}
return { name, change }
}
// 使用场景:在我们已经有了响应式数据之后,但是模版中只需要其中一个数据。
5.toRefs是函数,将响应式对象中的所有属性转换为单独响应式数据,对象成为普通对象,并且值是关联的
<div>
<h1>{{name}}</h1>
<h1>{{age}}</h1>
<button @click='change'>修改名字</button>
</div>
import { reactive, toRefs } from 'vue'
setup(){
// 通常来定义响应式对象 从响应式数据中解构出来的数据不是响应式数据
const data = reactive({
name: 'ls',
age: 18
})
const person = toRefs(data)
// 在定义方法修改数据的时候 我们也可以解构出来 注意 这里不能解构data,会报错
const change = ()=>{
// 第一种写法
person.name.value = 'zs'
// 第二种 可以直接使用data中数据修改也是可以的,都是响应式数据
data.name = 'zs'
}
// 使用展开运算符,就可以在模版中直接使用属性名渲染数据
return { ...data, change }
}
6.ref函数用于定义响应式数据,一般用于简单数据类型(在修改数据的时候和toRef一直 需要 .value
)
import { ref } from 'vue'
/*
ref也可以定义复杂数据类型的数据 在不清楚数据类型的时候我们可以这样写
const data = ref(null)
*/
setup(){
const name = ref('ls')
const age = ref(10)
// 修改同理
}
7.computed函数定义计算属性,计算属性不可修改
<template>
<div class="main">
<h1>今年:{{age}}岁</h1>
<h1>后年:{{newAge}}岁</h1>
</div>
</template>
<script>
import { ref, computed } from 'vue'
export default {
name: 'App',
setup(){
//1.计算属性:当需要依赖现有的响应式数据,得到一个新的数据
const age = ref(18)
const newAge = computed(()=>{
// 该函数的返回值就是计算属性的值
return age.value + 2
})
return { age, newAge }
}
}
</script>
8.修改计算属性computed的值,尽量不要这样去修改数据!
<template>
<div class="main">
<h1>今年:{{age}}岁</h1>
<h1>后年:{{newAge}}岁</h1>
<input v-model='newAge'></input>
</div>
</template>
<script>
import { ref } from 'vue'
export default {
name: 'App',
setup(){
//1.计算属性:当需要依赖现有的响应式数据,得到一个新的数据
const age = ref(18)
// computed 传入一个对象
const newAge = computed({
// get函数获取要修改的值
get(){
return age.value + 2
}
// set 当计算属性的值被修改是触发
set(value){
age.value= value - 2
}
})
return { age, newAge }
}
}
</script>
9.watch监听器
<template>
<div class="main">
<h1>{{count}}</h1>
<button @click="increment">+1</button>
</div>
</template>
<script>
import { ref, watch } from 'vue'
export default {
name: 'App',
setup(){
const count = ref(0)
const increment = ()=>{
count.value ++
}
// 监听ref数据 reactive同理,也可以监听多个数据的改变 watch([count,person],()=>{ })
watch(count,(newVal,oldVal)=>{
console.log(newVal,oldVal)
},{
// 深度监听
deep:true
})
return { count, increment }
}
}
// 如果要监听对象中的某一项属性值的变化
// watch(()=>obj.name,()=>{})
</script>
10.ref属性,获取组件实例,vue3.0区别vue2.x的写法
<template>
<div class="main">
<div ref="box">div</div>
<ul>
<li v-for="i in 4" key="i" :ref="liRefs">第{{i}}个li</li>
</ul>
</div>
</template>
<script>
import { ref, onMounted } from 'vue'
export default {
name: 'App',
setup(){
// 单个数据的ref属性使用
const box = ref(null)
onMounted(()=>{
console.log(box.value)
})
/**
* v-for 遍历的ref使用
* 先定一个空的数组,用来收集遍历后的dom
* 定义一个函数,往空数组push dom
*/
const list = []
const liRefs = (el)=>{
list.push(el)
}
// 组件挂在完成
/*
这样操作存在一个问题,就是说当我页面别的数据更新变化的时候,list数组会一直push数据
不是我们之前显示的四条数据
我们可以在onBeforeUpdate钩子中重置list数组为空就可以解决了。
*/
onMounted(()=>{
console.log(list[0])
})
return { box, liRefs }
}
}
</script>
11.组件传值 父–>子,整体写法和vue2.x无区别,也是通过绑定自定义属性
<template>
<div class="main">
<h1>父组件</h1>
<Child :count="count"/>
</div>
</template>
<script>
import Child from './child.vue'
import { ref } from "vue";
export default {
name: 'App',
components:{
Child
},
setup(){
const count = ref(100)
return { count }
}
}
</script>
<template>
<div class="main">
<h1>子组件</h1>
<span>{{count}}</span>
</div>
</template>
<script>
export default {
name: "child",
props:{
count:{
type:Number,
default:0
}
},
// 我们也在setup函数中拿到props
setup(props){
// 在页面加载完成之前拿到父组件传来的值
console.log(props.count)
}
}
</script>
12.子—–>父传值,和vue2.x版本一样 定义自定义函数。
<template>
<div class="main">
<h1>父组件</h1>
<hr>
<Child :count="count" @decrement="handleDecrement"/>
</div>
</template>
<script>
import Child from './child.vue'
import { ref } from "vue";
export default {
name: 'App',
components:{
Child
},
setup(){
const count = ref(100)
const handleDecrement = (val) => {
count.value = val
}
return { count,handleDecrement }
}
}
</script>
<template>
<div class="main">
<h1>子组件</h1>
<h1>{{count}}</h1>
<button @click="decrement">子组件方法</button>
</div>
</template>
<script>
export default {
name: "child",
// props:['count']
props:{
count:{
type:Number,
default:0
}
},
setup(props,context){
console.log(props.count)
// setup函数中没有this,我们不能用this.$emit触发事件
// props接收父组件的值,contex包含了$emit的方法 或者可以解构context {emit}函数 触发事件
const decrement = () => {
context.emit('decrement',50)
}
return { decrement }
}
}
</script>
13.区别于vue2.x版本的.sync
双向数据绑定,vue3.0写法v-model
<template>
<div class="main">
<h1>父组件</h1>
<hr>
<!-- <Child :count="count" @update:count="handleDecrement"/>-->
<Child v-model:count="count"/>
</div>
</template>
<script>
import Child from './child.vue'
import { ref } from "vue";
export default {
name: 'App',
components:{
Child
},
setup(){
const count = ref(100)
const handleDecrement = (val) => {
console.log(111)
count.value = val
}
return { count,handleDecrement }
}
}
</script>
<template>
<div class="main">
<h1>子组件</h1>
<h1>{{count}}</h1>
<button @click="decrement">子组件方法</button>
</div>
</template>
<script>
export default {
name: "child",
// props:['count']
props:{
count:{
type:Number,
default:0
}
},
setup(props,context){
console.log(props.count)
// props接收父组件的值,contex包含了$emit的方法 或者可以解构context {emit}函数 触发事件
const decrement = () => {
context.emit('update:count',50)
}
return { decrement }
}
}
</script>
14.provide函数和inject函数
<template>
<div class="main">
<h1>父组件{{count}}</h1>
<hr>
<Child :count="count"/>
</div>
</template>
<script>
import Child from './child.vue'
import { provide, ref } from "vue";
export default {
name: 'App',
components:{
Child
},
setup(){
const count = ref(100)
// 将数据传递给后代组件使用
provide('count',count)
return { count }
}
}
</script>
<template>
<div class="main">
<h2>子组件{{count}}</h2>
</div>
</template>
<script>
import { inject } from "vue";
export default {
name: "child",
setup(){
// 不能直接修改父组件传来的值,遵循单向数据流
const count = inject('count')
return { count }
}
}
</script>
如果要修改父组件的值,需要在父组件中提供方法(provide),子组件中注入方法(inject)
<template>
<div class="main">
<h1>父组件{{count}}</h1>
<hr>
<Child :count="count"/>
</div>
</template>
<script>
import Child from './child.vue'
import { provide, ref } from "vue";
export default {
name: 'App',
components:{
Child
},
setup(){
const count = ref(100)
// 接收子组件的传来的数据
const decrement = (val)=>{
count.value -= val
}
// 将数据传递给后代组件使用
provide('count',count)
provide('decrement',decrement)
return { count, decrement }
}
}
</script>
<template>
<div class="main">
<h2>子组件{{count}}</h2>
<button @click="fn">减1</button>
</div>
</template>
<script>
import { inject } from "vue";
export default {
name: "child",
setup(){
const count = inject('count')
const decrement = inject('decrement')
const fn = ()=>{
// 通知父组件每次要自减1
decrement(1)
}
return { count,fn }
}
}
</script>