尚硅谷Vue3入门到实战,最新版vue3+TypeScript前端开发教程

1.创建Vue3工程

复制代码
npm create vue@latest

或者

复制代码
npm init vue@latest

输入项目名和需要的工具后进入项目

如果项目报错 使用命令安装Node.js的项目依赖包

复制代码
npm i

启动vue项目,查看项目是否创建完成

复制代码
npm run dev

直接删掉src

然后创建src文件夹,在该文件夹中创建main.ts和App.vue文件

在src中有两个文件必不可少,分别是

main.ts

App.vue

App.vue基本内容:

复制代码
<style>

</style>
<template>
    
</template>

<script lang="ts">

</script>

那么main.ts的基本内容:

复制代码
import { createApp } from 'vue'
import App from './App.vue'

createApp(App).mount('#app')

2.写一个简单的效果

使用插件

创建components文件夹,然后再创建Person.vue文件

components/Person.vue:

复制代码
<style>
.person{
    background-color: skyblue;
    box-shadow: 0 0 10px;
    border-radius: 10px;
    padding: 20px;
}
button{
    margin: 0 10px;
}
</style>
<template>
    <div class="person">
        <h2>姓名:{{name}}</h2>
        <h2>年龄:{{age}}</h2>
        <button @click="changeName">修改姓名</button>
        <button @click="changeAge">修改年龄</button>
        <button @click="showTel">显示联系方式</button>
    </div>
</template>

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

App.vue:

复制代码
<style scoped>
    .app{
        background-color: skyblue;
        box-shadow: 0 0 10px;
        border-radius: 10px;
        padding: 20px;
    }
</style>
<template>
    <div class="app">
        <h1>App你好</h1>
        <PersonVue/>
    </div>
</template>

<script lang="ts">
import PersonVue from "./components/Person.vue";

export default{
    name:'App',
    components:{PersonVue}
}
</script>

这说明了Vue3可以写Vue2的代码

上面是选项式API,我们将其改为组合式API,如下:

在setup函数中的this是undefined

如果遇到组件名和文件名不一致的情况,如:

为了使用一个script标签标识setup的同时命名文件的组件名,则需要安装插件

复制代码
npm i vite-plugin-vue-setup-extend -D

然后再vite.config.ts中加入

复制代码
import VueSetupExtend from 'vite-plugin-vue-setup-extend'

然后在plugins中追加VueSetupExtend()

如下:

所修改后的组合式API:

复制代码
<style scoped>
.person{
    background-color: skyblue;
    box-shadow: 0 0 10px;
    border-radius: 10px;
    padding: 20px;
}
button{
    margin: 0 10px;
}
</style>
<template>
    <div class="person">
        <h2>姓名:{{name}}</h2>
        <h2>年龄:{{age}}</h2>
        <button @click="changeName">修改姓名</button>
        <button @click="changeAge">修改年龄</button>
        <button @click="showTel">显示联系方式</button>
    </div>
</template>

<script lang="ts" setup name="Person234">
    let name = '张三'
    let age = 18
    let tel = '13888888888'

    function changeName(){
        name = 'zhang-san'
    }

    function changeAge(){
        age += 1
    }

    function showTel(){
        alert(tel)
    }
</script>

这还不是完整的修改,因为变量name和age,无法通过调用函数的方式显示改变后变量的值,同时还没使用到ref,下面的修改会解决这些问题

3.ref创建,基本类型的响应式数据

复制代码
<style scoped>
.person{
    background-color: skyblue;
    box-shadow: 0 0 10px;
    border-radius: 10px;
    padding: 20px;
}
button{
    margin: 0 10px;
}
</style>
<template>
    <div class="person">
        <h2>姓名:{{name}}</h2>
        <h2>年龄:{{age}}</h2>
        <button @click="changeName">修改姓名</button>
        <button @click="changeAge">修改年龄</button>
        <button @click="showTel">显示联系方式</button>
    </div>
</template>

<script lang="ts" setup name="Person">
import { ref } from "vue"
    let name = ref('张三')
    let age = ref(18)
    let tel = '13888888888'

    function changeName(){
        name.value = 'zhang-san'
    }

    function changeAge(){
        age.value += 1
    }

    function showTel(){
        alert(tel)
    }
</script>

4.reative创建,对象类型的响应式数据

复制代码
<style scoped>
.person{
    background-color: skyblue;
    box-shadow: 0 0 10px;
    border-radius: 10px;
    padding: 20px;
}
button{
    margin: 0 10px;
}
</style>
<template>
    <div class="person">
       <h2>一辆{{car.brand}}车,价值{{car.price}}万</h2>
       <button @click="changePrice">修改汽车的价格</button>
    </div>
    <br>
    <h2>游戏列表:</h2>
    <ul>
        <li v-for="game in games" :key="game.id">{{game.name}}</li>
    </ul>
    <button @click="changeFirstGame">修改第一个游戏名称</button>
</template>

<script lang="ts" setup name="Person">
    import { reactive } from "vue"
    let car = reactive({brand:'奔驰',price:100})
    let games = reactive([
        {id:'game01',name:'王者'},
        {id:'game02',name:'原神'},
        {id:'game03',name:'三国'}
    ])

    function changePrice(){
        car.price += 10
    }

    function changeFirstGame(){
        games[0].name = "荣耀"
    }

</script>

5.将reactive修改为ref的方式

修改的结果如下:

复制代码
<style scoped>
.person{
    background-color: skyblue;
    box-shadow: 0 0 10px;
    border-radius: 10px;
    padding: 20px;
}
button{
    margin: 0 10px;
}
</style>
<template>
    <div class="person">
       <h2>一辆{{car.brand}}车,价值{{car.price}}万</h2>
       <button @click="changePrice">修改汽车的价格</button>
    </div>
    <br>
    <h2>游戏列表:</h2>
    <ul>
        <li v-for="game in games" :key="game.id">{{game.name}}</li>
    </ul>
    <button @click="changeFirstGame">修改第一个游戏名称</button>
</template>

<script lang="ts" setup name="Person">
    import {ref } from "vue"
    let car = ref({brand:'奔驰',price:100})
    let games = ref([
        {id:'game01',name:'王者'},
        {id:'game02',name:'原神'},
        {id:'game03',name:'三国'}
    ])

    function changePrice(){
        car.value.price += 10
    }

    function changeFirstGame(){
        games.value[0].name = "荣耀"
    }

