vue3学习01composition API

97 阅读1分钟

vue3 composition API setup(){}的使用

<template>
  <div>
    setup
    <!-- ref创建的数据对象在teplate内不需要.value -->
    {{ count }}
    double:{{ double }} age: {{ user.age }}
    <button ref="btn" @click="handleClick">click</button>
    <button @click="handleChangeUserAge">change - age</button>
  </div>
</template>

<script>
/* 引入setup中需要用到的方法
ref 创建要使用.value的响应式数据,类似JS中的number string,
ref 创建单一数据对象,来创建对象也需要使用.value来修改
reactive 创建proxy的响应试数据,类似JS中的object,创建对象形数据对象 
readonly 创建一个不能修改的reactive
computed 创建计算属性响应式对象
watch 监听响应式数据
watchEffect 监听组件内所有数据的变化,第一次创建会自动执行

*/
import {ref, reactive, readonly, computed, watch, watchEffect} from "vue";
export default {
  name: "HelloWorld",
  //父组件传进来的props对象
  props: {
    msg: String,
  },
  created() {
    // ....
  },
  //setup 内获取到父组件传进来的props,setup(props){},props不能修改
  setup(props) {
    // 新的 composition api 出现的
    // 当前组件初始化的入口
    // 响应式数据对象
    //ref创建数据对象
    let count = ref(1);
    // 和 ref 类型一致 ,都要有.value,来读取/修改数据
    const double = computed(() => {
      return count.value * 2;
    });
    // 计算属性创建的响应式对象和依赖属于一致

    //reactive创建数据对象
    // 引入类型 对象  数组
    let user = reactive({ name: "xiaohong", age: 18 });
    //readonly 创建数据对象
    //readonly  不可以修改的
    const readonlyUser = readonly({ name: "xiaohong", age: 18 });
    //在内部创建的Function,只要return出去,就可以在外部使用
    const handleClick = (e) => {
      console.log(e);
      // console.log(count)
      // value 有点心理负担
      count.value++;
      // eslint
    };
    //wacth监听ref创建的数据
    watch(count,(newValue, oldValue) => {
        console.log("watch - count");
        console.log(newValue, oldValue);
      },{
        immediate: true,
      }
    );
    //wacth监听reactive创建的数据对象单值
    watch(() => user.age,(newVal, oldVal) => {
        console.log("watch -- user.age");
        console.log(newVal);
        console.log(oldVal);
      }
    );
    watchEffect(() => {
      // 函数
      // 1. 不需要详细的指定观察谁
      // 2. 它获取不到之前的值
      console.log("watch-effect");
      console.log(user.age);
    });
    // 必须返回一个对象
    // 返回的数据 就是暴露给 template 用的
    return {
      btn,
      handleChangeUserAge,
      handleClick,
      count,
      user,
      double,
    };
  },
};
</script>

vue3 生命周期对比

image.png 生命周期使用

<template>
  <div>
    setup
    <button ref="btn" >click</button>
  </div>
</template>

<script>
/* 引入setup中需要用到的方法
onMounted 引入的生命周期函数

*/
import {onMounted} from "vue";
export default {
  name: "HelloWorld",
 
  created() {
    // ....
  },
  //setup 替代vue2 的created生命周期
  setup(props) {
    //在vue2中使用created和beforeCreated的函数,可放在这里
    
    // 生命周期函数 onMounted可以有多个
    onMounted(() => {
      console.log("mounted - 1");
    });

    onMounted(() => {
      console.log("mounted - 2");
    });
    // refs获取dom元素
    const btn = ref(null);
    onMounted(() => {
        //
      console.log(btn);
    });

    return {
      //导出setup的函数
    };
  },
};
</script>

为什么引入composition api

A、更好的代码组织与逻辑复用 更好的代码组织,可以把同一功能的代码集中到一块。不需要反复横跳。

<template>
  <div>
    foo
    {{ one }}
  </div>
</template>

<script>
import { ref } from "vue";
export default {
  setup() {
    // 在setup中引入代码的组合
    // 功能1
    // 代码组织方式的全新变更
    // 组合的思想
    // 多用组合 少用继承
    // vue3 函数式编程的思想
    // 一个函数 是不是就是可以复用的
    const { one } = oneFeature();
    // const { two } = twoFeature();
    // const { three } = threeFeature();

    return {
      one,
    };
  },
};

function oneFeature() {
  const one = ref("one");
  const oneF = () => {
    console.log(one);
  };
  return {
    one,
    oneF,
  };
}
</script>

<style></style>

更好的逻辑复用 uerMove.js

//引入需要用到的JS
import {ref, onMounted, onUnmounted } from "vue";
export function useMove() {
  const x = ref(0);
  const y = ref(0);
  const handleKeyup = (e) => {
    console.log(e.code);
    // 上下左右 x y
    switch (e.code) {
      case "ArrowUp":
        y.value--;
        break;
      case "ArrowDown":
        y.value++;
        break;
      case "ArrowLeft":
        x.value--;
        break;
      case "ArrowRight":
        x.value++;
        break;
    }
  };
  onMounted(() => {
    window.addEventListener("keyup", handleKeyup);
  });
  onUnmounted(() => {
    window.removeEventListener("keyup", handleKeyup);
  });
  return {
     x,
     y,
  };
}


调用uerMove.js的Foo.vue

<template>
  <div>{{ x }} -- {{ y }}</div>
</template>
<script>
import { useMove } from "./useMove";
export default {
  // fooMixin  x,y
  // 1. 来源不清晰
  // 2. 命名冲突
  //   mixins: [MoveMixin, fooMixin, barMixin, otherMixin],
  setup() {
    // 来源清晰
    // 命名冲突
    // const { x, y } = useMove();
    // const { x: XXA, y: XXB } = useXX();
    return {
      x,
      y,
    };
    return { x, y };
  },
};
</script>

B、更好的类型推导

响应式对象丢失解决方法:

原因:是因为在setup内解构,造成响应对象丢失:

setup(){
    let position = reactive(x:0,y:0)
    //响应式对象丢失
    const { x, y } = position;
    return{
        x,
        y
    }
}

解决方法 import { toRefs } from "vue";

setup(){
    let position = reactive(x:0,y:0)
    //解决响应式对象丢失
    const { x, y } = toRefs(position);
    return{
        x,
        y
    }
}