VUE3版本新特性

news2024/11/27 4:29:10

VUE3版本新特性

  1. VUE3和VUE2的区别
  2. 路由的使用
  3. vite安装项目
  4. 新特性使用

1.VUE3和VUE2的区别

2020年9月18日,Vue.js发布版3.0版本,代号:One Piece 于 2022 年 2 月 7 日星期一成为新的默认版本! Vue3性能更高,初次渲染快55%, 更新渲染快133% 。体积更小 Vue3.0 打包大小减少41%。 同时Vue3可以更好的支持TypeScript。 vue3中文文档:Vue.js : https://cn.vuejs.org/,vue2和vue3的主要区别在于以下几点:1、生命周期函数钩子不同

beforeCreate  -> setup()    开始创建组件之前,创建的是data和method
created       -> setup()
beforeMount   -> onBeforeMount    组件挂载到节点上之前执行的函数。
mounted       -> onMounted    组件挂载完成后执行的函数
beforeUpdate  -> onBeforeUpdate    组件更新之前执行的函数。
updated       -> onUpdated    组件更新完成之后执行的函数。
beforeDestroy -> onBeforeUnmount    组件挂载到节点上之前执行的函数。
destroyed     -> onUnmounted    组件卸载之前执行的函数。
activated     -> onActivated    组件卸载完成后执行的函数
deactivated   -> onDeactivated  在组件切换中老组件消失的时候执行

2、数据双向绑定原理不同

VUE2VUE3
利用ES5的一个APIObject.defineProperty()对数据进行劫持,结合发布者订阅者模式的方式来实现的。使用了ES6的Proxy API对数据代理。

vue3提供的proxy API代理的优势在于:

  • defineProperty只能监听某个属性,不能对全对象监听
  • 可以省去for…in,闭包等内容来提升效率(直接绑定整个对象即可)
  • 可以监听数组,不再单独的对数组做特异性处理。可以检测到数组内部数据的变化。

3、定义变量和方法不同

vue2vue3
在data中定义变量,在methods中创建方法使用一个新的setup方法

vue3提供的setup方法在组件初始化构造的时候触发,使用以下三个步骤建立反应性数据:

  • 从vue引入reactive

  • 使用reactive方法来声明数据为响应性数据

  • 使用setup方法返回响应性数据,从而template可以获取这些响应式数据。

    <script>
    export default {
    setup(){
     // 数据和方法都写这里,更简洁
      const user = "username";
      const met =  ()=>{
    
      }
    }
    }
    </script>
    

4、API类型不同

vue2vue3
选项型api(在代码中分割不同属性:data,computed,methods等)组合型api(使用方法进行分隔,显得更加简便整洁)

5、是否支持碎片

vue2vue3
是,即可以拥有多个根节点
<template>
  <div>
   <h1></h1>
  <div>
  <div>
   <h1></h1>
  <div>
</template>

6、父子之间传参不同

vue2vue3
父传子:子组件通过prop接收子传父:子组件中通过$emit向父组件触发一个监听方法,传递一个参数使用setup()中的第二个参数content对象中有emit,只需要在setup()接收第二个参数中使用分解对象法取出emit就可以在setup方法中随意使用了。

7、v-if 和 v-for的优先级

VUE2VUE3
v-for 优先于 v-if 生效v-if 优先于 v-for 生效

2.使用Vite创建项目

在VUE3中使用vite来创建项目而不再使用 vue-cli,初始化项目 ,vite 是新一代前端构建工具,官网地址:https://vitejs.cn,vite的优势如:

  • 轻量快速的热重载(HMR),能实现极速的服务启动。

  • TypeScriptJSXCSS 等支持开箱即用。

  • 真正的按需编译,不再等待整个应用编译完成。注意:Vite 需要 Node.js 版本 >= 12.0.0。【使用nvm安装 node 18.14.2】

在这里插入图片描述

注意:还需要去设置仓库地址: npm config set registry https://registry.npmmirror.com在VUE2中使用npm进行包的管理,在VUE3中pnpm进行包的管理,首先我们需要安装 pnpm

  1. 安装pnpm :

在磁盘上创建一个文件夹,如: vue3-demo,然后进入目录,使用cmd窗口执行命令如下:

npm i pnpm -g
  1. 安装vite : 执行下面命令,按照提示完成项目创建

    pnpm create vite@latest 或者 yarn create vite