</script>

6.volar工具

ref要定义的对象要加上.value改变值

可以使用volar工具,这样不用刻意去记哪个是ref,那个是reactive定义的对象

下载插件后,勾选扩展功能

7.处理数据返回

对于返回来reactive定义对象的数据,如果要更新原本的数据,可以使用Object.assign这么处理

8.toRefs和toRef

toRefs和toRef都是拿响应式数据解构出来,使其具有响应式能力,都是ref对象,所以需要.value

复制代码
<style scoped>
.person{
    background-color: skyblue;
    box-shadow: 0 0 10px;
    border-radius: 10px;
    padding: 20px;
}
button{
    margin: 0 10px;
}
</style>
<template>
    <div class="person">
       <h2>姓名:{{name}}</h2>
       <h2>年龄:{{age}},n1:{{ n1 }}</h2>
       <button @click="changeName">修改名字</button>
       <button @click="changeAge">修改年龄</button>
    </div>
   
</template>

<script lang="ts" setup name="Person">
    import {reactive, ref, toRef, toRefs } from "vue"
    
    let person = reactive({
        name:'张三',
        age:18
    })

    let {name,age} = toRefs(person)
    let n1 = toRef(person,'age')

    function changeName(){
        name.value += '~'
    }
    function changeAge(){
        age.value += 1
    }

</script>

9.computed计算属性

定义computed 想可读可写的方式如下所示

复制代码
<style scoped>
.person{
    background-color: skyblue;
    box-shadow: 0 0 10px;
    border-radius: 10px;
    padding: 20px;
}
button{
    margin: 0 10px;
}
</style>
<template>
    <div class="person">
      姓:<input type="text" v-model="firstName"/>
      <br>
      名:<input type="text" v-model="lastName"/>
      <br>
      姓名:<span>{{fullName}}</span>
      <button @click="changeFullName">修改名字</button>
    </div>
   
</template>

<script lang="ts" setup name="Person">
    import { computed, ref } from "vue"
    let firstName = ref('张')
    let lastName = ref('三')

    //这么定义的fullName是一个计算属性,只可读
/*     let fullName = computed(()=>{
        return firstName.value.slice(0,1).toUpperCase() + firstName.value.slice(1) + '-' + lastName.value
    }) */

    //这么定义的fullName是一个计算属性,可读可写
    let fullName = computed({
        get(){
            return firstName.value.slice(0,1).toUpperCase() + firstName.value.slice(1) + lastName.value
        },
        set(val){
            const [str1,str2] = val.split('-')
            firstName.value = str1
            lastName.value = str2
        }
    })

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

10.watch监视

10.1watch监视ref定义基本类型的数据

复制代码
<style scoped>
.person{
    background-color: skyblue;
    box-shadow: 0 0 10px;
    border-radius: 10px;
    padding: 20px;
}
button{
    margin: 0 10px;
}
</style>
<template>
    <div class="person">
        <h2>sum:{{sum}}</h2>
        <button @click="changeSum">sum++</button>
    </div>
   
</template>

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

   let sum = ref(0)

   function changeSum(){
        sum.value += 1
   }

   const stopWatch = watch(sum,(newValue,oldValue)=>{
        console.log('sum变化了',newValue,oldValue)
        //定义停止监听条件
        if(newValue >= 10){
            stopWatch()
        }
   })
</script>

10.2watch监视ref定义的对象类型数据

复制代码
<style scoped>
.person{
    background-color: skyblue;
    box-shadow: 0 0 10px;
    border-radius: 10px;
    padding: 20px;
}
button{
    margin: 0 10px;
}
</style>
<template>
    <div class="person">
        <h2>姓名:{{person.name}}</h2>
        <h2>年龄:{{person.age}}</h2>
        <button @click="changeName">修改姓名</button>
        <button @click="changeAge">修改年龄</button>
        <button @click="changePerson">修改人</button>
    </div>
   
</template>

<script lang="ts" setup name="Person">
    import {ref,watch} from 'vue'
    let person = ref({
        name:'张三',
        age:18
    })

    function changeName(){
        person.value.name = '李四'
    }

    function changeAge(){
        person.value.age += 1
    }

    function changePerson(){
        person.value = {name:'小刘',age:20}
    }

    watch(person,(newValue,oldValue)=>{
        console.log(newValue,oldValue)
    },{deep:true})
</script>

10.3watch监视reactive定义对象类型数据,且默认开启了深度监听

复制代码
<style scoped>
.person{
    background-color: skyblue;
    box-shadow: 0 0 10px;
    border-radius: 10px;
    padding: 20px;
}
button{
    margin: 0 10px;
}
</style>
<template>
    <div class="person">
        <h2>姓名:{{person.name}}</h2>
        <h2>年龄:{{person.age}}</h2>
        <button @click="changeName">修改姓名</button>
        <button @click="changeAge">修改年龄</button>
        <button @click="changePerson">修改人</button>
    </div>
   
</template>

<script lang="ts" setup name="Person">
    import {reactive,watch} from 'vue'
    let person = reactive({
        name:'张三',
        age:18
    })

    function changeName(){
        person.name = '李四'
    }

    function changeAge(){
        person.age += 1
    }

    function changePerson(){
        Object.assign(person,{name:'小刘',age:20})
    }

    watch(person,(newValue,oldValue)=>{
        console.log(newValue,oldValue)
    })
</script>

10.4watch监视ref或reactive定义对象类型数据中某个属性

如果监听响应式对象中的某个属性,若该属性是基本类型属性,要写成函数式

复制代码
<style scoped>
.person{
    background-color: skyblue;
    box-shadow: 0 0 10px;
    border-radius: 10px;
    padding: 20px;
}
button{
    margin: 0 10px;
}
</style>
<template>
    <div class="person">
        <h2>姓名:{{person.name}}</h2>
        <h2>年龄:{{person.age}}</h2>
        <button @click="changeName">修改姓名</button>
        <button @click="changeAge">修改年龄</button>
        <button @click="changePerson">修改人</button>
    </div>
   
</template>

<script lang="ts" setup name="Person">
    import {reactive,watch} from 'vue'
    let person = reactive({
        name:'张三',
        age:18
    })

    function changeName(){
        person.name += '~'
    }

    function changeAge(){
        person.age += 1
    }

    function changePerson(){
        Object.assign(person,{name:'小刘',age:20})
    }

    watch(()=>person.name,(newValue,oldValue)=>{
        console.log(newValue,oldValue)
    })
