Vue3的Composition API高级语法:生命周期钩子、provide函数、inject函数、hooks提取代码案例

一、生命周期钩子

我们前面说过 setup 可以用来替代 data 、 methods 、 computed 、watch 等等这些选项,也可以替代 生命周期钩子。

那么setup中如何使用生命周期函数呢?

        可以使用直接导入的 onX 函数注册生命周期钩子;

<template>
  <div>
    <button @click="increment">{{counter}}</button>
  </div>
</template>

<script>
  import { onMounted, onUpdated, onUnmounted, ref } from 'vue';

  export default {
    setup() {
      const counter = ref(0);
      const increment = () => counter.value++

      onMounted(() => {
        console.log("App Mounted1");
      })
      onMounted(() => {
        console.log("App Mounted2");
      })
      onUpdated(() => {
        console.log("App onUpdated");
      })
      onUnmounted(() => {
        console.log("App onUnmounted");
      })

      return {
        counter,
        increment
      }
    }
  }
</script>

 

二、Provide函数、Inject函数

事实上我们之前还学习过Provide和Inject,Composition API也可以替代之前的 Provide 和 Inject 的选项。

provide

我们可以通过 provide来提供数据:

        可以通过 provide 方法来定义每个 Property;

        provide可以传入两个参数:

name:提供的属性名称;

value:提供的属性值;

inject

在 后代组件 中可以通过 inject 来注入需要的属性和对应的值:

        可以通过 inject 来注入需要的内容;

        inject可以传入两个参数:

                要 inject 的 property 的 name;

                默认值;

数据响应式

为了增加 provide 值和 inject 值之间的响应性,我们可以在 provide 值时使用 ref 和 reactive。
修改响应式Property
provide将数据传递给子孙组件,inject子孙组件接收数据,数据流最好是单向的,如顶层组件有一个counter改变,数据流传递到子孙组件counter改变,但是不能子孙组件的counter自己改变,影响顶层组件改变。如果想实现,则可以在子孙组件添加一个事件,改变counter,在顶层组件添加监听事件,监听到要改变,则在顶层组件进行counter的修改。所以顶层组件传递给子孙组件值时,用readonly属性。
如果我们需要修改可响应的数据,那么最好是在数据提供的位置来修改:
        我们可以将修改方法进行共享,在后代组件中进行调用;

//顶层组件
<template>
  <div>
    <home/>
    <h2>App Counter: {{counter}}</h2>
    <button @click="increment">App中的+1</button>
  </div>
</template>

<script>
  import { provide, ref, readonly } from 'vue';

  import Home from './Home.vue';

  export default {
    components: {
      Home
    },
    setup() {
      const name = ref("coderwhy");
      let counter = ref(100);

      provide("name", readonly(name));
      provide("counter", readonly(counter));

      const increment = () => counter.value++;

      return {
        increment,
        counter
      }
    }
  }
</script>
//子孙组件:home.vue
<template>
  <div>
    <h2>{{name}}</h2>
    <h2>{{counter}}</h2>

    <button @click="homeIncrement">home+1</button>
  </div>
</template>

<script>
  import { inject } from 'vue';

  export default {
    setup() {
      const name = inject("name");
      const counter = inject("counter");

      // 此处事件counter并不会+1,因为顶层组件传过来的是只读
      const homeIncrement = () => counter.value++

      return {
        name,
        counter,
        homeIncrement
      }
    }
  }
</script>

三、useCounter

我们先来对之前的counter逻辑进行抽取:
//在hooks中抽取出到useCounter.js
import {ref, computed} from 'vue';

export default function() {
	const counter = ref(0);
	const doubleCounter = computed(() => counter.value * 2);

	const increment = () => counter.value++;
	const decreament = () => counter.value--;


	return {
		counter,
		doubleCounter,
		increment,
		decreament
	}
}
//在app.vue中调用
<template>
	<div>
		<h2>当前计数:{{counter}}</h2>
		<h2>当前计数*2:{{doubleCounter}}</h2>
		<button @click="increment">  +1 </button>
		<button @click="decreament"> -1 </button>
	</div>
</template>
<script>
	import {ref, computed} from 'vue';
	import {useCounter} from './hooks/useCounter';//引入

	export default{
		setup() {
			// 调用获取数据
			const {counter,doubleCounter,increment,decreament} = useCounter();
			
		}
	}
</script>

四、我们编写一个修改title的Hook:

//useTitle.js
import { ref, watch } from 'vue';

export default function(title = "默认的title") {
  const titleRef = ref(title);

  watch(titleRef, (newValue) => {
    document.title = newValue
  }, {
    immediate: true
  })

  return titleRef
}
 import { ref, computed } from 'vue';
 import {
    useCounter,
    useTitle
  } from './hooks';