1.输入项目名字,默认为vue3-demo2.选择创建的项目类型,选择vue即可3.选择创建的vue项目类型, TypeScript4.启动项目

命令 : pnpm create vite@latest  执行效果如下
![1710845893295](images\1710845893295.png)

- 也可以使用 : npm init vite@latest 
3. 安装依赖: `进入到创建好的项目中`执行命令 pnpm i
```shell
pnpm i

cnpm install
  1. 启动项目
  • 启动命令看 package.json -> scripts { … }

    pnpm dev
    

    访问控制台地址,启动效果如下imagepng然后使用开发工具,导入创建好的项目

3.项目结构认识

├── dist/                                                        //代码编译目录
└── src/
    ├── api/                       // 接口请求目录
    ├── assets/                    // 静态资源目录
    ├── common/                    // 通用类库目录
    ├── components/                // 公共组件目录
    ├── router/                    // 路由配置目录
    ├── store/                     // 状态管理目录
    ├── style/                     // 通用样式目录
    ├── utils/                     // 工具函数目录
    ├── views/                     // 页面组件目录
    ├── App.vue
    ├── main.ts                                        //主ts
├── tests/                         // 单元测试目录
├── index.html                                        //默认首页,入口页面
├── jsconfig.json                  // JavaScript 配置文件
├── vite.config.js                 // Vite 配置文件
└── package.json                                        //依赖管理
└── vite.config.ts

4.route的使用

4.1.安装route路由

官网:https://router.vuejs.org/zh/installation.html

pnpm install vue-router@4

imagepng

4.2.创建页面

在src目录下创建views/order/order.vue 以及 views/user/user.vue 页面文件,内容如下

<script setup lang="ts">

</script>

<template>
  <div>11111111111111</div>
</template>

<style scoped>
</style>
----
4.3.创建router

在src目录下创建router/index.ts文件,内容如下

import { createRouter, createWebHashHistory } from 'vue-router'

const router = createRouter({
    history: createWebHashHistory(),
    routes: [
      {path:"/",name:"home",component:()=>import("../views/User.vue")},
      {path:"/test",name:"test",component:()=>import("../views/Order.vue"),}
    ],
  })

 export default router 
  • createWebHashHistory: hash 模式下使用的是createWebHashHistoryapi 进行配置 VueRouter 的历史模式。使用 hash 模式下会在浏览器网页路由当中使用哈希字符(#)对 url 进行切割并且匹配哈希字符后的字符进行判断路由匹配与跳转处理。

    4.4.在main.js中使用路由
    ...省略...
    

//导入路由import { createApp } from 'vue’import router from ‘./router/index’

//创建appconst app = createApp(App);

//使用路由app.use(router)

//挂载appapp.mount(‘#app’)

#### 4.5.在App.vue文件中指定路由出口
```vue
<template>
  <div>
        <!--     路由出口 ,所有页面都会放到这个里面-->
    <router-view></router-view>
  </div>
</template>
4.6.重启测试

5.vue的核心语法

5.1 简单入门

Vue3向下兼容Vue2语法,且Vue3中的模板中可以没有根标签

<template>
  <div class="person">
    <h2>姓名:{{name}}</h2>
    <h2>年龄:{{age}}</h2>
    <button @click="changeName">修改名字</button>
    <button @click="changeAge">年龄+1</button>
    <button @click="showTel">点我查看联系方式</button>
  </div>
</template>

<script lang="ts">
  export default {
    name:'App',
    data() {
      return {
        name:'张三',
        age:18,
        tel:'13888888888'
      }
    },
    methods:{
      changeName(){
        this.name = 'zhang-san'
      },
      changeAge(){
        this.age += 1
      },
      showTel(){
        alert(this.tel)
      }
    },
  }
</script>
5.2 Setup函数

在学习以下知识之前我们先了解一下 options api 和 composition api的区别:vue2中使用的是optionsAPI,来定义一个组件内部的一些属性,如methods、data等等;其缺点往往会在大项目中体现出来,比如一个简单的计数器功能,可能需要在methods内部书写一部分逻辑,在computed内部也书写一部分逻辑,那么问题来了:如果该组件内部有n个这样的小功能,那么此时代码逻辑是十分分散的,并且后期迭代维护面临的问题也是可能修改一个需求需要在不同的属性内部反复查找相关的代码,而compositionAPI的出现就是为了解决这一问题的。