</script>

10.5watch监听多个属性

复制代码
<style scoped>
.person{
    background-color: skyblue;
    box-shadow: 0 0 10px;
    border-radius: 10px;
    padding: 20px;
}
button{
    margin: 0 10px;
}
</style>
<template>
    <div class="person">
        <h2>姓名:{{person.name}}</h2>
        <h2>年龄:{{person.age}}</h2>
        <button @click="changeName">修改姓名</button>
        <button @click="changeAge">修改年龄</button>
        <button @click="changePerson">修改人</button>
    </div>
   
</template>

<script lang="ts" setup name="Person">
    import {reactive,watch} from 'vue'
    let person = reactive({
        name:'张三',
        age:18
    })

    function changeName(){
        person.name += '~'
    }

    function changeAge(){
        person.age += 1
    }

    function changePerson(){
        Object.assign(person,{name:'小刘',age:20})
    }

    watch([()=>person.name,()=>person.age],(newValue,oldValue)=>{
        console.log(newValue,oldValue)
    })
</script>

10.6watchEffect

watchEffect不用明确指出监听的数据(函数中用到哪些属性,那就监听哪些属性)

复制代码
<style scoped>
.person{
    background-color: skyblue;
    box-shadow: 0 0 10px;
    border-radius: 10px;
    padding: 20px;
}
button{
    margin: 0 10px;
}
</style>
<template>
    <div class="person">
        <h2>水温:{{temp}}</h2>
        <h2>水位:{{height}}</h2>
        <button @click="changeTemp">提高水温+10</button>
        <button @click="changeHeight">提高水位+10</button>
    </div>
   
</template>

<script lang="ts" setup name="Person">
    import {reactive,ref,watch, watchEffect} from 'vue'
   
    let temp = ref(10)
    let height = ref(0)

    function changeTemp(){
        temp.value += 10
    }
    
    function changeHeight(){
        height.value += 10
    }

    //监听 -- watch
    // watch([temp,height],(value)=>{
    //     let [newTemp,newHeight] = value
    //     if(newTemp>=30 || newHeight>=50){
    //         console.log('服务器发起请求')
    //     }
    // })

    //监听 -- watchEffect
    watchEffect(()=>{
        if(temp.value >= 30 || height.value >=50){
            console.log('服务器发起请求')
        }
    })

</script>

11.标签的ref属性

创建一个title2,用于存储ref标记的内容

Person.vue:

复制代码
<style scoped>
.person{
    background-color: skyblue;
    box-shadow: 0 0 10px;
    border-radius: 10px;
    padding: 20px;
}
button{
    margin: 0 10px;
}
</style>
<template>
    <div class="person">
        <h2 ref="title2">北京</h2>
        <button @click="showLog">点击我输出h2元素</button>
    </div>
   
</template>

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

let title2 = ref()

function showLog(){
    console.log(title2.value)
}


</script>

App.vue:

复制代码
<style scoped>
    .app{
        background-color: skyblue;
        box-shadow: 0 0 10px;
        border-radius: 10px;
        padding: 20px;
    }
</style>
<template>
    <h2 ref="title2">你好</h2>
    <button @click="showLog">点击我输出h2</button>
    <PersonVue/>
</template>

<script lang="ts" setup name="App">
import PersonVue from "./components/Person.vue";
import { ref }from 'vue'
let title2 = ref()

function showLog(){
    console.log(title2.value)
}

</script>

如果父组件想获取子组件中的元素,则可以使用defineExpose

Person.vue:

复制代码
<style scoped>
.person{
    background-color: skyblue;
    box-shadow: 0 0 10px;
    border-radius: 10px;
    padding: 20px;
}
button{
    margin: 0 10px;
}
</style>
<template>
    <div class="person">
        <h2 ref="title2">北京</h2>
        <button @click="showLog">点击我输出h2元素</button>
    </div>
   
</template>

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

let title2 = ref()
let a = ref(0)
let b = ref(1)

function showLog(){
    console.log(title2.value)
}

defineExpose({a,b})

</script>

App.vue:

复制代码
<style scoped>
    .app{
        background-color: skyblue;
        box-shadow: 0 0 10px;
        border-radius: 10px;
        padding: 20px;
    }
</style>
<template>
    <h2 ref="title2">你好</h2>
    <button @click="showLog">点击我输出</button>
    <PersonVue ref="ren" />
</template>

<script lang="ts" setup name="App">
import PersonVue from "./components/Person.vue";
import { ref }from 'vue'
let title2 = ref()
let ren = ref()

function showLog(){
    console.log(ren.value)
    
}



</script>

12.TS中的接口、泛型、自定义类型

如果引入的是数据类型,而不是值的话,则需要使用type来标识

创建types/index.ts

复制代码
//定义一个接口,用于限制person对象的具体属性
export interface PersonInter {
    id:string,
    name:string,
    age:number
}

//一个自定义类型
// export type Persons = Array<PersonInter>
export type Persons = PersonInter[]

Person.vue:

复制代码
<style scoped>
.person{
    background-color: skyblue;
    box-shadow: 0 0 10px;
    border-radius: 10px;
    padding: 20px;
}
button{
    margin: 0 10px;
}
</style>
<template>
  <div class="person">

  </div>
   
</template>

<script lang="ts" setup name="Person">
import  {type PersonInter,type Persons } from '@/types'


// let person:PersonInter = {id:'dasads01',name:'zhangsan',age:20}

let person:Persons = [
    {id:'dasads01',name:'zhangsan',age:20},
    {id:'dasads02',name:'lisi',age:22},
    {id:'dasads03',name:'wangwu',age:30}
]
</script>

13.props的使用

如果子组件想获取父组件中的元素,则可以使用defineProps

Person.vue:

复制代码
<style scoped>
.person{
    background-color: skyblue;
    box-shadow: 0 0 10px;
    border-radius: 10px;
    padding: 20px;
}
button{
    margin: 0 10px;
}
</style>
<template>
  <div class="person">
    <ul>
        <li v-for="personObj in list" :key="personObj.id">
            {{ personObj.name }} -- {{ personObj.age }}
        </li>
    </ul>
  </div>
   
</template>

