0


同事都说我卷,趁着午休我 —— 彻底熟练使用《Vue3的选项APi》

那啥 开始就声明解释一下mixin,它不叫米新,它叫米克僧嗯,mix +‎ in 额 就说通不通易不易懂,在本文我将以最为通俗的、让能看懂的话术解释V3Api,当然了一些概念还的是全面点!

mixin—局部

红框和绿框组件,都有相同的方法,和钩子,那么你将他们相同的剪贴走,建一个文件粘贴

进去(mixin.js 也可以是aa.js),最后导入页面,就是混合原理

配合代码更加贴切,易懂

  1. /*
  2. *
  3. * 子组件uname
  4. *
  5. /
  6. <template>
  7. <div>
  8. <h2 @click="choseName">姓名:{{ uname }}</h2>
  9. <hr />
  10. <button @click="fn">测试组件和mixin方法重复,执行谁</button>
  11. </div>
  12. </template>
  13. <script>
  14. import { MyMiXin } from "./mixin";
  15. export default {
  16. data() {
  17. return {
  18. uname: "活在风浪里。。",
  19. };
  20. },
  21. // mixins复数,因为要调用data中数据,必须写在data下面
  22. mixins: [MyMiXin],
  23. methods: {
  24. fn() {
  25. console.log("组件方法");
  26. },
  27. },
  28. created() {
  29. console.log("组件钩子");
  30. },
  31. };
  32. </script>
  1. /*
  2. *
  3. * 子组件school
  4. *
  5. /
  6. <template>
  7. <div>
  8. <h2 @click="choseName">学校:{{ uname }}</h2>
  9. <hr />
  10. <button @click="fn">测试组件和mixin方法重复,执行谁</button>
  11. </div>
  12. </template>
  13. <script>
  14. import { MyMiXin } from "./mixin";
  15. export default {
  16. data() {
  17. return {
  18. uname: "北大",
  19. };
  20. },
  21. // mixins复数,因为要调用data中数据,必须写在data下面
  22. mixins: [MyMiXin],
  23. methods: {
  24. fn() {
  25. console.log("组件方法");
  26. },
  27. },
  28. created() {
  29. console.log("组件钩子");
  30. },
  31. };
  32. </script>
  1. /*
  2. *
  3. * 父组件 引入子组件
  4. *
  5. /
  6. <template>
  7. <div id="about">
  8. <school></school>
  9. <hr />
  10. <uname></uname>
  11. </div>
  12. </template>
  13. <script>
  14. import school from "../components/school.vue";
  15. import uname from "../components/uname.vue";
  16. export default {
  17. data() {
  18. },
  19. components: { school, uname },
  20. };
  21. </script>
  1. /*
  2. *
  3. * 新建mixin JS文件
  4. *
  5. /
  6. export const MyMiXin = {
  7. // data、methods、如果和组件重复,只会执行组件的内容,mixi不会执行
  8. methods: {
  9. choseName() {
  10. alert(this.uname)
  11. },
  12. fn() {
  13. console.log('mixin方法');
  14. }
  15. },
  16. // 钩子函数事特殊的,它会合并组件的钩子,先执行mixin钩子,在执行组件钩子
  17. created() {
  18. console.log("mixin钩子");
  19. },
  20. }

如果组件与mixin冲突怎么办?总结:

  • 组件 data、method 优先级高于 Mixin 混入的 data、method
  • 组件自定义属性优先级高于 Mixin 混入的 自定义属性
  • 先执行 Mixin 的钩子,再执行组件里的钩子,会合并
  • 建议配合上面代码和图片,还是看不懂请揍我

mixin造成的问题:

首先Vue是渐进式框架,不需要必须使用它的api,可替代性很强,你可以只用我的一部分,而不是所有部分

  • 变量来源不明,不利于代码的阅读;
  • 使用多个Mixin可能会造成命名冲突;
  • Mixin和组件的关系,复杂度较高

mixin—全局

更新中。。。
什么是全局选项? 就是 全局组件,全局过滤器,全局指令,全局mixin

1、Vue.component 注册的 【全局组件】
2、Vue.filter 注册的 【全局过滤器】
3、Vue.directive 注册的 【全局指令】
4、Vue.mixin 注册的 【全局mixin】

Vue2与Vue3的区别 Options API的弊端

**相对于Vue2来说,Vue3最大的突破就是

  1. Composition API

。与现有的Vue2

  1. Option API

截然不同**

  1. 数据劫持、双向绑定之类,不在这里说,太多,太占篇幅,
  2. 比如**data定义数据、methods中定义方法、computed中定义计算属性、watch中监听属性改变,也包括生命周期钩子;假如一个大项目,逻辑很多,那么同一个功能的逻辑就会被拆分的很分散,这个组件的代码是难以阅读和理解的(阅读组件的其他人),碎片化的代码使用理解和维护变得很困难,如果我们能将同一个逻辑关注点相关的代码收集在一起**会更好,这个位置就是Vue3 setup 函数

setup函数有哪些参数?

  1. // setup函数有哪些参数?
  2. // setup函数有什么样的返回值
  3. // setup(props, context)
  4. setup(props, {attrs, slots, emit}) {//解构context
  5. console.log(props.message);
  6. console.log(attrs.id, attrs.class);
  7. console.log(slots);
  8. console.log(emit);
  9. return {
  10. }
  11. },
  • 我们先来研究一个setup函数的参数,它主要有两个参数: - 第一个参数:**props- 第二个参数:context**

props非常好理解,它其实就是父组件传递过来的属性会被放到props对象中,我们在setup中如果需要使用,那么就可以直接通过props参数获取:

**另外一个参数是

  1. context

**

  1. **attrs**:所有的非prop的attribute;
  2. **slots**:父组件传递过来的插槽
  3. **emit**:当我们组件内部需要发出事件时会用到emit

任何人写的文都不会比官方文档还要全,建议撸一遍V3官方文档

setup函数的返回值

  • 必须使用return返回

setup不可以使用this

  • 官方关于this有这样一段描述
  • 表达的含义是this并没有指向当前组件实例
  • 并且在setup被调用之前,data、computed、methods等都没有被解析;
  • 所以**无法在setup中获取this**

Vue3中 reactive 和 ref 和 toRefs 和 toRef

reactive 是vue3的一个组合api vue3中新增的最核心的功能就是组合api
** reactive vue3建议只用来声明对象 他声明的对象中的每一个属性都是响应式的**
他是结合es6的proxy 结合递归给每一个reactive声明的对象数据添加上 setter/getter方法 从而实现数据的响应式
ref是用reactive封装成的一个方法 这个方法我们通常用来声明基本数据类型和数组数据
ref声明的数据是一个对象 值是value ref在使用的时候不需要写value 但是赋值的时候必须写value
toRefs可以解构reactive对象的属性 将属性取出 转换成一个ref对象,假如你要reactive里面的obj.name,在return{}用了 ...toRefs(obj)就可以直接使用name

如果不经过toRefs,直接解构是不具备相应式的

  1. setup() {
  2. const info = reactive({name: "why", age: 18});
  3. // 1.toRefs: 将reactive对象中的所有属性都转成ref,
  4. // 如果不经过toRefs,直接解构是不具备相应式的
  5. let { name, age } = toRefs(info);
  6. return {//具备相应式
  7. name,
  8. age
  9. }
  10. }

总结ref:

  • 在模板中引入ref的值时,Vue会自动帮助我们进行解包操作,所以我们并不需要在模板中通过 ref.value 的方式来使用;
  • 但是在 setup 函数内部,它依然是一个 ref引用, 所以对其进行操作时,我们依然需要使用 ref.value的方式;

** 什么是解包:**

a解构出来相当于** a={value:xx}**

readonly只读属性

使用场景:在父传子时就可以将接受的数据定为只读,子组件不允许直接修改父组件的数据,如果一个子组件有很多父组件(子组件定义结构样式,父组件传递不同的值,以显示不同的页面),子组件修改父组件可能会造成数据混乱,因为多个父组件可能定义了相同的变量,但是可以子传父,不能直接在子组件修改父组件数据

toRef

如果我们只希望转换一个reactive对象中的属性为ref, 那么可以使用toRef的方法:

computed

  • 在V2 中选项性Options API中,我们是使用computed选项来完成的;
  • 在V3组合型Composition API中,我们可以在 setup 函数中使用 computed 方法来编写一个计算属性;
  • 两种写法,一种函数形式、一种对象形式,对象形式不能直接赋值,需要setter、getter方法调用,下面都会一一举例说明。Vue2建议参考计算属性 + Vue2 、Vue3 wacth + 过滤器_技术前端,忠于热爱-CSDN博客

比如在computed() 中不需要赋值一个变量,再比如定义方法必须赋值一个变量choseNameEv可以是aa但是对应的 点击事件也要变化

子组件:(函数写法)

  1. <template>
  2. <div>
  3. <h2>{{ resultName }}</h2>
  4. <button @click="choseNameEv">点击计算姓名</button>
  5. </div>
  6. </template>
  7. <script>
  8. import { ref, computed } from "vue";
  9. export default {
  10. components: {},
  11. setup() {
  12. const firstName = ref("tom");
  13. const lastName = ref("baby");
  14. const resultName = computed(() => firstName.value + " - " + lastName.value);
  15. const choseNameEv = () => {
  16. firstName.value = "小黑";
  17. };
  18. return {
  19. firstName,
  20. lastName,
  21. resultName,
  22. choseNameEv,
  23. };
  24. },
  25. };
  26. </script>
  27. <style lang="scss" scoped></style>

**父组件: **

  1. <template>
  2. <div>
  3. <computedChild />
  4. </div>
  5. </template>
  6. <script>
  7. import computedChild from "../components/计算属性.vue";
  8. export default {
  9. components: {
  10. computedChild,
  11. },
  12. setup() {
  13. return {};
  14. },
  15. };
  16. </script>
  17. <style lang="scss" scoped></style>

效果图:

子组件 ——— (第二种对象写法 )

  1. <template>
  2. <div>
  3. <h2>{{ resultName }}</h2>
  4. <button @click="choseNameEv">点击计算姓名</button>
  5. </div>
  6. </template>
  7. <script>
  8. import { ref, computed } from "vue";
  9. export default {
  10. components: {},
  11. setup() {
  12. // 1、定义数据
  13. const firstName = ref("jack");
  14. const lastName = ref("Biu");
  15. const resultName = computed({ // 对象写法: 传入一个对象, 对象包含getter/setter
  16. // 2、 利用get得到数据
  17. get: () => firstName.value + " " + lastName.value,
  18. // 3 、利用set设置数据 set的形参就是要赋的值(code)
  19. set(newValue) {
  20. lastName.value = newValue
  21. },
  22. });
  23. const choseNameEv = () => {
  24. lastName.value = "code";//将code,赋值 firstName.value
  25. };
  26. return {
  27. firstName,
  28. lastName,
  29. resultName,
  30. choseNameEv,
  31. };
  32. },
  33. };
  34. </script>
  35. <style lang="scss" scoped></style>

其实和Vue2差不多,下面是Vu2的

  1. <template>
  2. <div class="home">
  3. 商品价格--- {{sumPrice}}
  4. <button @click="changePrice">修改商品价格</button>
  5. </div>
  6. </template>
  7. <script>
  8. export default {
  9. name: "Home",
  10. data() {
  11. return {
  12. // 1 定义数据
  13. price: 123,
  14. num: 666,
  15. };
  16. },
  17. computed: {
  18. sumPrice: {
  19. // 2 在get中将数据return出去
  20. get() {
  21. return this.price;
  22. },
  23. //3 手动添加set方法 修改值 形参就是事件赋的值
  24. set(val) {
  25. // console.log(val); val就是赋的值
  26. this.price = val;
  27. },
  28. },
  29. },
  30. methods: {
  31. // 4 点击按钮的事件 对象不能直接赋值,需要手动添加get/set方法 现在就可以直接赋值
  32. changePrice() {
  33. //直接写死值
  34. // this.sumPrice = 1234;
  35. // 动态变量值
  36. this.sumPrice = this.num;
  37. },
  38. },
  39. };
  40. </script>

效果图:

Wacth监听

  • watchEffect:在watchEffect对象里的数据,会被自动收集
  • wacth:需要手动指定要监听的数据

Vue2 watch监听

  1. // Vue2 简写wacth
  2. watch: {
  3. sum (newValue, oldValue) {
  4. console.log("sum的数值的变换新值、老值", newValue, oldValue);
  5. }
  6. },
  1. //完整写法
  2. watch: {
  3. obj: {
  4. handler (newvalue, oldvalue) {
  5. console.log(newvalue, oldvalue)
  6. },
  7. immediate: true, //立即监听
  8. deep: true // 深度监听
  9. }
  10. },
  1. // 监听路由:
  2. wacth:{
  3. "$router.path":(new,old)=>{
  4. console.log(new,old)
  5. }
  6. }

vue3 watch的使用

  • 如果要监听对象某一个值,例如person,在wacth小括号里以箭头函数形式监听对象某一个值 例如
  1. watch(() =>person.name, (newVal, oldVal)=> {
  2. console.log(newVal, oldVal)
  3. })

如果监听person对象里的多个值:wacth小括号中以数组形式书写,在数组中用箭头函数 例如:

  1. watch([() =>person.name, ()=> person.age], (newVal, oldVal)=> {undefined
  2. console.log(newVal, oldVal)
  3. })
  • 监听ref数组简单类型
  1. //监听ref单一值的变化
  2. watch(监听的值, (newvAL, oLdVal) => {
  3. console.log(newvAL, oLdVal)
  4. })
  1. // 监听ref多个值的变化 数组形式
  2. watch([msg, sum], (newVal, oldVal) => {
  3. console.log(newVal, oldVal)
  4. })
  • 监听ractive复杂对象类型
  1. // 监听reactive中的整个person对象
  2. watch(person, (newVal, oldVal)=> {
  3. console.log(newVal, oldVal)
  4. }, {deep: true})
  1. // 监听reactive对象中某一个属性的变化
  2. watch(() =>person.name, (newVal, oldVal)=> {
  3. console.log(newVal, oldVal)
  4. })
  1. //监听person对象里的某一个值,开启深度监听
  2. watch([() => person.job], (newVal, oldVak) => {
  3. console.log(newVal, oldVak)
  4. }, {deep: true})
  1. //监听person对象里的某两个值
  2. watch([() =>person.name, ()=> person.age], (newVal, oldVal)=> {
  3. console.log(newVal, oldVal)
  4. })

注意:wacth监听打印新旧值都是一样的,因为监听的同一条数据,监听的都是同一个引用

  1. <template>
  2. <div>
  3. <h1>{{ obj.age }}</h1>
  4. <button @click="choseAge">修改age</button>
  5. </div>
  6. </template>
  7. <script>
  8. import { reactive, watch } from "vue";
  9. export default {
  10. components: {},
  11. setup() {
  12. const obj = reactive({ name: "tom", age: 18, sex: "女" });
  13. const choseAge = () => {
  14. obj.age++;
  15. };
  16. watch(
  17. //watch写在setup中,第一个形参是监听的数据,第二个是新值旧值
  18. () => obj,
  19. (newVal, oldVal) => {
  20. console.log("新" + newVal.age, "旧" + oldVal.age);
  21. },
  22. { deep: true },
  23. { immediate: false }
  24. );
  25. return { obj, choseAge };
  26. },
  27. };
  28. </script>
  29. <style lang="scss" scoped></style>

总结:vue3 wacth后是一个小括号,在小括号中操作,如果要监听ref单个的值,监听的值逗号箭头函数,箭头函数里面有两个形参,new,old,可以在对象中直接打印,

监听多个值,可以在监听值的地方使用数组,多个值以逗号分隔

监听ractive复杂对象类型 :wacth小括号,监听的对象逗号箭头函数,箭头函数中有两个值,new,old,在箭头函数对象中可以直接打印,如果要开启深度监听,在箭头函数后面加逗号,逗号后面是对象,对象中开启deep:true

Vue3 watchEffect

  • 自动收集依赖,简单来说watchEffect 小括号里的数据都会被监听
  1. <template>
  2. <div>
  3. <h2>{{ uname }}-{{ age }}</h2>
  4. <button @click="choseNameEv">修改uname</button>
  5. <button @click="choseAgeEv">修改age</button>
  6. </div>
  7. </template>
  8. <script>
  9. import { ref, watchEffect } from "vue";
  10. export default {
  11. setup() {
  12. const uname = ref("活在分浪里。。");
  13. const age = ref(18);
  14. const choseNameEv = () => (uname.value = "tom");
  15. const choseAgeEv = () => age.value++;
  16. // watchEffect: 自动收集响应式的依赖
  17. // 在watchEffect方法里会自动监听
  18. watchEffect(() => {
  19. console.log("uname:", uname.value, "age:", age.value);
  20. });
  21. return {
  22. uname,
  23. age,
  24. choseNameEv,
  25. choseAgeEv,
  26. };
  27. },
  28. };
  29. </script>

watchEffect的停止侦听

如果在发生某些情况下,我们希望停止侦听,这个时候我们可以获取watchEffect的返回值函数,调用该函数即可。

  • 比如在上面的案例中,我们age达到22的时候就停止侦听:

思路:watchEffect的返回值,在终于条件哪里调用

  1. <template>
  2. <div>
  3. <h2>{{ uname }}:{{ age }}</h2>
  4. <button @click="choseNameEv">修改uname</button>
  5. <button @click="choseAgeEv">修改age</button>
  6. </div>
  7. </template>
  8. <script>
  9. import { ref, watchEffect } from "vue";
  10. export default {
  11. setup() {
  12. const uname = ref("活在分浪里。。");
  13. const age = ref(18);
  14. const choseNameEv = () => (uname.value = "tom");
  15. const choseAgeEv = () => age.value++;
  16. // 利用watchEffect的返回值(它是一个方法,你也可以const aa)
  17. const stop = watchEffect(() => {
  18. if (age.value >= 22) {//age>=22就不会检测,也就是不会打印下面log
  19. stop();
  20. }
  21. console.log("uname:", uname.value, "age:", age.value);
  22. });
  23. return {
  24. uname,
  25. age,
  26. choseNameEv,
  27. choseAgeEv,
  28. };
  29. },
  30. };
  31. </script>

watchEffect清除副作用

就是防抖思路,假如用watchEffect检测Ajax请求,例如查询搜索:要在本次点击或输入之前,清除上一次的请求,

主要思路就是watchEffect的 onInvalidate 参数,watchEffect的停止侦听是利用返回值,请求异步检测则需要利用onInvalidate 参数清除上一次请求

  1. <template>
  2. <div>
  3. <!-- 狂点按钮,只会打印最后一次请求 -->
  4. <h2>{{ age }}</h2>
  5. <button @click="choseAge">修改age</button>
  6. </div>
  7. </template>
  8. <script>
  9. import { ref, watchEffect } from "vue";
  10. export default {
  11. setup() {
  12. const age = ref(12);
  13. watchEffect((onInvalidate) => {
  14. // 点击按钮就会修改age,但是写了onInvalidate,会先执行onInvalidate里的逻辑
  15. console.log( age.value);// 3
  16. onInvalidate(() => {
  17. // 这里面写清除方法
  18. // request.cancel() //ajax清除方法,现在是用定时器模拟ajax
  19. clearTimeout(timer);// 1
  20. console.log("onInvalidate");// 2
  21. });
  22. const timer = setTimeout(() => {// 4
  23. console.log("网络请求成功");
  24. }, 1000);
  25. });
  26. const choseAge = () => age.value++;
  27. return {
  28. age,
  29. choseAge,
  30. };
  31. },
  32. };
  33. </script>

setup中使用 ref 获取dom

思路:主要是利用 watchEffect箭头函数后的对象里的 ** flush: "post"****, watchEffect(
() => { }, **

** {
flush: "post", //默认 flush: "async" 异步
}**
** );**

  1. <template>
  2. <div>
  3. <h2 ref="title">恭喜你有学到了</h2>
  4. </div>
  5. </template>
  6. <script>
  7. import { ref, watchEffect } from "vue";
  8. export default {
  9. setup() {
  10. const title = ref(null);
  11. console.log(title.value); // 这里还是null,写了 flush: "post",就可以拿到dom
  12. watchEffect(
  13. () => {
  14. console.log(title.value);//<h2>恭喜你有学到了</h2>
  15. title.value.style.color='red'
  16. },
  17. {
  18. flush: "post", //默认 flush: "async" 异步
  19. }
  20. );
  21. return {
  22. title,
  23. };
  24. },
  25. };
  26. </script>

vue2 ref 获取dom

  1. <template>
  2. <div>
  3. <h1 ref="title">vue2获取dom</h1>
  4. </div>
  5. </template>
  6. <script>
  7. export default {
  8. data() {
  9. return {};
  10. },
  11. created() {
  12. this.$nextTick(() => {
  13. this.$refs.title.style.backgroundColor = "green";
  14. });
  15. },
  16. };
  17. </script>
  18. <style lang="scss" scoped>
  19. //@import '引入的css文件';
  20. </style>

本文转载自: https://blog.csdn.net/m0_57904695/article/details/123064289
版权归原作者 0.活在风浪里 所有, 如有侵权,请联系我们删除。

“同事都说我卷,趁着午休我 &mdash;&mdash; 彻底熟练使用《Vue3的选项APi》”的评论:

还没有评论