vue3新增的compositionAPI主要就是为了解决API太过于分散的问题,避免一个功能点下的api太过于分散不便于维护,将同一个功能下的api统一放到一个地方,这样一来项目的开发和维护就简便多了。compositionAPI也叫做组合式API,vue3中组合式API的入口就是setup函数; imagepng

https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/bc0be8211fc54b6c941c036791ba4efe~tplv-k3u1fbpfcp-watermark.image

setupVue3中一个新的配置项,值是一个函数,它是 Composition API “表演的舞台,组件中所用到的:数据、方法、计算属性、监视…等等,均配置在setup中。

特点如下:

  • setup函数返回的对象中的内容,可直接在模板中使用。
  • setup中访问thisundefined
  • setup函数会在beforeCreate之前调用,它是“领先”所有钩子执行的。
5.1.普通写法[不推荐]

​ 通过 export default { setup(){ } } 来定义setup函数 , 这种方式不推荐

<template>
  <div class="person">
    <h2>姓名:{{name}}</h2>
    <h2>年龄:{{age}}</h2>
    <button @click="changeName">修改名字</button>
    <button @click="changeAge">年龄+1</button>
    <button @click="showTel">点我查看联系方式</button>
  </div>
</template>

<script lang="ts">
  export default {
    name:'Person',
    setup(){
      // 数据,原来写在data中(注意:此时的name、age、tel数据都不是响应式数据)
      let name = '张三'
      let age = 18
      let tel = '13888888888'

      // 方法,原来写在methods中
      function changeName(){
        name = 'zhang-san' //注意:此时这么修改name页面是不变化的
        console.log(name)
      }
      function changeAge(){
        age += 1 //注意:此时这么修改age页面是不变化的
        console.log(age)
      }
      function showTel(){
        alert(tel)
      }

      // 返回一个对象,对象中的内容,模板中可以直接使用
      return {name,age,tel,changeName,changeAge,showTel}
    }
  }
</script>
5.2.语法糖[推荐]
注意:在setup语法中使用 this 会出现unidefined , 在 `setup` 中你应该避免使用 `this`,因为它不会找到组件实例。`setup` 的调用发生在 `data` property、`computed` property 或 `methods` 被解析之前,所以它们无法在 `setup` 中被获取,这也是为了避免setup()和其他选项式API混淆。

### 6.数据响应函数
什么是响应式:响应式指的是,把数据绑定当视图,当数据的值发生改变,视图也会跟着重新渲染。
#### 6.1.ref:基础数据响应式函数
VUE3提供了ref函数可以在修改完 数据后自动渲染视图,类似余双向绑定