<script lang="ts" setup name="Person">
import  { Persons } from '@/types'

//只接收list
// defineProps(['list'])

//接收list + 限制类型
// defineProps<{list:Persons}>()


//接收list + 限制类型 + 限制必要性 + 指定默认值
//在list后打上?,表示可以不传入数据
withDefaults(defineProps<{list?:Persons}>(),{
    list:()=>[{id:'asdasas01',name:'康之福',age:23}]
})

</script>

App.vue:

复制代码
<style scoped>
    .app{
        background-color: skyblue;
        box-shadow: 0 0 10px;
        border-radius: 10px;
        padding: 20px;
    }
</style>
<template>

    <PersonVue a="哈哈" :list="personList"/>
</template>

<script lang="ts" setup name="App">
import PersonVue from "./components/Person.vue";
import {reactive} from 'vue';
import { type Persons } from "./types";

let personList = reactive<Persons>([
    {id:'dasads01',name:'zhangsan',age:20},
    {id:'dasads02',name:'lisi',age:22},
    {id:'dasads03',name:'wangwu',age:30}
])


</script>

14.生命周期

14.1 Vue2的生命周期

分为四个阶段:创建、挂载、更新、销毁

创建前:beforeCreate()

创建完毕:created()

挂载前:beforeMount()

挂载完毕:mounted()

更新前:beforeUpdate()

更新完毕:updated()

销毁前:beforeDestroy()

销毁完毕:destroyed()

14.2 Vue3的生命周期

创建阶段:setup

挂载阶段:onBeforeMount、onMounted

更新阶段:onBeforeUpdate、onUpdated

卸载阶段:onBeforeUnmount、onUnmounted

常用的钩子:onMounted(挂载完毕)、onUpdated(更新完毕)、onBeforeUnmount(卸载之前)

15.自定义Hooks

安装axios

复制代码
npm i axios

以两个函数为示例,这是没有使用hooks的方式

Person.vue:

复制代码
<style scoped>
.person{
    background-color: skyblue;
    box-shadow: 0 0 10px;
    border-radius: 10px;
    padding: 20px;
}
button{
    margin: 0 10px;
}

img{
    height: 100px;
    margin: 10px;
}
</style>
<template>
  <div class="person">
    <h2>当前求和:{{ sum }}</h2>
    <button @click="add">点我+1</button>
    <br>
    <button @click="getDog">换一只狗</button>
    <img v-for="(dog,index) in dogList" :src="dog" :key="index">
  </div>
   
</template>

<script lang="ts" setup name="Person">

import { reactive, ref, } from 'vue';
import axios from 'axios';


let sum = ref(0)

let dogList = reactive([
    'https://images.dog.ceo/breeds/pembroke/n02113023_4373.jpg'
])

async function getDog(){
    let result = await axios.get('https://dog.ceo/api/breed/pembroke/images/random')
    dogList.push(result.data.message)
}

function add(){
    sum.value += 1
}

</script>

使用hooks后的方式,先创建hooks文件夹,然后创建useDog.ts和useSum.ts文件,分别存放,Sum和Dog相关的代码块,使用方式:

useSum.ts:

复制代码
import {computed, onMounted, ref } from 'vue';


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

    let bigsum = computed(()=>{
        return sum.value * 10
    })


    function add(){
        sum.value += 1
    }

    onMounted(()=>{
        sum.value += 1
    })

    return {sum,add,bigsum}
}

useDog.ts:

复制代码
import { reactive} from 'vue';
import axios from 'axios';


export default function(){
    let dogList = reactive([
        'https://images.dog.ceo/breeds/pembroke/n02113023_4373.jpg'
    ])
    
    async function getDog(){
        let result = await axios.get('https://dog.ceo/api/breed/pembroke/images/random')
        dogList.push(result.data.message)
    }

    return {dogList,getDog}
}

Person.vue:

复制代码
<style scoped>
.person{
    background-color: skyblue;
    box-shadow: 0 0 10px;
    border-radius: 10px;
    padding: 20px;
}
button{
    margin: 0 10px;
}

img{
    height: 100px;
    margin: 10px;
}
</style>
<template>
  <div class="person">
    <h2>当前求和:{{ sum }},放大十倍后:{{bigsum}}</h2>
    <button @click="add">点我+1</button>
    <br>
    <button @click="getDog">换一只狗</button>
    <img v-for="(dog,index) in dogList" :src="dog" :key="index">
  </div>
   
</template>

<script lang="ts" setup name="Person">
import useSum from '@/hooks/useSum'
import useDog from '@/hooks/useDog'
const {sum,add,bigsum} = useSum()
const {dogList,getDog} = useDog()

</script>

16.路由

16.1路由的基本切换效果

安装路由器

复制代码
npm i vue-router

在components中创建Home.vue、News.vue、About.vue文件

创建文件夹router,然后在router中创建index.ts文件

path应该以斜杠 / 开头,以确保它是一个完整的路径

router/index.ts:

复制代码
//引入createRouter
import { createRouter, createWebHistory } from "vue-router";

//引入组件
import Home from "@/components/Home.vue";
import About from "@/components/About.vue";
import News from "@/components/News.vue";

//创建路由器
const router = createRouter({
    history:createWebHistory(), //路由器编译规则
    routes:[{
        path:'/home',
        component:Home
    },{
        path:'/about',
        component:About
    },{
        path:'/news',
        component:News
    }]
})

export default router

main.ts:

复制代码
import { createApp } from "vue";

import App from './App.vue'
import router from "./router";

//创建一个应用
const app = createApp(App)
//使用路由器
app.use(router)
//挂载整个应用到app容器中
app.mount('#app')

App.vue:

复制代码
<style scoped>
    .app{
        background-color: skyblue;
        box-shadow: 0 0 10px;
        border-radius: 10px;
        padding: 20px;
    }

    
</style>
<template>
    <div class="navigate">
        <h1>navigate</h1>
       <RouterLink to="/home">首页</RouterLink>
       <RouterLink to="/news">新闻</RouterLink>
       <RouterLink to="/about">关于</RouterLink>
    </div>
    <br>
    内容:
    <div>
        <RouterView></RouterView>
    </div>

</template>

<script lang="ts" setup name="App">

import {RouterView,RouterLink} from 'vue-router'

</script>

16.2路由两个注意点

注意:

(1)一般组件存放在components文件夹中,路由组件存放在pages或views文件夹中

(2)通过点击导航,视觉效果上"消失"了的路由组件,默认是被销毁的,需要的时候再去挂载

16.3 to的两种写法

16.4路由命名

16.5嵌套路由

注意:children下的path的开头是不需要加上斜杠 / 的

在pages中创建文件Detail.vue

pages/Detail.vue:

复制代码
<template>
    <div class="detail">
      <h2>Detail</h2>
    </div>
</template>
  
<script lang="ts" setup name="Detail">

</script>
<style scoped>

</style>

pages/News.vue:

复制代码
<template>
    <div class="news">
        <h2>News</h2>
        <RouterView></RouterView>  
    </div>    
</template>

<script lang="ts" setup name="News">

</script>
<style scoped> 

</style>

router/index.ts:

复制代码
//引入createRouter
import { createRouter, createWebHistory } from "vue-router";

//引入组件
import Home from "@/pages/Home.vue";
import About from "@/pages/About.vue";
import News from "@/pages/News.vue";
import Detail from "@/pages/Detail.vue";

//创建路由器
const router = createRouter({
    history:createWebHistory(), //路由器编译规则
    routes:[{
        name:'zhuye',
        path:'/home',
        component:Home
    },{
        name:'guanyu',
        path:'/about',
        component:About
    },{
        name:'xinwen',
        path:'/news',
        component:News,
        children:[{
            path:'detail',
            component:Detail
        }]
    }]
})

export default router

main.ts:

复制代码
import { createApp } from "vue";

import App from './App.vue'
import router from "./router";

//创建一个应用
const app = createApp(App)
//使用路由器
app.use(router)
//挂载整个应用到app容器中
app.mount('#app')

16.6路由query参数(传参)

App.vue:

复制代码
<template>  
    <div class="app">  
        <h1>navigate</h1>  
        <ul>
            <li v-for="news in newsList" :key="news.id">
                <!-- 第一种方法 -->
                <!-- <RouterLink :to="`/news/detail?id=${news.id}&title=${news.title}&content=${news.content}`" >{{news.title}}</RouterLink>   -->
                
                <!-- 第二种写法 -->
                <RouterLink :to="{
                    path:'/news/detail',
                    query:{
                        id:news.id,
                        title:news.title,
                        content:news.content
                    }
                }">{{news.title}}</RouterLink>
                
            </li>
        </ul>
        <RouterLink to="/home">首页</RouterLink>  
       
        <RouterLink to="/about">关于</RouterLink>  
        <br>  
        内容:  
        <div>  
            <RouterView></RouterView>  
        </div>  
    </div>  
</template>  
  
<script lang="ts" setup name="App">  
import { reactive } from 'vue';
import { RouterView, RouterLink } from 'vue-router';  

const newsList = reactive([  
  { id: 'asdad01', title: '标题1', content: '内容1' },  
  { id: 'asdad02', title: '标题2', content: '内容2' },  
  { id: 'asdad03', title: '标题3', content: '内容3' }  
]);

</script>  
  
<style scoped>  
.app {  
    background-color: skyblue;  
    box-shadow: 0 0 10px;  
    border-radius: 10px;  
    padding: 20px;  
}  
</style>

pages/Detail.vue:

复制代码
<template>
    <div class="detail">
      <h2>Detail</h2>
      <ul>
        <li>编号:{{route.query.id}}</li>
        <li>标题:{{route.query.title}}</li>
        <li>内容:{{route.query.content}}</li>
      </ul>
    </div>
</template>
  
<script lang="ts" setup name="Detail">
import { useRoute } from 'vue-router';
let route = useRoute()
</script>
<style scoped>

</style>

可以将pages/Detail.vue这么改:

复制代码
<template>
    <div class="detail">
      <h2>Detail</h2>
      <ul>
        <li>编号:{{query.id}}</li>
        <li>标题:{{query.title}}</li>
        <li>内容:{{query.content}}</li>
      </ul>
    </div>
</template>
  
<script lang="ts" setup name="Detail">
import { toRefs } from 'vue';
import { useRoute } from 'vue-router';
let route = useRoute()
let {query} = toRefs(route)
</script>
<style scoped>

</style>

16.7路由params参数(传参)

注意:

(1)传递params参数时,使用to的对象写法,必须使用name配置项,不能用path

(2)传递params参数时,需要提前在规则中占位

App.vue:

复制代码
<template>  
    <div class="app">  
        <h1>navigate</h1>  
        <ul>
            <li v-for="news in newsList" :key="news.id">
                <!-- 第一种方法 -->
                <!-- <RouterLink :to="`/news/detail/${news.id}/${news.title}/${news.content}`" >{{news.title}}</RouterLink>   -->
                
                <!-- 第二种写法 -->
                <RouterLink :to="{
                    name:'xiang',
                    params:{
                        id:news.id,
                        title:news.title,
                        content:news.content
                    }
                }">{{news.title}}</RouterLink>

            </li>
        </ul>
        <RouterLink to="/home">首页</RouterLink>  
       
        <RouterLink to="/about">关于</RouterLink>  
        <br>  
        内容:  
        <div>  
            <RouterView></RouterView>  
        </div>  
    </div>  
</template>  
  
<script lang="ts" setup name="App">  
import { reactive } from 'vue';
import { RouterView, RouterLink } from 'vue-router';  

const newsList = reactive([  
  { id: 'asdad01', title: '标题1', content: '内容1' },  
  { id: 'asdad02', title: '标题2', content: '内容2' },  
  { id: 'asdad03', title: '标题3', content: '内容3' }  
]);

</script>  
  
<style scoped>  
.app {  
    background-color: skyblue;  
    box-shadow: 0 0 10px;  
    border-radius: 10px;  
    padding: 20px;  
}  
</style>

router/index.ts:

注意:params传参需要对路径名前加上:,表示所传递的参数,不然会当作子路径

复制代码
//引入createRouter
import { createRouter, createWebHistory } from "vue-router";

//引入组件
import Home from "@/pages/Home.vue";
import About from "@/pages/About.vue";
import News from "@/pages/News.vue";
import Detail from "@/pages/Detail.vue";