export default {
    setup() {
      // title
      const titleRef = useTitle("coderwhy");

      setTimeout(() => {
        titleRef.value = "kobe"
      }, 3000);

      return {
       
      }
    }
  }
</script>

五、useScrollPosition

我们来完成一个监听界面滚动位置的Hook:

//useScrollPosition.js
import { ref } from 'vue';

export default function() {
  const scrollX = ref(0);
  const scrollY = ref(0);

  document.addEventListener("scroll", () => {
    scrollX.value = window.scrollX;
    scrollY.value = window.scrollY;
  });

  return {
    scrollX,
    scrollY
  }
}
<template>
    <div class="scroll">
      <div class="scroll-x">scrollX: {{scrollX}}</div>
      <div class="scroll-y">scrollY: {{scrollY}}</div>
    </div>
</template>

<script>
  import { ref, computed } from 'vue';

  import {
    useScrollPosition,
  } from './hooks';

  export default {
    setup() {

      // 滚动位置
      const { scrollX, scrollY } = useScrollPosition();

      return {
        scrollX,
        scrollY,
      }
    }
  }
</script>

<style scoped>
  .content {
    width: 3000px;
    height: 5000px;
  }

  .scroll {
    position: fixed;
    right: 30px;
    bottom: 30px;
  }
</style>

六、useMousePosition

//useMousePosition
import { ref } from 'vue';

export default function() {
  const mouseX = ref(0);
  const mouseY = ref(0);

  window.addEventListener("mousemove", (event) => {
    mouseX.value = event.pageX;
    mouseY.value = event.pageY;
  });

  return {
    mouseX,
    mouseY
  }
}
七、useLocalStorage
​​​​​​​
//useLocalStorage.js
import { ref, watch } from 'vue';

export default function(key, value) {
  const data = ref(value);

  if (value) {
    window.localStorage.setItem(key, JSON.stringify(value));
  } else {
    data.value = JSON.parse(window.localStorage.getItem(key));
  }

  watch(data, (newValue) => {
    window.localStorage.setItem(key, JSON.stringify(newValue));
  })

  return data;
}

// 一个参数: 取值
// const data = useLocalStorage("name");

// // 二个参数: 保存值
// const data = useLocalStorage("name", "coderwhy");

// data.value = "kobe";

 

index.js:所有hooks的出口

import useCounter from './useCounter';
import useTitle from './useTitle';
import useScrollPosition from './useScrollPosition';
import useMousePosition from './useMousePosition';
import useLocalStorage from './useLocalStorage';

export {
  useCounter,
  useTitle,
  useScrollPosition,
  useMousePosition,
  useLocalStorage
}
​​​​​​​
<template>
  <div>
    <h2>当前计数: {{counter}}</h2>
    <h2>计数*2: {{doubleCounter}}</h2>
    <button @click="increment">+1</button>
    <button @click="decrement">-1</button>

    <h2>{{data}}</h2>
    <button @click="changeData">修改data</button>

    <p class="content"></p>

    <div class="scroll">
      <div class="scroll-x">scrollX: {{scrollX}}</div>
      <div class="scroll-y">scrollY: {{scrollY}}</div>
    </div>
    <div class="mouse">
      <div class="mouse-x">mouseX: {{mouseX}}</div>
      <div class="mouse-y">mouseY: {{mouseY}}</div>
    </div>
  </div>
</template>

<script>
  import { ref, computed } from 'vue';

  import {
    useCounter,
    useLocalStorage,
    useMousePosition,
    useScrollPosition,
    useTitle
  } from './hooks';

  export default {
    setup() {
      // counter
      const { counter, doubleCounter, increment, decrement } = useCounter();

      // title
      const titleRef = useTitle("coderwhy");
      setTimeout(() => {
        titleRef.value = "kobe"
      }, 3000);

      // 滚动位置
      const { scrollX, scrollY } = useScrollPosition();

      // 鼠标位置
      const { mouseX, mouseY } = useMousePosition();

      // localStorage
      const data = useLocalStorage("info");
      const changeData = () => data.value = "哈哈哈哈"

      return {
        counter,
        doubleCounter,
        increment,
        decrement,

        scrollX,
        scrollY,

        mouseX,
        mouseY,

        data,
        changeData
      }
    }
  }
</script>

<style scoped>
  .content {
    width: 3000px;
    height: 5000px;
  }

  .scroll {
    position: fixed;
    right: 30px;
    bottom: 30px;
  }
  .mouse {
    position: fixed;
    right: 30px;
    bottom: 80px;
  }
</style>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值