- 在js中通过  import {ref} from "vue"; 来声明 ref函数
- 注意:ref属性在js中要使用.value 取值
```javascript
<template>
  <div class="person">
    <h2>姓名:{{name}}</h2>
    <h2>年龄:{{age}}</h2>
    <button @click="changeName">修改名字</button>
    <button @click="changeAge">年龄+1</button>
    <button @click="showTel">点我查看联系方式</button>
  </div>
</template>

<script setup lang="ts" name="Person">
  import {ref} from 'vue'
  // name和age是一个RefImpl的实例对象,简称ref对象,它们的value属性是响应式的。
  let name = ref('张三')
  let age = ref(18)
  // tel就是一个普通的字符串,不是响应式的
  let tel = '13888888888'

  function changeName(){
    // JS中操作ref对象时候需要.value
    name.value = '李四'
    console.log(name.value)

    // 注意:name不是响应式的,name.value是响应式的,所以如下代码并不会引起页面的更新。
    // name = ref('zhang-san')
  }
  function changeAge(){
    // JS中操作ref对象时候需要.value
    age.value += 1 
    console.log(age.value)
  }
  function showTel(){
    alert(tel)
  }
</script>

通过ref获取dom对象

<template>
    <input ref="inputRef" :value="refValue"/>
</template>

<script setup>
    import {ref} from "vue";
    //变量名 inputRef 和 dom元素上的ref="inputRef" 一样,就能获取到dom元素
    let inputRef = ref(null);
    console.log(inputRef);

</script>
6.2.reactive创建:对象类型的响应式数据

对于对象类型可以使用reactive进行响应式函数处理

<template>
  <div class="person">
    <h2>汽车信息:一台{{ car.brand }}汽车,价值{{ car.price }}万</h2>
    <h2>游戏列表:</h2>
    <ul>
      <li v-for="g in games" :key="g.id">{{ g.name }}</li>
    </ul>
    <h2>测试:{{obj.a.b.c.d}}</h2>
    <button @click="changeCarPrice">修改汽车价格</button>
    <button @click="changeFirstGame">修改第一游戏</button>
    <button @click="test">测试</button>
  </div>
</template>

<script lang="ts" setup name="Person">
import { reactive } from 'vue'

// 数据
let car = reactive({ brand: '奔驰', price: 100 })
let games = reactive([
  { id: 'ahsgdyfa01', name: '英雄联盟' },
  { id: 'ahsgdyfa02', name: '王者荣耀' },
  { id: 'ahsgdyfa03', name: '原神' }
])
let obj = reactive({
  a:{
    b:{
      c:{
        d:666
      }
    }
  }
})

function changeCarPrice() {
  car.price += 10
}
function changeFirstGame() {
  games[0].name = '流星蝴蝶剑'
}
function test(){
  obj.a.b.c.d = 999
}
</script>

注意:其实ref接收的数据可以是:基本类型对象类型。若ref接收的是对象类型,内部其实也是调用了reactive函数

例如:

<template>
  <div class="person">
    <h2>汽车信息:一台{{ car.brand }}汽车,价值{{ car.price }}万</h2>
    <h2>游戏列表:</h2>
    <ul>
      <li v-for="g in games" :key="g.id">{{ g.name }}</li>
    </ul>
    <h2>测试:{{obj.a.b.c.d}}</h2>
    <button @click="changeCarPrice">修改汽车价格</button>
    <button @click="changeFirstGame">修改第一游戏</button>
    <button @click="test">测试</button>
  </div>
</template>

<script lang="ts" setup name="Person">
import { ref } from 'vue'

// 数据
let car = ref({ brand: '奔驰', price: 100 })
let games = ref([
  { id: 'ahsgdyfa01', name: '英雄联盟' },
  { id: 'ahsgdyfa02', name: '王者荣耀' },
  { id: 'ahsgdyfa03', name: '原神' }
])
let obj = ref({
  a:{
    b:{
      c:{
        d:666
      }
    }
  }
})

console.log(car)

function changeCarPrice() {
  car.value.price += 10
}
function changeFirstGame() {
  games.value[0].name = '流星蝴蝶剑'
}
function test(){
  obj.value.a.b.c.d = 999
}
</script>

对比:

  1. ref用来定义:基本类型数据对象类型数据
  2. reactive用来定义:对象类型数据
  3. ref创建的变量必须使用.value
  4. reactive重新分配一个新对象,会失去响应式

7.toRef 和 toRefs【了解】

7.1.toRef解析响应式

​ 将一个响应式对象中的每一个属性,转换为ref对象,toRefstoRef功能一致,但toRefs可以批量转换。

<template>
  <div class="person">
    <h2>姓名:{{person.name}}</h2>
    <h2>年龄:{{person.age}}</h2>
    <h2>性别:{{person.gender}}</h2>
    <button @click="changeName">修改名字</button>
    <button @click="changeAge">修改年龄</button>
    <button @click="changeGender">修改性别</button>
  </div>
</template>

<script lang="ts" setup name="Person">
  import {ref,reactive,toRefs,toRef} from 'vue'

  // 数据
  let person = reactive({name:'张三', age:18, gender:'男'})

  // 通过toRefs将person对象中的n个属性批量取出,且依然保持响应式的能力
  let {name,gender} =  toRefs(person)

  // 通过toRef将person对象中的gender属性取出,且依然保持响应式的能力
  let age = toRef(person,'age')

  // 方法
  function changeName(){
    name.value += '~'
  }
  function changeAge(){
    age.value += 1
  }
  function changeGender(){
    gender.value = '女'
  }
</script>

8.computed计算函数

下面通过计算函数演示2个值相加,需要通过 import {computed} from “vue”; 引入函数

<template>
  <div class="person">
    姓:<input type="text" v-model="firstName"> <br>
    名:<input type="text" v-model="lastName"> <br>
    全名:<span>{{fullName}}</span> <br>
    <button @click="changeFullName">全名改为:li-si</button>
  </div>
</template>

<script setup lang="ts" name="App">
  import {ref,computed} from 'vue'

  let firstName = ref('zhang')
  let lastName = ref('san')

  // 计算属性——只读取,不修改
  /* let fullName = computed(()=>{
    return firstName.value + '-' + lastName.value
  }) */


  // 计算属性——既读取又修改
  let fullName = computed({
    // 读取
    get(){
      return firstName.value + '-' + lastName.value
    },
    // 修改
    set(val){
      console.log('有人修改了fullName',val)
      firstName.value = val.split('-')[0]
      lastName.value = val.split('-')[1]
    }
  })

  function changeFullName(){
    fullName.value = 'li-si'
  } 
</script>

9.watch监听器

watch的作用是用来监听某个值的变化从而出发watch回调。watch可以:

  • 监听单体数据

  • 监听对象

  • 监听对象的某个属性

  • 监听多个数据

    <template>
      <div class="watch"></div>
      <button @click="value++">修改value</button>
      <button @click="persion.age++">修改persion</button>
    </template>
    <script setup>
    

import {reactive, ref, watch} from “vue”;

const value = ref(1111);const persion = reactive({ username:“zs” , age:18})//监听单个值watch(value,()=>{ console.log(value);})//监听对象watch(persion,()=>{ console.log(persion);})

//监听多个,用[]包含多个watch([persion,value],()=>{ console.log(persion,value);});

//监听对象的属性 watch(persion.age,()=>{ console.log(persion);});

watch如果监听对象,可以深度监听(即:对象中又深度嵌套了对象,嵌套的对象值被修改也会被监听到)
### 10.watchEffect监听副作用[了解]
立即运行一个函数,同时响应式地追踪其依赖,并在依赖更改时重新执行该函数。watchEffect的作用是只要使用到的数据都会被监听到,无需指定具体监听谁,他包含4个功能

- 页面加载,watchEffect的回调就会立即执行
- 只要watchEffect 只要里面使用了任何数据,就会触发回到函数
- onCleanup函数可以清除副作用
- 返回一个stopHandler可以停止监听
```vue
<template>
    <div class="watch_effect"></div>
    <button @click="num++">num++</button>
    <button @click="stopHandler">StopWatch</button>