//创建路由器
const router = createRouter({
    history:createWebHistory(), //路由器编译规则
    routes:[{
        name:'zhuye',
        path:'/home',
        component:Home
    },{
        name:'guanyu',
        path:'/about',
        component:About
    },{
        name:'xinwen',
        path:'/news',
        component:News,
        children:[{
            name:'xiang',
            path:'detail/:id/:title/:content',
            component:Detail
        }]
    }]
})

export default router

pages/Detail.vue:

复制代码
<template>
    <div class="detail">
      <h2>Detail</h2>
      <ul>
        <li>编号:{{route.params.id}}</li>
        <li>标题:{{route.params.title}}</li>
        <li>内容:{{route.params.content}}</li>
      </ul>
    </div>
</template>
  
<script lang="ts" setup name="Detail">
import { toRefs } from 'vue';
import { useRoute } from 'vue-router';
let route = useRoute()

</script>
<style scoped>

</style>

16.8路由props配置

router/index.ts:

一般使用第一种方法和第二种方法,第二种方法使用params方法传递参数所以return route.params,如果是使用query方法传递参数,则return route.query

复制代码
//引入createRouter
import { createRouter, createWebHistory } from "vue-router";

//引入组件
import Home from "@/pages/Home.vue";
import About from "@/pages/About.vue";
import News from "@/pages/News.vue";
import Detail from "@/pages/Detail.vue";

//创建路由器
const router = createRouter({
    history:createWebHistory(), //路由器编译规则
    routes:[{
        name:'zhuye',
        path:'/home',
        component:Home
    },{
        name:'guanyu',
        path:'/about',
        component:About
    },{
        name:'xinwen',
        path:'/news',
        component:News,
        children:[{
            name:'xiang',
            path:'detail/:id/:title/:content',
            component:Detail,
            // 第一种写法:将路由收到的所有params参数作为props传给路由组件
            // props:true

            //第二种写法:函数写法,可以自己决定将什么作为props给路由组件
            props(route){
                return route.params
            }

            //第三种写法:对象写法,可以自己决定将什么作为props给路由组件
            /* props:{
                id:10,
                title:'今天去哪里?',
                content:'当然是北京'
            } */
        }]
    }]
})

export default router

pages/Detail.vue:

复制代码
<template>
    <div class="detail">
      <h2>Detail</h2>
      <ul>
        <li>编号:{{id}}</li>
        <li>标题:{{title}}</li>
        <li>内容:{{content}}</li>
      </ul>
    </div>
</template>
  
<script lang="ts" setup name="Detail">
defineProps(['id','title','content'])

</script>
<style scoped>

</style>

16.9路由replace属性

给RouterLink加上replace后就无法返回上一页的内容

16.9路由导航,路由跳转

有点类似<RouterLink/>

不带参数跳转:

pages/Home.vue:

复制代码
<template>
    <div class="home">
        <h2>Home</h2>
    </div>  
</template>

<script lang="ts" setup name="Home">
import { onMounted } from "vue";
import {useRouter} from 'vue-router'

const router = useRouter()

onMounted(()=>{
    setTimeout(()=>{
        //跳转路由
        router.push('/news')
    },3000)
})

</script>

<style scoped>

</style>

带参数跳转:

App.vue:

复制代码
<template>  
    <div class="app">  
        <h1>navigate</h1>  
        <ul>
            <li v-for="news in newsList" :key="news.id">
                <button @click="showNewsDetail(news)">查看新闻</button>
                <!-- 第一种方法 -->
                <!-- <RouterLink :to="`/news/detail/${news.id}/${news.title}/${news.content}`" >{{news.title}}</RouterLink>   -->
                
                <!-- 第二种写法 -->
                <RouterLink :to="{
                    name:'xiang',
                    params:{
                        id:news.id,
                        title:news.title,
                        content:news.content
                    }
                }">{{news.title}}</RouterLink>

               
            </li>
        </ul>
        <RouterLink to="/home">首页</RouterLink>  
       
        <RouterLink to="/about">关于</RouterLink>  
        <br>  
        内容:  
        <div>  
            <RouterView></RouterView>  
        </div>  
    </div>  
</template>  
  
<script lang="ts" setup name="App">  
import { reactive } from 'vue';
import { RouterView, RouterLink, useRouter } from 'vue-router';  

const newsList = reactive([  
  { id: 'asdad01', title: '标题1', content: '内容1' },  
  { id: 'asdad02', title: '标题2', content: '内容2' },  
  { id: 'asdad03', title: '标题3', content: '内容3' }  
]);

const router = useRouter()

//用于限制类型
interface NewsInter{
    id:string,
    title:string,
    content:string
}

function showNewsDetail(news:NewsInter){
    router.push({
        name:'xiang',
        params:{
            id:news.id,
            title:news.title,
            content:news.content
        }}
    )
}


</script>  
  
<style scoped>  
.app {  
    background-color: skyblue;  
    box-shadow: 0 0 10px;  
    border-radius: 10px;  
    padding: 20px;  
}  
</style>

如果将router.push改为router.replace,就表示跳转到指定的路由后就无法返回了,将上面的函数的代码改为replace如下所示:

复制代码
function showNewsDetail(news:NewsInter){
    router.replace({
        name:'xiang',
        params:{
            id:news.id,
            title:news.title,
            content:news.content
        }}
    )
}

16.10路由重定向

重定向(Redirect)是指通过各种方法将各种网络请求重新定向到其它位置的过程

17.Pinia

考虑多个组件共享数据

安装axios

复制代码
npm i axios

安装nanoid(效果类似uuid)

复制代码
npm i nanoid

17.1Pinia配置

安装pinia

复制代码
npm i pinia

配置

mian.ts:

复制代码
import { createApp } from "vue";

import App from './App.vue'
import { createPinia } from "pinia";

const app = createApp(App)
const pinia = createPinia()

app.use(pinia)
app.mount('#app')

下面是一个效果,

17.2未使用Pinia前的方式

components/Count.vue:

复制代码
<template>
    <div class="count">
      <h1>当前求和:{{sum}}</h1>
      <select v-model.number="step">
        <option value="1">1</option>
        <option value="2">2</option>
        <option value="3">3</option>
      </select>
      <button @click="add">加</button>
      <button @click="minus">减</button>
    </div>
</template>

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


let sum = ref(0)
let step = ref(1)

function add(){
    sum.value += step.value
}

function minus(){
    sum.value -= step.value
}

</script>

<style scoped>
.count{
    background-color: skyblue;
    padding: 10px;
    border-radius:10px;
    box-shadow:0 0 10px;
}

