一.create-vue
// new Vue() 创建一个应用实例 => createApp()
// createRouter() createStore()
// 将创建实例进行了封装,保证每个实例的独立封闭性import { createApp } from 'vue'
import App from './App.vue'// mount 设置挂载点 #app (id为app的盒子)
createApp(App).mount('#app')
二.组合式API
(1)setup选项
setup:
1.执行时机,比beforeCreate还要早
2.setup函数中,获取不到this (this是undefined)
3.数据 和 函数,需要在 setup 最后 return,才能模板中应用
问题:每次都要return,好麻烦?
4.通过 setup 语法糖简化代码
<script>
export default {setup () {// console.log('setup函数', this)// 数据const message = 'hello Vue3'// 函数const logMessage = () => {console.log(message)}return {message,logMessage}},beforeCreate () {console.log('beforeCreate函数')}
}
</script> --><script setup>
const message = 'this is a message'
const logMessage = () => {console.log(message)
}
</script><template><div>{{ message }}</div><button @click="logMessage">按钮</button>
</template>
(2)reactive和ref函数
reactive作用:接收对象类型数据的参数传入并返回一个响应式对象
ref()作用:接收简单或者对象类型数据的参数传入并返回一个响应式对象
reactive核心步骤:
1.从vue包中导入reactive函数
2.在< script setup >中执行reactive函数并传入类型为对象的初始值并使用变量接收返回值
ref核心步骤
1.从vue包中导入ref函数
2.在< script setup >中执行ref函数并传入初始值并使用变量接收ref函数的返回值
<script setup>
// 1. reactive: 接收一个对象类型的数据,返回一个响应式的对象
// 问题:如果是简单类型,怎么办呢?
// import { reactive } from 'vue'
// const state = reactive({
// count: 100
// })
// const setCount = () => {
// state.count++
// }// 2. ref: 接收简单类型 或 复杂类型,返回一个响应式的对象
// 本质:是在原有传入数据的基础上,外层包了一层对象,包成了复杂类型
// 底层,包成复杂类型之后,再借助 reactive 实现的响应式
// 注意点:
// 1. 脚本中访问数据,需要通过 .value
// 2. 在template中,.value不需要加 (帮我们扒了一层)// 推荐:以后声明数据,统一用 ref => 统一了编码规范
import { ref } from 'vue'
const count = ref(0)
const setCount = () => {count.value++
}
</script><template><div><div>{{ count }}</div><button @click="setCount">+1</button></div>
</template>
(3)computed计算属性函数
计算属性基本思想和vue2的完全一致,组合API下的计算属性只是修改了写法
核心步骤:
1.导入computed函数
2.执行函数在回调参数中return基于响应式数据做计算的值,用变量接收
<script setup>
// const 计算属性 = computed(() => {
// return 计算返回的结果
// })import { computed, ref } from 'vue'// 声明数据
const list = ref([1, 2, 3, 4, 5, 6, 7, 8])// 基于list派生一个计算属性,从list中过滤出 > 2
const computedList = computed(() => {return list.value.filter(item => item > 2)
})// 定义一个修改数组的方法
const addFn = () => {list.value.push(666)
}
</script><template><div><div>原始数据: {{ list }}</div><div>计算后的数据: {{ computedList }}</div><button @click="addFn" type="button">修改</button></div>
</template>
(4)watch
作用:侦听一个或者多个数据的变化,数据变化时执行回调函数
两个额外参数:1.immediate(立刻执行)2.deep(深度侦听)
核心步骤:
1.导入watch函数
2.执行watch函数传入要侦听的响应式数据(ref对象)和回调参数
immediate:在侦听器创建时立刻触发回调,响应式数据变化之后继续执行回调
在不开启deep的前提下,侦听age的变化,只有age变化时才执行回调
<script setup>
import { ref, watch } from 'vue'
const count = ref(0)
const nickname = ref('张三')const changeCount = () => {count.value++
}
const changeNickname = () => {nickname.value = '李四'
}// 1. 监视单个数据的变化
// watch(ref对象, (newValue, oldValue) => { ... })
// watch(count, (newValue, oldValue) => {
// console.log(newValue, oldValue)
// })// 2. 监视多个数据的变化
// watch([ref对象1, ref对象2], (newArr, oldArr) => { ... })
// watch([count, nickname], (newArr, oldArr) => {
// console.log(newArr, oldArr)
// })// 3. immediate 立刻执行
// watch(count, (newValue, oldValue) => {
// console.log(newValue, oldValue)
// }, {
// immediate: true
// })
// --------------------------------------------
// 4. deep 深度监视, 默认 watch 进行的是 浅层监视
// const ref1 = ref(简单类型) 可以直接监视
// const ref2 = ref(复杂类型) 监视不到复杂类型内部数据的变化
const userInfo = ref({name: 'zs',age: 18
})
const setUserInfo = () => {// 修改了 userInfo.value 修改了对象的地址,才能监视到// userInfo.value = { name: 'ls', age: 50 }userInfo.value.age++
}// deep 深度监视
// watch(userInfo, (newValue) => {
// console.log(newValue)
// }, {
// deep: true
// })// 5. 对于对象中的单个属性,进行监视
watch(() => userInfo.value.age, (newValue, oldValue) => {console.log(newValue, oldValue)
})
</script><template><div>{{ count }}</div><button @click="changeCount">改数字</button><div>{{ nickname }}</div><button @click="changeNickname">改昵称</button><div>-----------------------</div><div>{{ userInfo }}</div><button @click="setUserInfo">修改userInfo</button>
</template>
(5)生命周期函数
<script setup>
import { onMounted } from 'vue';// beforeCreate 和 created 的相关代码
// 一律放在 setup 中执行const getList = () => {setTimeout(() => {console.log('发送请求,获取数据')}, 2000)
}
// 一进入页面的请求
getList()// 如果有些代码需要在mounted生命周期中执行
onMounted(() => {console.log('mounted生命周期函数 - 逻辑1')
})// 写成函数的调用方式,可以调用多次,并不会冲突,而是按照顺序依次执行
onMounted(() => {console.log('mounted生命周期函数 - 逻辑2')
})</script><template><div></div>
</template>
(6)父子通信
①父传子
1.父组件中给子组件绑定属性
2.子组件内部通过props选项接收
<script setup>
// 父传子
// 1. 给子组件,添加属性的方式传值
// 2. 在子组件,通过props接收// 局部组件(导入进来就能用)
import { ref } from 'vue'
import SonCom from '@/components/son-com.vue'const money = ref(100)
const getMoney = () => {money.value += 10
}
</script><template><div><h3>父组件 - {{ money }}<button @click="getMoney">挣钱</button></h3><!-- 给子组件,添加属性的方式传值 --><SonCom car="宝马车" :money="money"></SonCom></div>
</template>
defineProps原理:就是编译阶段的一个标识,实际编译器解析时,遇到后会进行编译转换
②子传父
1.父组件中给子组件标签通过@绑定事件
2.子组件内部通过emit方法触发事件
<script setup>
// 子传父
// 1. 在子组件内部,emit触发事件 (编译器宏获取)
// 2. 在父组件,通过 @ 监听// 局部组件(导入进来就能用)
import { ref } from 'vue'
import SonCom from '@/components/son-com.vue'const money = ref(100)
const getMoney = () => {money.value += 10
}
const changeFn = (newMoney) => {money.value = newMoney
}
</script><template><div><h3>父组件 - {{ money }}<button @click="getMoney">挣钱</button></h3><!-- 给子组件,添加属性的方式传值 --><SonCom @changeMoney="changeFn"car="宝马车" :money="money"></SonCom></div>
</template>
(7)模板引用
通过ref标识获取真实的dom对象或者组件实例对象
以获取dom为例 组件同理
1.调用ref函数生成一个ref对象
2.通过ref标识绑定ref对象到标签
<script setup>
import TestCom from '@/components/test-com.vue'
import { onMounted, ref } from 'vue'// 模板引用(可以获取dom,也可以获取组件)
// 1. 调用ref函数,生成一个ref对象
// 2. 通过ref标识,进行绑定
// 3. 通过ref对象.value即可访问到绑定的元素(必须渲染完成后,才能拿到)
const inp = ref(null)// 生命周期钩子 onMounted
onMounted(() => {// console.log(inp.value)// inp.value.focus()
})
const clickFn = () => {inp.value.focus()
}// --------------------------------------
const testRef = ref(null)
const getCom = () => {console.log(testRef.value.count)testRef.value.sayHi()
}
</script><template><div><input ref="inp" type="text"><button @click="clickFn">点击让输入框聚焦</button></div><TestCom ref="testRef"></TestCom><button @click="getCom">获取组件</button>
</template>
defineExpose()
默认情况下在< script setup >语法糖下组件内部的属性和方法是不开放给父组件访问的,可以通过defineExpose编译宏指定哪些属性和方法允许访问
(8)provide和inject
场景:顶层组件向任意的底层组件传递数据和方法,实现跨层组件通信
顶层组件通过provide函数提供数据
底层组件通过inject函数获取数据
跨层传递响应式数据
顶层provide('app-key',ref对象)
底层const message = inject('app-key')
跨层传递方法:底层组件调用方法修改顶层组件中的数据
<script setup>
import CenterCom from '@/components/center-com.vue'
import { provide, ref } from 'vue'// 1. 跨层传递普通数据
provide('theme-color', 'pink')// 2. 跨层传递响应式数据
const count = ref(100)
provide('count', count)setTimeout(() => {count.value = 500
}, 2000)// 3. 跨层传递函数 => 给子孙后代传递可以修改数据的方法
provide('changeCount', (newCount) => {count.value = newCount
})</script><template>
<div><h1>我是顶层组件</h1><CenterCom></CenterCom>
</div>
</template>