</template>

<script setup>

import {ref, watchEffect} from "vue";

const num = ref(1111);

//1.页面加载,初始化立即回执行回调
//2.只要watchEffect 只要里面使用了数据,就会触发回到函数
//3.onCleanup函数可以清除副作用
//4.返回一个stopHandler可以停止监听
/**
watchEffect(()=>{
    console.log(num.value);
})
 **/

const stopHandler = watchEffect(onCleanup=>{
    console.log(num.value);
    onCleanup(()=>{
        console.log("清除副作用");
    });
})

</script>

11.生命周期方法

因为 setup 是围绕 beforeCreatecreated 生命周期钩子运行的,所以不需要显式地定义它们。换句话说,在这些钩子中编写的任何代码都应该直接在 setup 函数中编写。下表包含如何在 setup () 内部调用生命周期钩子:

选项式 API(VUE2)Hook inside setup
beforeCreateNot needed* 不需要
createdNot needed* 不需要
beforeMountonBeforeMount
挂载之前
mountedonMounted
页面加载完成时执行
beforeUpdateonBeforeUpdate
updatedonUpdated
beforeUnmountonBeforeUnmount
unmountedonUnmounted
页面销毁时执行
errorCapturedonErrorCaptured
renderTrackedonRenderTracked
renderTriggeredonRenderTriggered
activatedonActivated
deactivatedonDeactivated

下面是代码案例

<script setup>
import {onBeforeMount, onBeforeUnmount, onMounted, onUnmounted} from "vue";

console.log("初始化")
onMounted(()=>{
    console.log("onMounted 挂载中...");
})

onBeforeMount(()=>{
    console.log("onBeforeMount 挂载前....");
})
onUnmounted(()=>{
    console.log("onUnmounted 当销毁..")
})
onBeforeUnmount(()=>{
    console.log("onBeforeUnmount 当销毁前..")
})
</script>

12.父子组件[重点]

12.1.父传参数给子

第一步:创建一个父组件页面,引入子组件,并传入参数 parent.vue

<template>
    <H1 class="parent_child">父传子</H1>
    <h2>使用子组件传参</h2>
    <child-vue text="传入静态文本"  :num="num" :title="title" :persion="persion"></child-vue>
</template>

<script setup>

//引入子组件取名用驼峰,页面用中划线 <child-vue></child-vue>
import ChildVue from "@/views/parent_child/child.vue";
import {reactive, ref} from "vue";

//构建一个响应式对象
const persion = reactive({
    username:"zs",
    age:18
})
//定义响应式变量
const title = ref("我是标题");
const num = ref(111);
</script>

第二步:创建一个子组件页面 : child.vue , 通过 defineProps接受父传入的参数

<template>
    <h2>text:{{text}}</h2>
    <h2>num:{{num}}</h2>
    <h2>title:{{title}}</h2>
    <h2>persion:{{persion}}</h2>
</template>

<script setup>
//通过defineProps来接受父传入过来的参数
const  prop = defineProps({
    text:String,
    num:Number,
    title:String,
    persion:Object
})
//在js中可以读取父传入过来的参数,但是不能修改
console.log("prop.title" , prop.title)


</script>

注意:在子组件中没法修改父转件传入的参数

12.2.子传参给父

子组件给父组件传值,需要通过defineEmits在子组件声明事件方法,然后调用该事件方法传值,父组件需要监听该事件方法取值。第一步:在子组件中准备一个按钮,点击按钮就给父组件传值。然后给按钮绑定一个方法。

<h1>给父组件传参</h1>
<button @click="sendData2Parent">给父组件传参</button>

------------------------------------------------------------------------------------------

//声明事件
const $emits = defineEmits(["data2parent","事件名","事件名"]);

const  sendData2Parent = ()=>{
    //调用声明的事件
    $emits('data2parent',"传给父组件的数据");
}
  • const $emits = defineEmits([“data2parent”,“事件2”,“事件3”]); 自定义了三个事件
  • $emits(‘data2parent’,“传给父组件的数据”); 调用自定义的事件

第二步:在父组件中绑定该事件,并调用一个函数来接受值

<child-vue @data2parent="getDataFromChild"  ...></child-vue>



const getDataFromChild = (data)=>{
    console.log("打印数据",data);
}
  • @data2parent=“getDataFromChild” : data2parent对应了子组件中声明的事件,拿到数据后交给getDataFromChild去处理。

    12.3.子暴露

    VUE3提供了 defineExpose 来暴露子组件中的数据和方法在父组件中可以拿到子组件中暴露的数据或者方法。第一步在子组件中暴露数据

    //子暴露
    defineExpose({
      data:"我是子暴露的数据",
      sayHi:()=>{
          return "我是子暴露的方法被调用返回的结果";
      }
    })
    

    第二步:在父组件接受子暴露的数据

    <child-vue
      ref="childVueRef" ...></child-vue>
    

//用一个响应式变量,接受子暴露的数据const childVueRef = ref(null);onMounted(()=>{ console.log(“子暴露的数据:”,childVueRef.value.data); console.log(“子暴露的方法:”,childVueRef.value.sayHi());})

- ref="childVueRef" : 接受子暴露,把数据绑定给childVueRef

注意:因为在父组件的 setup 函数中,声明周期很早,此时子组件还没加载,所以需要在onMounted去调用子暴露的数据和方法才可以拿到结果。

### 13.自定义Hooks函数
**hooks就是用来给我们抽取公共代码的**,hooks函数就是通过 use开头的js参数 。 自定义`hook`的优势:复用代码, 让`setup`中的逻辑更清楚易懂。
代码如下:

​    useSum.ts