select,button{
    margin: 0 5px;
    height: 25px;
}

</style>

components/LoveTalk.vue:

复制代码
<template>
    <div class="talk">
        <button @click="getLoveTalk">获取一句话</button>
        <ul>
            <li v-for="talk in talkList" :key="talk.id">{{talk.title}}</li>
        </ul>
    </div>
</template>

<script lang="ts" setup name="LoveTalk">
import axios from 'axios';
import { reactive } from 'vue';
import {nanoid} from 'nanoid'

let talkList = reactive([
    {id:'sadaohd01',title:'早上好!'},
    {id:'sadaohd02',title:'中午好!'},
    {id:'sadaohd03',title:'晚上好!'}
    ])

async function getLoveTalk(){
    let {data:{content:title}} = await axios.get('https://api.uomg.com/api/rand.qinghua?format=json')
    let obj = {id:nanoid(),title}
    talkList.unshift(obj)
}

</script>

<style scoped>
.talk{
    background-color: skyblue;
    padding: 10px;
    border-radius:10px;
    box-shadow:0 0 10px;
}
</style>

App.vue:

复制代码
<template>
  <div>
    <h1>App组件</h1>
    <Count/>
    <br>
    <LoveTalk/>
  </div>
</template>

<script lang="ts" setup name="App">
import Count from './components/Count.vue';
import LoveTalk from './components/LoveTalk.vue';
</script>

<style scoped> 

</style>

17.3使用Pinia后的方式

创建文件夹store,然后在该文件夹中创建count.ts

store/count.ts:

复制代码
import {defineStore} from 'pinia'

export const useCountStore = defineStore('count',{
    actions:{
        increment(value: number){
            console.log('increment被调用了',value)
            if(this.sum<10){
                this.sum += value
            }
        }    
    },
    //真正存储数据的地方
    state(){
        return{
            sum:6,
            school:'guigu',
            address:'beijing'
        }
    }
})

components/Count.vue:

复制代码
<template>
    <div class="count">
      <h1>当前求和:{{countStore.sum}}</h1>
      <h1>学校:{{countStore.school}};地址:{{countStore.address}}</h1>
      <select v-model.number="step">
        <option value="1">1</option>
        <option value="2">2</option>
        <option value="3">3</option>
      </select>
      <button @click="add">加</button>
      <button @click="minus">减</button>
    </div>
</template>

<script lang="ts" setup name="Count">
import { ref } from 'vue';
import { useCountStore } from '@/store/count';

const countStore = useCountStore()

//获取state数据的两种方式:
// console.log(countStore.sum)
// console.log(countStore.$state.sum)


let step = ref(1)

function add(){
  //第一种方式修改
 /*  countStore.sum += 1
  countStore.school = '硅谷'
  countStore.address = '北京' */

  //第二种方式批量修改
/*   countStore.$patch({
    sum:888,
    school:'硅谷',
    address:'北京'
  }) */

  //第三种方式,调用store里的函数
  countStore.increment(step.value)

}

function minus(){

}

</script>

<style scoped>
.count{
    background-color: skyblue;
    padding: 10px;
    border-radius:10px;
    box-shadow:0 0 10px;
}

select,button{
    margin: 0 5px;
    height: 25px;
}

</style>

但是上面还没实现方法和调用storeToRefs(),实现后的完整版如下:

components/Count.vue:

复制代码
<template>
    <div class="count">
      <h1>当前求和:{{sum}}</h1>
      <h1>学校:{{school}};地址:{{address}}</h1>
      <select v-model.number="step">
        <option value="1">1</option>
        <option value="2">2</option>
        <option value="3">3</option>
      </select>
      <button @click="add">加</button>
      <button @click="minus">减</button>
    </div>
</template>

<script lang="ts" setup name="Count">
import { ref } from 'vue';
import { useCountStore } from '@/store/count';
import { storeToRefs } from 'pinia';

const countStore = useCountStore()
//storeToRefs只会关注store中数据,不会对方法进行ref包裹
const {sum,school,address} = storeToRefs(countStore)


//获取state数据的两种方式:
// console.log(countStore.sum)
// console.log(countStore.$state.sum)


let step = ref(1)

function add(){
  //第一种方式修改
 /*  countStore.sum += 1
  countStore.school = '硅谷'
  countStore.address = '北京' */

  //第二种方式批量修改
/*   countStore.$patch({
    sum:888,
    school:'硅谷',
    address:'北京'
  }) */

  //第三种方式,调用store里的函数
  countStore.increment(step.value)

}

function minus(){
  countStore.sum -= step.value
}

</script>

<style scoped>
.count{
    background-color: skyblue;
    padding: 10px;
    border-radius:10px;
    box-shadow:0 0 10px;
}

select,button{
    margin: 0 5px;
    height: 25px;
}

</style>

store/count.ts:

复制代码
import {defineStore} from 'pinia'

export const useCountStore = defineStore('count',{
    actions:{
        increment(value: number){
            console.log('increment被调用了',value)
            if(this.sum<10){
                this.sum += value
            }
        }    
    },
    //真正存储数据的地方
    state(){
        return{
            sum:6,
            school:'guigu',
            address:'beijing'
        }
    }
})

components/LoveTalk:

复制代码
<template>
    <div class="talk">
        <button @click="getLoveTalk">获取一句话</button>
        <ul>
            <li v-for="talk in talkStore.talkList" :key="talk.id">{{talk.title}}</li>
        </ul>
    </div>
</template>

<script lang="ts" setup name="LoveTalk">

import { useTalkStore } from '@/store/loveTalk';
import { storeToRefs } from 'pinia';
const talkStore = useTalkStore()
const {talkList} = storeToRefs(talkStore)

async function getLoveTalk(){
    talkStore.getATalk()
}

</script>

<style scoped>
.talk{
    background-color: skyblue;
    padding: 10px;
    border-radius:10px;
    box-shadow:0 0 10px;
}
</style>

store/loveTalk.ts:

复制代码
import {defineStore} from 'pinia'
import axios from 'axios';
import { reactive } from 'vue';
import {nanoid} from 'nanoid'

