1.生命周期钩子
setup可以用来代替methods、data、watch等这些选项,也可以替代生命周期钩子。
可以直接导入以on开头的函数注册生命周期钩子;
import {onUpdated,onBeforeUpdate} from "vue"
然后在setup中使用函数即可:
setup() {
onUpdated(()=>{
console.log("updated")
})
}
2.Provide和inject函数
provide给子组件提供数据,一般相邻的组件传递数据使用props,不相邻组件使用provide; inject子组件接受父组件传输过来的数据。
父组件:
<template>
<div>
<home></home>
<button @click="increment">app+1</button>
</div>
</template>
<script>
// 导入provide函数
import {provide,ref,readonly} from "vue";
import Home from "./Home.vue";
export default{
components:{
Home
},
setup() {
const name =ref("phoebe");
const counter = ref(100);
// 将传输数据设置为readonly模式;子组件则不能修改数据
provide("name",readonly(name));
provide("counter",readonly(counter))
// 响应式使counter+1
const increment=()=>{
counter.value++
}
return{
increment
}
}
}
</script>
子组件:
<template>
<div>
<h2>{{name}} {{counter}}</h2>
<button @click="homeInrement">home +1</button>
</div>
</template>
<script>
import {inject} from "vue";
export default{
setup() {
// inject 接受传入的数据
const name = inject("name");
const counter =inject("counter")
// 一般情况不能在子组件中使父组件的数据更改,不符合数据的单向传输
// 所以要在父组件中设置传输来的数据为只读模式
const homeInrement = ()=>{counter.value++}
return{
name,
counter,
homeInrement
}
}
}
</script>
3.代码练习
练习1:体会compositionAPI: 将功能模块的代码提取到hook中,方便后期管理和修改;
<template>
<div>
<h2>{{counter}}</h2>
<h2>{{doubleCounter}}</h2>
<button @click="increment">+1</button>
<button @click="decrement">-1</button>
</div>
</template>
<script>
// import {ref,computed} from "vue";
import useCounter from "./hooks/useCounter.js"
export default{
setup() {
const {counter,doubleCounter,increment,decrement} = useCounter();
//提取到hooks里面
// const counter=ref(0);
// // 计算属性得使用computed
// const doubleCounter = computed(()=>counter.value*2)
// const increment = ()=> {counter.value++}
// const decrement = ()=> {counter.value--}
return {
counter,
doubleCounter,
increment,
decrement
}
}
}
</script>
useCounter.js文件(提取的代码):
import {ref,computed} from "vue";
export default function(){
const counter=ref(0);
// 计算属性得使用computed
const doubleCounter = computed(()=>counter.value*2)
const increment = ()=> {counter.value++}
const decrement = ()=> {counter.value--}
return {
counter,
doubleCounter,
increment,
decrement
}
}
练习2:通过hook修改页面的title
useTitle.js文件:
import { ref, watch } from "vue";
export default function(title= "默认"){
const titleRef = ref(title);
watch(titleRef, (newvalue) =>{
document.title=newvalue;
},{
immediate:true
})
return{
titleRef
}
}
App.vue:
import useTitle from "./hooks/useTitle.js"
export default{
setup() {
// 修改title
const titleRef =useTitle("phoebe");
// 定时修改title
setTimeout(() => {
titleRef.value = "lily"
},1000);
}
}
练习3:在页面右下角显示页面滚动坐标 hooks中的usescrollposition.js文件:
import {ref} from "vue"
export default function(){
// 滚动位置
// 默认情况下的滚动位置
const scrollX =ref(0)
const scrollY =ref(0)
// 监听scoll
document.addEventListener("scroll",()=>{
scrollX.value=Math.round(window.scrollX)
scrollY.value=Math.round(window.scrollY)
})
return{
scrollX,
scrollY
}
}
App文件:
<template>
<div>
<p class="content"></p>
<!-- 展示X,Y滚动坐标 -->
<div class="scroll">
<div class="scoll-x">scollX:{{ scrollX}}</div>
<div class="scoll-y">scollY:{{ scrollY}}</div>
</div>
</div>
</template>
//....
import usescrollposition from "./hooks/usescrollposition.js"
export default{
setup() {
//....
const {scrollX,scrollY} =usescrollposition();
return{ scrollX ,scrollY}
}
}
<style scpode>
.content{
width: 3000px;
height: 4000px;
}
.scroll{
position: fixed;
right: 30px;
bottom: 30px;
}
</style>
4.监听鼠标位置的hook
import {ref} from "vue"
export default function(){
// 滚动位置
// 默认情况下的滚动位置
const mouseX =ref(0)
const mouseY =ref(0)
// 监听scoll
window.addEventListener("mousemove",(event)=>{
mouseX.value=event.pageX
mouseY.value=event.pageY
})
return{
mouseX,
mouseY
}
}
在App.vue引入即可:import usemouseposition from "./hooks/usemouseposition.js" 使用:const{ mouseX,mouseY} = usemouseposition() 要有返回值:return {mouseX, mouseY}
5.使用hook进行本地保存
import { ref,watch } from "vue"
export default function(key,value){
const data = ref(value)
if(value){
//如果有value就是要保存数据
window.localStorage.setItem(key,JSON.stringify(value))
}
else{
// 如果没有value就是要获取数据
data.value = JSON.parse(window.localStorage.getItem(key))
}
//数据发生变化,修改值后再保存
watch(data,(newvalue)=>{
window.localStorage.setItem(key,JSON.stringify(newvalue))
})
return data;
}
import uselocalstorage from "./hooks/uselocastorage.js"
//...
export default{
setup() {
//....
//保存数据到本地服务器 {name:"phoebe",age:18}
const data = uselocalstorage("info")
// 修改数据
const changedata = ()=> data.value="hahah "
return {data,
changedata}
}
}
这里导入有很多,可以将这些代码提取出来,在hooks文件夹中新建index.js文件:
import useCounter from "./useCounter.js"
import useTitle from "./useTitle.js"
import usescrollposition from "./usescrollposition.js"
import usemouseposition from "./usemouseposition.js"
import uselocalstorage from "./uselocastorage.js"
export {
useCounter,
useTitle,
uselocalstorage,
usemouseposition,
usescrollposition
}
在App.vue中这样使用即可:
import {
useCounter,
useTitle,
uselocalstorage,
usemouseposition,
usescrollposition
} from "./hooks/index.js"
4.setup的顶级写法
<script setup>
每个 *.vue 文件最多可以包含一个 <script setup>。 (不包括一般的 <script> )
这个脚本块将被预处理为组件的 setup() 函数,这意味着它将为每一个组件实例都执行。<script setup> 中的顶层绑定都将自动暴露给模板。 更多细节,可以到vue官网上查看。
5. 认识h函数
vue推荐使用模板创建html,但一些特殊场景,需要JavaScript的完全编程的能力,可以使用渲染函数,比模板更接近编译器。 h() 是 hyperscript 的简称——意思是“能生成 HTML (超文本标记语言) 的 JavaScript”。
Vue 提供了一个 h() 函数用于创建 vnodes
h()函数怎么使用?
h()函数接收三个参数 第一个参数:是标签的名称、组件、异步组件或者函数式组件 第二个参数:标签的属性, 第三参数:标签中的内容 如果使用render函数的话,就不需要写template标签了
<script>
import { h } from "vue"
export default{
render() {
return h("h2",{class:"title"},"hello render")
}
}
</script>
h函数实现计数器
<script>
import {
h
} from "vue"
export default {
data(){
return{
counter : 0
}
},
render() {
return h("div",{class:"app"},[
// h("h2",null,'当前计数: this.counter),
h('h2',null,`当前计数:${this.counter}`),
h("button",{onClick:()=> this.counter++},"+1"),
h("button",{onClick:()=> this.counter--},"-1")
])
}
}
</script>
也可以使用setup替代data使用
import {h,ref} from "vue"
export default {
setup(){
const counter=ref(0)
return {counter}
}
//....
}
也可以在setup中写render函数
setup(){
const counter=ref(0)
return ()=>{
return h('div',{
class:'app'
},[
h('h2',null,`当前计数:${counter.value}`),
h('button',{
onClick:()=>counter.value++
},'+1'),
h('button',{
onClick:()=>counter.value--
},'-1')
])
}
}
在h函数中传入组件 App.vue
<script>
import {
h
} from "vue";
import HelloWorld from "./HelloWorld.vue";
export default {
render() {
return h(HelloWorld,null,"")
}
}
</script>
HelloWorld.vue
<script>
import { h } from "vue"
export default{
render() {
return h("h2",null,"Hello World")
}
}
</script>
也可以传入插槽
app.vue
<script>
import { h } from "vue";
import helloword from "./1/helloword.vue";
export default {
render() {
return h(helloword, null, {
default:props=>h('span',null,'传到helloword的内容')
});
},
};
</script>
helloword.vue
<script>
import {h} from 'vue'
export default {
render(){
return h("div",null,[
h('h2',null,'helloword'),
this.$slots.default ? this.$slots.default() : h('span',null,'插槽默认值'),
])
}
}
</script>
jsx的使用 现在的vue脚手架内置这些插件,所以可以直接编写jsx代码。
<script>
import { h } from "vue";
export default{
data(){
return {
counter:0
}
},
render() {
const increment=()=>this.counter++
const decrement=()=>this.counter--
return (
<div>
<h2>当前计数:{this.counter}</h2>
<button onClick={increment}>+</button>
<button onClick={decrement}>-</button>
</div>
)
}
}
</script>
|