```js
import {ref,onMounted} from 'vue'

export default function(){
  let sum = ref(0)

  const increment = ()=>{
    sum.value += 1
  }
  const decrement = ()=>{
    sum.value -= 1
  }
  onMounted(()=>{
    increment()
  })

  //向外部暴露数据
  return {sum,increment,decrement}
}        

useDog.ts中内容如下

import {reactive,onMounted} from 'vue'
import axios,{AxiosError} from 'axios'

export default function(){
  let dogList = reactive<string[]>([])

  // 方法
  async function getDog(){
    try {
      // 发请求
      let {data} = await axios.get('https://dog.ceo/api/breed/pembroke/images/random')
      // 维护数据
      dogList.push(data.message)
    } catch (error) {
      // 处理错误
      const err = <AxiosError>error
      console.log(err.message)
    }
  }

  // 挂载钩子
  onMounted(()=>{
    getDog()
  })

  //向外部暴露数据
  return {dogList,getDog}
}

组件中使用:

<template>
  <h2>当前求和为:{{sum}}</h2>
  <button @click="increment">点我+1</button>
  <button @click="decrement">点我-1</button>
  <hr>
  <img v-for="(u,index) in dogList" :key="index" :src="u"> 
  <span v-show="dogList.isLoading">加载中......</span><br>
  <button @click="getDog">再来一只狗</button>
</template>

<script lang="ts">
  import {defineComponent} from 'vue'

  export default defineComponent({
    name:'App',
  })
</script>

<script setup lang="ts">
  import useSum from './hooks/useSum'
  import useDog from './hooks/useDog'

  let {sum,increment,decrement} = useSum()
  let {dogList,getDog} = useDog()
</script>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1833415.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ROS中使用超声波传感器(附代码)

在ROS中使用超声波传感器通常涉及到订阅或发布sensor_msgs/Range类型的消息。下面是一个简单的示例&#xff0c;展示了如何使用C在ROS中编写一个超声波传感器的驱动程序。这个例子假设你有一个超声波传感器连接到了Arduino或者其他微控制器&#xff0c;并且该微控制器已经通过串…

FreeRtos-09事件组的使用

1. 事件组的理论讲解 事件组:就是通过一个整数的bit位来代表一个事件,几个事件的or和and的结果是输出 #define configUSE_16_BIT_TICKS 0 //configUSE_16_BIT_TICKS用1表示16位,用0表示32位 1.1 事件组适用于哪些场景 某个事件若干个事件中的某个事件若干个事件中的所有事…

经历的分享

我是三本计算机科学技术跨考上岸的学生&#xff0c;本科阶段技术能力并没有掌握多少&#xff0c;在选择导师时屡屡碰壁&#xff0c;我当时向许多计算机方向的导师&#xff0c;比如大数据方向,计算机视觉 迁移学习和图像处理方向的导师全都拒绝了我&#xff0c;最终学校给我分配…

Ubuntu 在线或离线安装docker

查看自己的ubuntu版本 在终端中执行以下命令&#xff1a; lsb_release -a 终端中的复制粘贴&#xff1a; ctrl shift c ctrl shifr v 在线安装docker&#xff08;不需要外网&#xff09;: 命令行安装&#xff1a;Ubuntu Docker -- 从入门到实践 看完…

Apollo9.0 PNC源码学习之Control模块(五)—— 基于LQR的横向控制

前面文章&#xff1a; Apollo9.0 PNC源码学习之Control模块&#xff08;一&#xff09; Apollo9.0 PNC源码学习之Control模块&#xff08;二&#xff09; Apollo9.0 PNC源码学习之Control模块&#xff08;三&#xff09; Apollo9.0 PNC源码学习之Control模块&#xff08;四&…

git Fork或者git clone克隆别人的项目到自己的仓库如何保持原仓库同步

一、问题描述 有时候我们会clone别人的项目到自己的仓库来进行二次开发,开发好之后提交到自己的仓库&#xff0c;如有原仓库有更新了,可以选择性的进行同步 二、解决方法 这里以ruoyi-vue-pro得前端项目来进行演示&#xff0c;创建一个目录&#xff0c;在目录下随便创建一个文…

示例:WPF中TreeView自定义TreeNode泛型绑定对象

一、目的&#xff1a;在开发中经常需要绑定TreeView&#xff0c;所以定义了一个泛型的TreeNode<T>用来方便绑定对象和复用 二、实现 public partial class TreeNodeBase<T> : SelectBindable<T>, ITreeNode{public TreeNodeBase(T t) : base(t){}private Obs…

Milvus跨集群数据迁移

将 Milvus 数据从 A 集群&#xff08;K8S集群&#xff09;迁到 B 集群&#xff08;K8S集群&#xff09;&#xff0c;解决方案很多&#xff0c;这里提供一个使用官方 milvus-backup 工具进行数据迁移的方案。 注意&#xff1a;此方案为非实时同步方案&#xff0c;但借助 MinIO 客…

嵌入式技术学习——c51——串口

一、串口介绍。 串口是一个 通讯接口。成本低&#xff0c;容易使用&#xff0c;通信线路简单&#xff0c;可实现两个设备的相互通信 单片机的串口可以实现单片机于单片机&#xff0c;单片机与电脑&#xff0c;单片机与其他模块相互通信。 51单片机内部自带UART&#xff0c;通…

AI训练Checkpoint对存储的影响

检查点&#xff08;Checkpoints&#xff09;是机器学习和深度学习训练过程中的一个重要机制&#xff0c;旨在定期保存训练状态&#xff0c;以便在训练过程中遇到失败或中断时能够从中断处恢复训练&#xff0c;而无需从头开始。 随着模型参数量的剧增&#xff0c;Checkpoint文件…

智慧档案库房建设费用大概多少

智慧档案库房建设费用因地区、规模和具体需求而异&#xff0c;以下是一些常见费用项&#xff1a; 1. 建筑物建设费用&#xff1a;包括设计、施工、装修、材料等费用。 2. 设备费用&#xff1a;包括服务器、网络设备、存储设备、十防等硬件设备的费用。 3. 软件费用&#xff1a;…

Aeron:两个代理之间的单向IPC(One-way IPC between two agents)

一、概述 本例展示了如何通过 IPC 在调度于不同线程的两个代理之间传输缓冲区。在继续学习本示例之前&#xff0c;最好先复习一下Simplest Full Example &#xff0c;因为该示例展示的是 IPC 通信&#xff0c;没有增加代理的复杂性。读者还应熟悉Media Driver 流程构建如下&…

Maya 2024 mac/win版:创意无界,设计新生

Maya 2024是一款由Autodesk推出的业界领先的三维计算机图形软件&#xff0c;广泛应用于电影、游戏、广告等创意产业。这款软件以其强大的功能和卓越的性能&#xff0c;为艺术家们提供了一个实现创意梦想的平台。 Maya 2024 mac/win版获取 在建模方面&#xff0c;Maya 2024提供…

Linux_理解程序地址空间和页表

目录 1、进程地址空间示意图 2、验证进程地址空间的结构 3、验证进程地址空间是虚拟地址 4、页表-虚拟地址与物理地址 5、什么是进程地址空间 6、进程地址空间和页表的存在意义 6.1 原因一&#xff08;效率性&#xff09; 6.2 原因二&#xff08;安全性&#xff09; …

Langchain中使用Ollama提供的Qwen大模型进行Function Call实现天气查询、网络搜索

Function Call&#xff0c;或者叫函数调用、工具调用&#xff0c;是大语言模型中比较重要的一项能力&#xff0c;对于扩展大语言模型的能力&#xff0c;或者构建AI Agent&#xff0c;至关重要。 Function Call的简单原理如下&#xff1a; 按照特定规范&#xff08;这个一般是L…

TensorRT的循环样例代码

官方文档地址 https://docs.nvidia.com/deeplearning/tensorrt/developer-guide/index.html#define-loops 非顺序结构&#xff0c;其内容确实有点乱&#xff0c;而且没有完整可运行的样例。 可以有多个IIteratorLayer, IRecurrenceLayer, and ILoopOutputLayer 层&#xff0c;…

wondershaper 一款限制 linux 服务器网卡级别的带宽工具

文章目录 一、关于奇迹整形器二、文档链接三、源码下载四、限流测试五、常见报错1. /usr/local/sbin/wondershaper: line 145: tc: command not found2. Failed to download metadata for repo ‘appstream‘: Cannot prepare internal mirrorlist: No URLs.. 一、关于奇迹整形…

抖音矩阵系统搭建,AI剪辑短视频,一键管理矩阵账号

目录 前言&#xff1a; 一、抖音矩阵系统有哪些功能&#xff1f; 1.AI智能文案 2.多平台账号授权 3.多种剪辑模式 4. 矩阵一键发布&#xff0c;智能发布 5.抖音爆店码功能 6.私信实时互动 7.去水印及外链 二、抖音矩阵系统可以解决哪些问题&#xff1f; 总结&#xff…

【MySQL基础随缘更系列】AB复制

文章目录 mysql AB复制实战一、mysql AB复制二、AB复制原理三、master服务器设置3.1、安装mysql并启动3.2、关闭防火墙,selinux3.3、设置时间服务器3.4、修改配置文件 设置server-idN3.5、创建slave连接master的账号&#xff0c;用于取SQL语句 四、slave设置4.3、修改配置文件 …

C#调用OpenCvSharp和SkiaSharp绘制图像直方图

最近在B站上学习OpenCv教程&#xff0c;学到图像直方图&#xff0c;后者描述的是不同色彩在整幅图像中所占的比例&#xff08;统计不同色彩在图像中的出现次数&#xff09;&#xff0c;可以对灰度图、彩色图等计算并绘制图像直方图。本文学习OpenCvSharp中与计算直方图相关的函…