export const useTalkStore = defineStore('talk',{
    actions:{
        async getATalk(){
            let {data:{content:title}} = await axios.get('https://api.uomg.com/api/rand.qinghua?format=json')
            let obj = {id:nanoid(),title}
            this.talkList.unshift(obj)
        }
    },
    //真正存储数据的地方
    state(){
        return{
            talkList:[
                {id:'sadaohd01',title:'早上好!'},
                {id:'sadaohd02',title:'中午好!'},
                {id:'sadaohd03',title:'晚上好!'}
            ]
        }
    }
})

17.4 getters

getters是 Vuex store 中的计算属性。它们类似于 Vue 组件中的计算属性,但是用于从 store 中的状态派生值

store/count.ts:

复制代码
import {defineStore} from 'pinia'

export const useCountStore = defineStore('count',{
    actions:{
        increment(value: number){
            console.log('increment被调用了',value)
            if(this.sum<10){
                this.sum += value
            }
        }    
    },
    //真正存储数据的地方
    state(){
        return{
            sum:6,
            school:'guigu',
            address:'beijing'
        }
    },
    getters:{
        bigSum:state => state.sum * 10,
        upperSchool():string{
            return this.school.toUpperCase()
        }
    }
})

components/Count.vue:

复制代码
<template>
    <div class="count">
      <h1>当前求和:{{sum}},放大:{{bigSum}}</h1>
      <h1>学校:{{school}};地址:{{address}},大写:{{upperSchool}}</h1>
      <select v-model.number="step">
        <option value="1">1</option>
        <option value="2">2</option>
        <option value="3">3</option>
      </select>
      <button @click="add">加</button>
      <button @click="minus">减</button>
    </div>
</template>

<script lang="ts" setup name="Count">
import { ref } from 'vue';
import { useCountStore } from '@/store/count';
import { storeToRefs } from 'pinia';

const countStore = useCountStore()
//storeToRefs只会关注store中数据,不会对方法进行ref包裹
const {sum,school,address,bigSum,upperSchool} = storeToRefs(countStore)


//获取state数据的两种方式:
// console.log(countStore.sum)
// console.log(countStore.$state.sum)


let step = ref(1)

function add(){
  //第一种方式修改
 /*  countStore.sum += 1
  countStore.school = '硅谷'
  countStore.address = '北京' */

  //第二种方式批量修改
/*   countStore.$patch({
    sum:888,
    school:'硅谷',
    address:'北京'
  }) */

  //第三种方式,调用store里的函数
  countStore.increment(step.value)

}

function minus(){
  countStore.sum -= step.value
}

</script>

<style scoped>
.count{
    background-color: skyblue;
    padding: 10px;
    border-radius:10px;
    box-shadow:0 0 10px;
}

select,button{
    margin: 0 5px;
    height: 25px;
}

</style>

17.5 $subscribe的使用

订阅,监视vuex文件里的修改

components/LoveTalk.vue:

复制代码
<template>
    <div class="talk">
        <button @click="getLoveTalk">获取一句话</button>
        <ul>
            <li v-for="talk in talkStore.talkList" :key="talk.id">{{talk.title}}</li>
        </ul>
    </div>
</template>

<script lang="ts" setup name="LoveTalk">

import { useTalkStore } from '@/store/loveTalk';
import { storeToRefs } from 'pinia';
const talkStore = useTalkStore()
const {talkList} = storeToRefs(talkStore)

//$subscribe订阅
talkStore.$subscribe((mutate,state)=>{
    console.log('talkStore里面保存的数据发生了变化',mutate,state)
    localStorage.setItem('talkList',JSON.stringify(state.talkList))
})



async function getLoveTalk(){
    talkStore.getATalk()
}

</script>

<style scoped>
.talk{
    background-color: skyblue;
    padding: 10px;
    border-radius:10px;
    box-shadow:0 0 10px;
}
</style>

store/loveTalk.ts:

复制代码
import {defineStore} from 'pinia'
import axios from 'axios';
import { reactive } from 'vue';
import {nanoid} from 'nanoid'

export const useTalkStore = defineStore('talk',{
    actions:{
        async getATalk(){
            let {data:{content:title}} = await axios.get('https://api.uomg.com/api/rand.qinghua?format=json')
            let obj = {id:nanoid(),title}
            this.talkList.unshift(obj)
        }
    },
    //真正存储数据的地方
    state(){
        return{

            talkList:JSON.parse(localStorage.getItem('talkList') as string) || []
        }
    }
})

17.6store里的组合式写法

store/loveTalk.ts:

复制代码
import {defineStore} from 'pinia'
import axios from 'axios';
import { reactive } from 'vue';
import {nanoid} from 'nanoid'

/* export const useTalkStore = defineStore('talk',{
    actions:{
        async getATalk(){
            let {data:{content:title}} = await axios.get('https://api.uomg.com/api/rand.qinghua?format=json')
            let obj = {id:nanoid(),title}
            this.talkList.unshift(obj)
        }
    },
    //真正存储数据的地方
    state(){
        return{
            talkList:JSON.parse(localStorage.getItem('talkList') as string) || []
        }
    }
}) */


//组合式
export const useTalkStore = defineStore('talk',()=>{

    //talkList就是state
    const talkList = reactive(
        JSON.parse(localStorage.getItem('talkList') as string) || []
    )

    //getATalk函数相当于action
    async function getATalk(){
        let {data:{content:title}} = await axios.get('https://api.uomg.com/api/rand.qinghua?format=json')
        let obj = {id:nanoid(),title}
        talkList.unshift(obj)
    }

    return {talkList,getATalk}
})

18.组件通信

18.1props

可以进行父传子和子传父;

父传子,属性值是非函数

子传父,属性值是函数

18.2自定义事件

18.3mitt

安装mitt

复制代码
npm i mitt

然后创建utils文件夹,里存放emitter.ts文件

18.4 v-model

18.5 $attrs

实现 祖传孙 和 孙传祖

18.6 refs和parent

$refs:父访问子的属性、方法、计算属性

$parent:子访问父的属性、方法、计算属性

18.7 provide 和 inject

在之前祖传孙需要使用$attrs,且打扰到了子组件

那么使用provide直接就可以传后代,通过inject获取

相关推荐
崔庆才丨静觅21 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60611 天前
完成前端时间处理的另一块版图
前端·github·web components
掘了1 天前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅1 天前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅1 天前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅1 天前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment1 天前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅1 天前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊1 天前
jwt介绍
前端
爱敲代码的小鱼1 天前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax