vue3基础用法记录

本文介绍了Vue3中如何使数据变得响应式,包括使用ref和reactive处理基础类型和引用类型数据,以及如何利用computed和watch进行计算属性和数据监听。此外,还展示了如何通过自定义hooks实现逻辑复用,如鼠标坐标和异步请求,并展示了在TS环境下的类型推断应用。
摘要由CSDN通过智能技术生成

ref

vue3中的数据默认都是不具备响应式的,想要把数据变成响应式就需要做处理

ref用于处理基础数据类型,reactive用于处理引用类型的数据

//vue3中,所有方法都是按需引入的,需要什么自己手动引入
import { computed, defineComponent ,reactive,ref,toRef, toRefs} from 'vue';
setup() {
    const obj = reactive({  //处理引用类型数据,使其变成响应式
      msg: 0,
      count: 1,
    })
    const info=ref('nihao')  //用ref包裹使其变成响应式数据
    const double= computed(() => { return obj.count * 2 })
    const change = () => { obj.msg++;info.value='hello' }
    
    //如果是对象,我们要把数据return出去为了方便书写,一般我们要把对象直接解构
    //直接解构出去不是响应式数据,会造成页面数据不更新,这时候我们用torefs包裹再解构就可以了
    const obj2=toRefs(obj)
    return {  //最后要吧数据和方法return出去
      ...obj2,double,change,info
    }
  }

watch的用法

//用法一 ,监听一个值
//第一个参数传要简单的数据,这个数据变化了会执行第二个函数
// 函数里面默认记录监听数据的新值和旧值
 watch(gretings, (nValue, oValue) => {
      document.title = "updata" + gretings.value;
      console.log(nValue, oValue);
   });

// 用法二  监听多个值,
//这个时候第一个参数可以是数组,会监听数组里每一个值的变化
 setup() {
    const data = reactive({
      count: 0,
    });
    const gretings = ref("");
    const datas = toRefs(data);
    const updataGretings = () => {
      gretings.value += "hello";
    };
    const addCount = () => {
      data.count++;
    };
    //直接把data对象类型的数据放进来监听,我们发现它的值打印出来是proxy,
    //那我们不要监听整个对象,就想监听对象里的某一个数据
    watch([gretings, data], (nValue, oValue) => {
      document.title = "updata" + gretings.value;
      console.log("新", nValue);
      console.log("旧", oValue);
    });
    return {
      ...datas,
      updataGretings,
      addCount,
    };
  },
//监听对象里的某一个数据
 setup() {
    const data = reactive({
      count: 0,
    });
    const gretings = ref("");
    const datas = toRefs(data);
    const updataGretings = () => {
      gretings.value += "hello";
    };
    const addCount = () => {
      data.count++;
    };
    //监听对象里的某一个对象,我们可以用箭头函数的写法
    watch([gretings, ()=>data.count], (nValue, oValue) => {
      document.title = "updata" + gretings.value;
      console.log("新", nValue);
      console.log("旧", oValue);
    });
    return {
      ...datas,
      updataGretings,
      addCount,
    };
  },

watch监听对象中的某一个值变化,完美拿到变化值
在这里插入图片描述

一个小案例

实现点击页面 显示坐标

setup() {
    let x = ref(0);
    let y = ref(0);
    const updataMouse = (e: MouseEvent) => {
      x.value = e.pageX;
      y.value = e.pageY;
    };
    onMounted(() => {
      // 挂载完毕执行
      document.addEventListener("click", updataMouse);
    });
    onUnmounted(() => {
      // 实例卸载成功后移除点击事件
      document.removeEventListener("click", updataMouse);
    });
    return {
      updataMouse,
      x,
      y,
    };
  },

vue3最伟大之处,组件抽离,实现逻辑复用,

把刚刚那个小案例,封装成一个hooks,调用的时候引入
注意一般我们自定义的hooks都要用use开头命名

新建 useMounse.ts 文件

import { ref , onMounted,onUnmounted} from 'vue'

function useMounse() {
  const x = ref(0);
  const y = ref(0);
  const updataMouse = (e: MouseEvent) => {
      x.value = e.pageX;
      y.value = e.pageY;
  };
  onMounted(() => {
  // 挂载完毕执行
  document.addEventListener("click", updataMouse);
  });
  onUnmounted(() => {
  // 实例卸载成功后移除点击事件
  document.removeEventListener("click", updataMouse);
  });
  return {
      x,y
  }
}
export default useMounse

把刚刚封装的代码引入使用

// 引入封装好的hooks
import useMounse from "../hooks/useMounse";
export default defineComponent({
  name: "HomeView",
  setup() {
    // 取出x , y 一样能实现效果,而且代码更简洁
    const { x, y } = useMounse();
    return {
      x,
      y,
    };
  },
});

封装一个异步请求,加载状态


// 封装一个自定义 hooks 来请求图片

import { reactive,toRefs} from 'vue'
import axios from 'axios'

function useLoading(url:string) {
    const state = reactive({
        loading: true,
        loaded: false,
        result: null,
        error:null
    })
    axios.get(url).then((e) => {
        state.result = e.data
        state.loading = false
        state.loaded = true
    }).catch((e) => {
        state.error = e
    })
    const states = toRefs(state)
    return {
        ...states
    }
}
export default useLoading

vue组件中使用


<template>
  <div class="home">
    <!-- 请求没回来就显示加载中 -->
    <h1 v-if="loading">加载中....</h1>
    <!-- 加载完毕后 把图片显示出来 -->
    <img v-if="loaded" :src="result.message" />
  </div>
</template>

<script lang="ts">
import { defineComponent } from "vue";
// 引入封装好的hooks
import useUrlLoading from "../hooks/useLoading";
export default defineComponent({
  name: "HomeView",
  setup() {
    const { result, loading, loaded } = useUrlLoading(
      //传入url
      "https://dog.ceo/api/breeds/image/random"
    );
    return {
      result,
      loading,
      loaded,
    };
  },
});
</script>

把小案例改造成支持TS类型推断


// 利用泛型 对接口返回值定义类型

// hooks页面

import { reactive,toRefs} from 'vue'
import axios from 'axios'
// 使用ts改造,让返回结构有类型提示
// 这里使用泛型
function useLoading<T>(url:string) {
    const state = reactive({
        loading: true,
        loaded: false,
        result:<T|null> null,  //result初始值还是设置成null 类型是传入的泛型或者null
        error:null
    })
    axios.get(url).then((e) => {
        state.result = e.data
        state.loading = false
        state.loaded = true
    }).catch((e) => {
        state.error = e
    })
    const states = toRefs(state)
    return {
        ...states
    }
}
export default useLoading

vue组件页面


<template>
  <div class="home">
    <!-- 请求没回来就显示加载中 -->
    <h1 v-if="loading">加载中....</h1>
    <!-- 加载完毕后 把图片显示出来 -->
    <!-- 返回值要判断,如果不是null我们才让它dianmessage -->
    <img v-if="loaded" :src="result?.message" />
  </div>
</template>

<script lang="ts">
import { defineComponent } from "vue";
// 引入封装好的hooks
import useUrlLoading from "../hooks/useLoading";
export default defineComponent({
  name: "HomeView",
  setup() {
    // 申明泛接口
    interface useResult {
      // 接口返回什么数据就申明什么数据
      message: string;
      status: string;
    }
    const { result, loading, loaded } = useUrlLoading<useResult>(
      //传入url
      "https://dog.ceo/api/breeds/image/random"
    );
    return {
      result,
      loading,
      loaded,
    };
  },
});
</script>

setup语法糖

defindefineEmits,defineProps

setup语法糖模式下 不需要引入,直接使用发射事件

子组件中


//子组件中

<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
    <input type="button" value="子级按钮" @click="jumpClick" />
  </div>
</template>

<script lang="ts" setup>
import { ref } from 'vue';
const num = ref(10);
//直接使用无需引入
//父传子
defineProps({
  msg: String,
});
// 声明泛型接口,约束类型
interface Emits {
  (event: 'clickChange', num: number): void;
}
//子传父
// 先定义emit 不能直接使用 defindefineEmits
const emit = defineEmits<Emits>();
const jumpClick = function () {
  emit('clickChange', num.value);
};
</script>

父组件中

<template>
  <div class="home">
    <HelloWorld
      msg="Welcome to Your Vue.js + TypeScript App"
      @click-change="accept"
    />
    <button @click="change">点我</button> <br />
    {{ obj.msg }} <br />
    {{ double }} <br />
    {{ info }}
  </div>
</template>

<script lang="ts" setup>
//组件导入直接使用 无需注册,数据直接使用,无需返回
import { computed, reactive, ref, toRef, toRefs } from 'vue';
import HelloWorld from '@/components/HelloWorld.vue'; // @ is an alias to /src
const obj = reactive({
  msg: 0,
  count: 1,
});
const info = ref('nihao');
const double = computed(() => {
  return obj.count * 2;
});
const change = () => {
  obj.msg++, (info.value = 'hello');
};
//接受子组件传过来的值
const accept = (hello: number) => {
  console.log(hello);
};
</script>

defineExpose暴露自己的属性供父组件使用

子组件中


// 想让父组件引用子组件ts不提示报错,那我们就要什么个数据接口来限制类型
export interface sonApi {
  num: number;
  outPush: () => void; //定义函数类型无返回值
}
const num = ref(100);
const outPush = () => {    // 函数类型定义
  console.log('hello word');
};

//把我们想暴露出去的数据方法写这里
defineExpose({
  num,
  outPush,
});

父组件中


// 获取子组件值的声明,值开始必须是null,名字要跟模板上ref='child'一致
// 接口定义联合类型,null或者sonApi,这样下面就不会报错
const child = ref<sonApi | null>(null);

// 挂载成功后获取子组件暴露出来的值
onMounted(() => {
  console.log(child.value?.num);
  // 可以传函数
  child.value?.outPush();
});

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值