Vue3学习隙

一、数据响应

修改数据

<template>
  <h2>车:{{ car.brand }}</h2>
  <h2>价格:{{ car.price }}</h2>
  <h2>当前求和为:{{ sum }}</h2>
  <button @click="ChangeSum">点我</button>
  <button @click="ChangeBrand">修改品牌</button>
  <button @click="ChangeCar">修改整车</button>

</template>
<script setup name="Person">
import { ref, reactive } from 'vue'
let sum = ref(0)
let car = reactive({ brand: '奔驰', price: 100 })

function ChangeSum() {
  sum.value += 1
}
function ChangeBrand() {
  car.brand = '宝马'
}
function ChangeCar() {
  // 方法一、重新给对象的属性赋值
  Object.assign(car, { brand: '法拉利', price: 200 })
  // 方法二、 将reactive 换成ref定义
  // 方法三、 将reactive 换成ref定义
}
</script>

<style></style>

数据转换

<template>
  <div>
    <h2>姓名:{{ name }}</h2>
    <h2>年龄:{{ age }}</h2>
    <br>
    <button @click="ChangeName">修改名字</button>
    <button @click="ChangeAge">修改年龄</button>
  </div>
</template>
<script setup name="Person">
import { toRefs, toRef, reactive } from 'vue'
let person = reactive({
  name: '张三',
  age: 18
})

let { name, age } = toRefs(person)
let nl = toRef(person, 'age')
console.log('nl', nl.value)
function ChangeName() {
  name.value += "!"
}
function ChangeAge() {
  age.value += 1
}
</script>

<style></style>

计算属性

<template>
  <div>
    <h2>姓:<input type="text" v-model="firstName"></h2>
    <h2>名:<input type="text" v-model="lastName"></h2>
    <h2>全名:{{ fullNmae }}</h2>
    <button @click="changeFullName">
      将全名改成李四
    </button>

  </div>
</template>
<script setup name="Person">
import { ref, computed } from 'vue'
let firstName = ref('张')
let lastName = ref('三')
// 只读的开始
// let fullNmae = computed(
//   () => {
//     console.log(1)
//     return firstName.value + '-' + lastName.value
//   }
// )
// 只读的结束

// 改计算属性的值开始
let fullNmae = computed(
  {
    get() {
      return firstName.value + '-' + lastName.value

    },
    set(val) {
      const [str1, str2] = val.split('-')
      firstName.value = str1
      lastName.value = str2

    }

  }
)

function changeFullName() {
  fullNmae.value = '李-四'
}
</script>

<style scoped></style>

二、数据监视

ref基本类型

<template>
  <div>
    <h2>当前求和是:{{ sum }}</h2>
    <button @click="sumCount">
      点我加1
    </button>
  </div>
</template>
<script setup name="Person">
import { ref, computed, watch } from 'vue'
let sum = ref(0)
function sumCount() {
  sum.value += 1
}
//监视ref的基本类型
const stopWatch = watch(sum, (newVal, oldVal) => {
  console.log(newVal, oldVal)
  if (newVal >= 10) {
    stopWatch()
  }

}
)
</script>

<style scoped></style>

ref对象类型数据

<template>
  <div>
    <h2>姓名:{{ person.name }}</h2>
    <h2>年龄:{{ person.age }}</h2>
    <button @click="changeName"> 修改名字 </button>
    <button @click="changeAge"> 修改年龄 </button>
    <button @click="changePerson"> 修改整个人 </button>
  </div>
</template>
<script 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, (newVal, oldVal) => {
//   console.log(newVal, oldVal)
// })

// 情况二、监视的对象的地全部 immediate立即监视,一上来就先执行一次
watch(person, (newVal, oldVal) => {
  console.log(newVal, oldVal)
}, { deep: true, immediate: true })

</script>

<style scoped></style>

reactive的对象

<template>
  <div>
    <h2>姓名:{{ person.name }}</h2>
    <h2>年龄:{{ person.age }}</h2>
    <button @click="changeName"> 修改名字 </button>
    <button @click="changeAge"> 修改年龄 </button>
    <button @click="changePerson"> 修改整个人 </button>
  </div>
</template>
<script 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

  })
}
// 当使用reactive定义时,默认开启深度监视,并且不可以关闭
watch(person, (newVal, oldVal) => {
  console.log(newVal, oldVal)
})

</script>

<style scoped></style>

监视ref或reactiver的某个属性

<template>
  <div>
    <h2>姓名:{{ person.name }}</h2>
    <h2>年龄:{{ person.age }}</h2>
    <h2>年汽车{{ person.car.c1 }}、{{ person.car.c2 }}</h2>

    <button @click="changeName"> 修改名字 </button>
    <button @click="changeAge"> 修改年龄 </button>
    <button @click="changeCar"> 修改整车 </button>
    <button @click="changeC1"> 修改车1 </button>
    <button @click="changeC2"> 修改车2 </button>
  </div>
</template>
<script setup name="Person">
import { reactive, watch } from 'vue'
let person = reactive(
  {
    name: '张三',
    age: 18,
    car: {
      c1: "奔驰",
      c2: "宝马"
    }
  }
)
function changeName() {
  person.name += "~"
}
function changeAge() {
  person.age += 1
}
function changeCar() {
  person.car = {
    c1: "奥迪",
    c2: "奥拓"

  }
}
function changeC1() {
  person.car.c1 = 'c1 car'

}
function changeC2() {

  person.car.c2 = 'c2 car'
}


// 要求修改名字的时候监视 需要使用getter函数
// watch(
//   () => { return person.name }, //getter函数
//   (newVal, oldVal) => {
//     console.log(newVal, oldVal)
//   })

// 监视某个属性car 需要写成函数式,同时加deep
watch(() => person.car,
  (newVal, oldVal) => {
    console.log(newVal, oldVal)
  },{deep:true})

</script>

<style scoped></style>

WatchEffect

<template>
  <div>
    <h2>当前求和为:{{ sum }}</h2>
    <button @click="changeSum">加一</button>
  </div>
</template>
<script setup name="Person">
import { ref, watchEffect } from 'vue'
let sum = ref(0)

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

watchEffect(() =>{
 if (sum.value>=10){
  console.log(1234)
 }
})

</script>

<style scoped></style>

REF使用

HTML使用

// father App.vue
<script setup>
import Person from './components/Person.vue'
import { ref } from 'vue'
//创建一个tittle2
let title2 = ref()
function showLog() {
  console.log(title2.value)
}

</script>

<template>
  <h2 ref="title2">当前求和111</h2>
  <Person />
  <button @click="showLog">点我输出H2元素</button>
</template>

<style scoped>
</style>

//child Person.vue'
<template>
  <div>
    <h2 ref="title2">当前求和</h2>
    <button @click="showLog">点我输出H2元素</button>
  </div>
</template>
<script setup name="Person">
import { ref } from 'vue'
//创建一个tittle2
let title2 = ref()
function showLog() {
  console.log(title2.value)
}
</script>

<style scoped></style>

组件使用

<template>
  <Person ref="ren"/>
  <button @click="showLog">点我输出子元素</button>
</template>



<script setup name="App">
import Person from './components/Person.vue'
import {ref} from 'vue'
let ren =ref()
function showLog() {
  console.log(ren.value)
}
</script>

<style scoped></style>


<template>
</template>
<script setup name="Person">
import { ref,defineExpose } from 'vue'

let a=ref(0)
let b=ref(1)
defineExpose({a,b})
</script>

<style scoped></style>

父传子

defineProps

普通类型

<template>
  <Person a="ren" :b="1 + 1" />
  father
</template>
<script setup name="App" lang="ts">
import Person from './components/Person.vue'
</script>

<style scoped></style>



<template>
{{ x }}
</template>
<script setup name="Person" lang="ts">
import { defineProps } from 'vue'
let x = defineProps(['a', 'b'])
</script>
<style scoped></style>

限制类型

// 父亲
<template>
  <Person :list=personlist />
  father
</template>



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

let personlist = reactive<PersonList>([
  { id: '001', name: '张三1', age: 18 },
  { id: '002', name: '张三2', age: 19 },
  { id: '003', name: '张三3', age: 20 },
])
</script>

<style scoped></style>


// 孩子

<template>
    {{ list }}
</template>
<script setup name="Person" lang="ts">
import { defineProps } from 'vue'

//方法一,只接收
// let x = defineProps(['a', 'b'])

import { type PersonList } from '@/types/'
// 方法二 接收并限制类型
defineProps<{ list: PersonList }>()

// 方法三 接收限制可选或必要性
defineProps<{ list?: PersonList }>()

// 方法四 如果没有,设置默认值
// import { withDefaults } from 'vue'
let def_recive = defineProps<{ list?: PersonList }>()
let def_list = [
    { id: '002', name: '张三2', age: 19 },
    { id: '002', name: '张三2', age: 19 },
]
withDefaults(def_recive, { list: () => def_list })

</script>

<style scoped></style>


// TS
export interface PersonInter {
    id: string
    name: string
    age: number
    x?:number //x是可选的
}
export type PersonList = PersonInter[]

生命周期

<template>
  <h1>father</h1>
  <button @click="uninstall">卸载</button>

  <hr>
  <Person v-if="isShow" />

</template>



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

let isShow = ref(true)
function uninstall() {
  isShow.value = false

}
</script>

<style scoped></style>


<template>
    <h1>child</h1>
    求和:{{ sum }}
    <br>
    <button @click="count">加一</button>
</template>



<script setup name="App" lang="ts">
import { ref, onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted } from 'vue'
let sum = ref(0)
function count() {
    sum.value += 1
}

//创建
console.log('创建')

//挂载前
onBeforeMount(() => {
    console.log('挂载前')
})
//挂载完毕
onMounted(() => {
    console.log('挂载完毕')
})


//更新前
onBeforeUpdate(() => {
    console.log('更新前')
})

//更新完毕
onUpdated(() => {
    console.log('更新完毕')
})


//卸载前
onBeforeUnmount(() => {
    console.log('卸载前')
})
//卸载完毕
onUnmounted(() => {
    console.log('卸载完毕')
})

</script>

<style scoped></style>

HOOKS

//father

<template>
  <h1>father</h1>
  <hr>
  <Person  />
</template>
<script setup name="App" lang="ts">
import Person from './components/Person.vue'
</script>
<style scoped></style>




// child
<template>
    <h1>child</h1>
    求和:{{ sum }}
    <br>
    <button @click="count">加一</button>
    <hr>
    <img v-for="(dog, index) in dosList" :src="dog" :key="index" class="dog-image">
    <br>
    <button @click="getDog">加个狗</button>
</template>

<script setup name="App" lang="ts">
import useSum from '@/hooks/useSum';
import useDog from '@/hooks/useDog';
const { sum, count } = useSum()
const { dosList, getDog } = useDog()
</script>

<style scoped>
    .dog-image {
        height: 300px;
        /* 注意:这里应该是 px 而不是只写 100 */
        width: auto;
        /* 可以添加以保持图片比例 */
        margin-bottom: 10px;
        /* 可选,为了美观添加一些底部外边距 */
    }
</style>


//hooks1


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


export default function () {
    let dosList = reactive<string[]>([])
    async function getDog() {
        let url = 'https://dog.ceo/api/breed/pembroke/images/random'
        try {
            let { data } = await axios.get<{ message: string }>(url)
            if (data && data.message && data.message) {
                dosList.push(data.message)
            }
        } catch (error) {
            console.error('Error fetching dog image:', error)
        }
    }
    // 获取初始值
    onMounted(() => {
        getDog()
    })
    //向外部提供任何数据
    return { dosList, getDog }
}


//hooks2


import { ref, reactive } from 'vue'
export default function () {
    let sum = ref(0)

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

    return { sum, count }
}

路由

基本用法

路由配置

//创建路由器器

import { createRouter, createWebHistory } from 'vue-router'
import Home from '@/pages/Home.vue'
import News from '@/pages/News.vue'
import About from '@/pages/About.vue'
const router = createRouter({
    history: createWebHistory(),
    routes: [
        {
            name: 'zhuye',
            path: '/home',
            component: Home
        },
        {
            name: 'xinwen',
            path: '/news',
            component: News
        },
        {
            name: 'guanyu',
            path: '/about',
            component: About
        },
    ]
})


export default router

绑定路由

import { createApp } from 'vue'
// 从一个单文件组件中导入根组件
import App from './App.vue'
import router from './router'

const app = createApp(App)
app.use(router)
app.mount('#app')

模板使用

<template>
  <div class="app">
    <Header></Header>
    <div class="navigate">
      <!-- 方法一 -->
      <RouterLink to="/home" active-class="active">首页</RouterLink>
      <!-- 方法二 根据路径 -->
      <RouterLink :to="{ path: '/news' }" active-class="active">新闻</RouterLink>
      <!-- 方法三 根据名称 -->
      <RouterLink :to="{ name: 'guanyu' }" active-class="active">关于</RouterLink>
    </div>

    <div class="main-content">
      <RouterView></RouterView>
    </div>
  </div>
  <hr>
  <Person />
</template>
<script setup name="App" lang="ts">
import { RouterView, RouterLink } from 'vue-router';
import Header from './components/Header.vue'
</script>
<style scoped>


  .navigate {
    display: flex;
    justify-content: space-around;
    margin: 0 100px;
  }

  .navigate a {
    display: block;
    text-align: center;
    width: 90px;
    height: 40px;
    line-height: 40px;
    border-radius: 10px;
    background-color: gray;
    text-decoration: none;
  }

  .navigate a.active {
    background-color: #64967E;
    color: #ffc268;
    font-weight: 900;
    text-shadow: 001px black;
    font-family: 微软雅黑;
  }

  .navigate a.active {
    background-color: #64967E;
    color: #ffc268;
    font-weight: 900;
    text-shadow: 001px black;
    font-family: 微软雅黑;
  }

  .main-content {
    margin: 0 auto;
    margin-top: 30px;
    border-radius: 10px;
    width: 90%;
    height: 400px;
    border: 1px solid;
  }

</style>

嵌套路由-query

路由配置

//创建路由器器

import { createRouter, createWebHistory, createWebHashHistory } from 'vue-router'
import Home from '@/pages/Home.vue'
import News from '@/pages/News.vue'
import About from '@/pages/About.vue'
import Detail from '@/pages/Detail.vue'
const router = createRouter({
    history: createWebHashHistory(),
    routes: [
        {
            name: 'zhuye',
            path: '/home',
            component: Home
        },
        {
            name: 'xinwen',
            path: '/news',
            component: News,
            children: [
                {
                    name: 'xiang',
                    path: 'detail',
                    component: Detail
                }
            ]
        },
        {
            name: 'guanyu',
            path: '/about',
            component: About
        },
    ]
})


export default router

模板配置

<template>
    <ul>
        <li v-for="news in newList" :key="news.id">

            <!-- 第一种写法 -->
            <!-- <RouterLink :to="`/news/detail?id=${news.id}&title=${news.title}&content=${news.content}`">
                {{ news.title }}
            </RouterLink> -->

            <!-- 第二种写法 -->
            <RouterLink :to="{
                name: 'xiang',
                query: {
                    id: news.id,
                    title: news.title,
                    content: news.content
                }
            }">
                {{ news.title }}
            </RouterLink>


        </li>

    </ul>
    <hr>
    <div>
        <RouterView></RouterView>
    </div>
</template>

<script setup name="about" lang="ts">
import { reactive } from 'vue';
const newList = reactive([
    { id: '001', title: "爱因斯坦一样,每当你提出了一个棘手的问题,", content: "杀死谷歌,成为AI时代的搜索皇帝!" },
    { id: '002', title: "推理计算,随着算力的增加,得到的答案质量也会", content: "诚邀!腾讯云套件新品发布会" },
    { id: '003', title: "字已经不再陌生。英伟达黄仁勋称它为“自己每天都", content: "​李彦宏:AI时代应避免掉入超级应用" },
    { id: '004', title: " Perplexity 的 CEO 埃拉文德·斯里尼瓦", content: "开发者投Rust重写系统后痛批" },
    { id: '005', title: "title005 学家,亲历了 Transformer 前生今世);", content: "图灵传人Steven Pemberton直言:未来AI或将毁灭90%人类 | Open AGI Forum" },
    { id: '006', title: "、贝索斯、杨立昆、扎克伯格,聊到了科学家、作家、艺术家,甚至梅西和罗纳尔多两位运动员", content: "“剑指 C/C++”,美国CISA等机构再" },
])
</script>
<style scoped></style>
<template>
    <ul>
        <li> {{ query.id }}</li>
        <li> {{ query.title }}</li>
        <li> {{ query.content }}</li>

    </ul>
</template>

<script setup name="about" lang="ts">
import { toRefs } from 'vue';
import { useRoute } from 'vue-router';

let route = useRoute()
let { query } = toRefs(route)
</script>
<style scoped></style>

嵌套路由-params

//创建路由器器

import { createRouter, createWebHistory, createWebHashHistory } from 'vue-router'
import Home from '@/pages/Home.vue'
import News from '@/pages/News.vue'
import About from '@/pages/About.vue'
import Detail from '@/pages/Detail.vue'
const router = createRouter({
    history: createWebHashHistory(),
    routes: [
        {
            name: 'zhuye',
            path: '/home',
            component: Home
        },
        {
            name: 'xinwen',
            path: '/news',
            component: News,
            children: [
                {
                    name: 'xiang',
                    path: 'detail/:id/:title/:content',
                    component: Detail
                }
            ]
        },
        {
            name: 'guanyu',
            path: '/about',
            component: About
        },
    ]
})


export default router
<template>
    <ul>
        <li v-for="news in newList" :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>
    <hr>
    <div>
        <RouterView></RouterView>
    </div>
</template>

<script setup name="about" lang="ts">
import { reactive } from 'vue';
const newList = reactive([
    { id: '001', title: "爱因斯坦一样,每当你提出了一个棘手的问题,", content: "杀死谷歌,成为AI时代的搜索皇帝!" },
    { id: '002', title: "推理计算,随着算力的增加,得到的答案质量也会", content: "诚邀!腾讯云套件新品发布会" },
    { id: '003', title: "字已经不再陌生。英伟达黄仁勋称它为“自己每天都", content: "​李彦宏:AI时代应避免掉入超级应用" },
    { id: '004', title: " Perplexity 的 CEO 埃拉文德·斯里尼瓦", content: "开发者投Rust重写系统后痛批" },
    { id: '005', title: "title005 学家,亲历了 Transformer 前生今世);", content: "图灵传人Steven Pemberton直言:未来AI或将毁灭90%人类 | Open AGI Forum" },
    { id: '006', title: "、贝索斯、杨立昆、扎克伯格,聊到了科学家、作家、艺术家,甚至梅西和罗纳尔多两位运动员", content: "“剑指 C/C++”,美国CISA等机构再" },
])
</script>
<style scoped></style>
<template>
    <ul>
        <li> {{ params.id }}</li>
        <li> {{ params.title }}</li>
        <li> {{ params.content }}</li>

    </ul>
</template>

<script setup name="about" lang="ts">
import { toRefs } from 'vue';
import { useRoute } from 'vue-router';

let route = useRoute()
let { params } = toRefs(route)
console.log(params.value)
</script>
<style scoped></style>

props配置

//创建路由器器

import { createRouter, createWebHistory, createWebHashHistory } from 'vue-router'
import Home from '@/pages/Home.vue'
import News from '@/pages/News.vue'
import About from '@/pages/About.vue'
import Detail from '@/pages/Detail.vue'
const router = createRouter({
    history: createWebHashHistory(),
    routes: [
        {
            name: 'zhuye',
            path: '/home',
            component: Home
        },
        {
            name: 'xinwen',
            path: '/news',
            component: News,
            children: [
                {
                    name: 'xiang',
                    component: Detail,
                    // 第一种写法,使用props 需要使用path的占位
                    // path: 'detail/:id/:title/:content',
                    // props:true
                    // 第二种写法,可以自己决定将什么给props <RouterLink :to="{ 需要改成query
                    path: 'detail',
                    props(router){
                        return router.query
                    }
                    // 第三种写法
                //     props: {
                //         a: 100,
                //         b: 200
                //     }
                }
            ]
        },
        {
            name: 'guanyu',
            path: '/about',
            component: About
        },
    ]
})


export default router
<template>
    <ul>
        <li v-for="news in newList" :key="news.id">

            <!-- 第一种写法 -->
            <!-- <RouterLink :to="`/news/detail/${news.id}/${news.title}/${news.content}`">
                {{ news.title }}
            </RouterLink> -->

            <!-- 第二种写法 -->
            <RouterLink :to="{
                name: 'xiang',
                // 下面的query或者params 需要和路由里的相呼应
                query: {
                    id: news.id,
                    title: news.title,
                    content: news.content
                }
            }
                ">
                {{ news.title }}
            </RouterLink>




        </li>

    </ul>
    <hr>
    <div>
        <RouterView></RouterView>
    </div>
</template>

<script setup name="about" lang="ts">
import { reactive } from 'vue';
const newList = reactive([
    { id: '001', title: "爱因斯坦一样,每当你提出了一个棘手的问题,", content: "杀死谷歌,成为AI时代的搜索皇帝!" },
    { id: '002', title: "推理计算,随着算力的增加,得到的答案质量也会", content: "诚邀!腾讯云套件新品发布会" },
    { id: '003', title: "字已经不再陌生。英伟达黄仁勋称它为“自己每天都", content: "​李彦宏:AI时代应避免掉入超级应用" },
    { id: '004', title: " Perplexity 的 CEO 埃拉文德·斯里尼瓦", content: "开发者投Rust重写系统后痛批" },
    { id: '005', title: "title005 学家,亲历了 Transformer 前生今世);", content: "图灵传人Steven Pemberton直言:未来AI或将毁灭90%人类 | Open AGI Forum" },
    { id: '006', title: "、贝索斯、杨立昆、扎克伯格,聊到了科学家、作家、艺术家,甚至梅西和罗纳尔多两位运动员", content: "“剑指 C/C++”,美国CISA等机构再" },
])
</script>
<style scoped></style>
<template>
    <ul>
        <li> {{ id }}</li>
        <li> {{ title }}</li>
        <li> {{ content }}</li>

    </ul>
</template>

<script setup name="about" lang="ts">
defineProps(['id', 'title', 'content'])
</script>
<style scoped></style>

编程式路由

//创建路由器器

import { createRouter, createWebHistory, createWebHashHistory } from 'vue-router'
import Home from '@/pages/Home.vue'
import News from '@/pages/News.vue'
import About from '@/pages/About.vue'
import Detail from '@/pages/Detail.vue'
const router = createRouter({
    history: createWebHashHistory(),
    routes: [
        {
            name: 'home',
            path: '/',
            redirect:'/home'
        },
        {
            name: 'zhuye',
            path: '/home',
            component: Home
        },
        {
            name: 'xinwen',
            path: '/news',
            component: News,
            children: [
                {
                    name: 'xiang',
                    component: Detail,
                    // 第一种写法,使用props 需要使用path的占位
                    // path: 'detail/:id/:title/:content',
                    // props:true
                    // 第二种写法,可以自己决定将什么给props <RouterLink :to="{ 需要改成query
                    path: 'detail',
                    props(router){
                        return router.query
                    }
                    // 第三种写法
                //     props: {
                //         a: 100,
                //         b: 200
                //     }
                }
            ]
        },
        {
            name: 'guanyu',
            path: '/about',
            component: About
        },
    ]
})


export default router
<template>
    <ul>
        <li v-for="news in newList" :key="news.id">
            <button @click="showNewsDetail(news)">查看详情</button>
            <RouterLink :to="{
                name: 'xiang',
                // 下面的query或者params 需要和路由里的相呼应
                query: {
                    id: news.id,
                    title: news.title,
                    content: news.content
                }
            }
                ">
                {{ news.title }}
            </RouterLink>




        </li>

    </ul>
    <hr>
    <div>
        <RouterView></RouterView>
    </div>
</template>

<script setup name="about" lang="ts">
import { reactive } from 'vue';
import { useRouter } from 'vue-router';
const newList = reactive([
    { id: '001', title: "爱因斯坦一样,每当你提出了一个棘手的问题,", content: "杀死谷歌,成为AI时代的搜索皇帝!" },
    { id: '002', title: "推理计算,随着算力的增加,得到的答案质量也会", content: "诚邀!腾讯云套件新品发布会" },
    { id: '003', title: "字已经不再陌生。英伟达黄仁勋称它为“自己每天都", content: "​李彦宏:AI时代应避免掉入超级应用" },
    { id: '004', title: " Perplexity 的 CEO 埃拉文德·斯里尼瓦", content: "开发者投Rust重写系统后痛批" },
    { id: '005', title: "title005 学家,亲历了 Transformer 前生今世);", content: "图灵传人Steven Pemberton直言:未来AI或将毁灭90%人类 | Open AGI Forum" },
    { id: '006', title: "、贝索斯、杨立昆、扎克伯格,聊到了科学家、作家、艺术家,甚至梅西和罗纳尔多两位运动员", content: "“剑指 C/C++”,美国CISA等机构再" },
])
interface NewsInter {
    id: string
    title: string
    content: string
}
const router = useRouter()
function showNewsDetail(news: NewsInter) {
    router.push(
        {
            name: 'xiang',
            query: {
                id: news.id,
                title: news.title,
                content: news.content
            }
        }
    )
}
</script>
<style scoped></style>

Pinia

基本操作

挂载

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");

模板

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

<script setup>
import { useTalkStore } from "@/store/talk";
const talkStore = useTalkStore();
let talkList=talkStore.talkList
function getLoveTalk() {
  talkStore.getLoveTalk();
}
</script>

<style></style>





<template>
  <h2>
    当前求和为:{{ sum }} <br>
    当前位置是:{{location}}
    <br />
    <select name="" id="" v-model.number="n">
      <option value="1" selected>1</option>
      <option value="2">2</option>
      <option value="3">3</option>
    </select>
    <button @click="AddCount">加</button>
    <button @click="JianCount">减</button>
  </h2>
</template>

<script setup>
import { ref } from "vue";
import { useCountStore } from "@/store/count";
import { storeToRefs } from "pinia";
const countStore = useCountStore();
let n = ref(1);
// 提取数据转为响应式
const {sum,location}=storeToRefs(countStore)

function AddCount() {
  // 第一种修改方式 常用
  // countStore.sum += n.value;
  // 第二种修改方式 批量
  // newSum=countStore.sum += n.value
  // countStore.$patch(
  //   {sum:newSum}
  // )
  // 第三种修改方式 使用动作,给countStore增加运动
  countStore.increment(n.value);
}


function JianCount() {

  countStore.sum -= n.value;
}
</script>

<style>
.select,
.button {
  margin: 0 5px;
  height: 20px;
}
</style>

配置

import { defineStore } from "pinia";
export const useCountStore = defineStore("count", {
  // actions为配置里的第三种方法
  actions: {
    increment(value: any) {
      this.sum += value
    },
  },
  state() {
    return {
      sum: 6,
      location:'北京'
    };
  },
});



import { defineStore } from "pinia";
import axios from "axios";
import { nanoid } from "nanoid";
interface TalkInter {
  id: string;
  title: string;
}
type TalkInterList = TalkInter[];
export const useTalkStore = defineStore("talk", {
  actions: {
    async getLoveTalk() {
       let {  
      data: { content: title },  
    } = await axios.get("https://api.uomg.com/api/rand.qinghua?format=json");  
    let obj: TalkInter = { id: nanoid(), title: title };  
    this.talkList.unshift(obj);
    },
  },
  state: (): { talkList: TalkInterList} => {
    return {
      talkList: [],
    };
  },
});

GETTER

import { defineStore } from 'pinia'
export const useCountStore = defineStore(
    'count', {
    state() {
        return {
            sum: 1,
            address: "beijing"
        }
    },
    actions: {},
    getters: {
        bigSum: state => state.sum * 10,
        upAddress(state):string{
            return this.address.toUpperCase()

        }
    }
}
)
<template>

    1234213
    {{ bigSum }}
    <br>
    {{ upAddress }}
    
</template>

<script setup name="about" lang="ts">
import {storeToRefs} from 'pinia'
import { useCountStore } from '@/store/useHomeStore.ts'
const { bigSum, upAddress } = storeToRefs(useCountStore())

</script>

<style scoped></style>

订阅

// 监视某个值
countstore.$subscribe((newval,oldval) => {
    console.log('@@@', newval, oldval)
})
function change() {
    countstore.sum += 1
}

组件通信

defineProps

father

<template>
    <div class="father">
        <h3>父组件,</h3>
        <h4>我的车:{{ car }}</h4>
        <h4>儿子给的玩具:{{ toy }}</h4>
        <Child :car="car" :getToy="getToy" />
    </div>
</template>

<script setup lang="ts" name="Father">
import Child from './Child.vue'
import { ref } from "vue";
// 数据
const car = ref('奔驰')
const toy = ref()
// 方法
function getToy(value: string) {
    toy.value = value
}
</script>

child

<template>
    <div class="child">
        <h3>子组件</h3>
        <h4>我的玩具:{{ toy }}</h4>
        <h4>父给我的车:{{ car }}</h4>
        <button @click="getToy(toy)">玩具给父亲</button>
    </div>
</template>

<script setup lang="ts" name="Child">
import { ref } from "vue";
const toy = ref('奥特曼')

defineProps(['car', 'getToy'])
</script>

自定义事件(子传父)

<template>
    <div class="father">
        <h3>父组件,</h3>
        <h4 v-show="str">收到儿子玩具:{{ str }}</h4>
        <br>
        <Child @haha='xyz' />
    </div>
</template>

<script setup lang="ts" name="Father">
import Child from './Child.vue'
import { ref } from "vue";
let str=ref('')
function xyz(value:any){
    console.log(value)
    str.value = value}

</script>

<template>
    <div class="child">
        <h3>子组件</h3>
        <h4>我的玩具:{{ toy }}</h4>

    </div>
</template>

<script setup lang="ts" name="Child">
import { ref,onMounted } from "vue";
let toy = ref('奥特曼')
//申明事件
const emit = defineEmits(['haha'])
onMounted(
    ()=>{
        setTimeout(()=>{
            emit('haha', toy)
        },2000)
    }
)
</script>

mitt

import mitt from "mitt";
const emitter = mitt();
export default emitter;
<template>
  <div class="bg1">
    <h2>子组件1</h2>
    <h4>玩具:{{ toy }}</h4>
    <br />
    <button @click="send_toy">玩具给弟弟</button>
  </div>
</template>

<script setup>
import { ref } from "vue";
import emitter from "@/utils/emitter";
let toy = ref("皮球");
function send_toy() {
  emitter.emit("sent_toy", toy.value);
}
</script>

<style scoped>
.bg1 {
  padding: 10px;
  background-color: blanchedalmond;
}
</style>
<template>
  <div class="bg2">
    <h2>子组件2</h2>
    <h4>我的电脑:{{ computer }}</h4>
    <h4>哥哥给的玩具:{{ toy }}</h4>
  </div>
</template>
<script setup>
import { ref, onUnmounted,onMounted } from "vue";
import emitter from "@/utils/emitter";
let computer = ref("联想");
let toy = ref("");

//绑定
emitter.on("sent_toy", (value) => {
  toy.value = value;
});
//解绑
// onMounted(
//     console.log(1)
// )
onMounted (
    ()=>{ console.log(1)}
   
    // emitter.off('sent_toy')
)
onUnmounted (
    ()=>{ console.log(2)}
   
    // emitter.off('sent_toy')
)
</script>

<style scoped>
.bg2 {
  padding: 10px;
  background-color: aquamarine;
}
</style>

v-model

单个

<template>
  <div class="bg">
    <h1>父组件</h1>
    <h4>{{ userName }}</h4>
    <AtguiguInput v-model="userName" />
     <!-- 上面代码的本质如下 -->
    <!-- <AtguiguInput :abc="userName" @update:abc="userName = $event" /> -->
  </div>
</template>

<script setup>
import AtguiguInput from "./AtGuiGuInput.vue";
import { ref } from "vue";
let userName = ref("zhangsan");
</script>

<style scoped>
.bg {
  padding: 10px;
  background-color: aqua;
}
</style>


<template>
    <div class="box">
      <input 
         type="text" 
         :value="modelValue" 
         @input="emit('update:modelValue',(<HTMLInputElement>$event.target).value)"
      >
    </div>
  </template>
  
  <script setup lang="ts" name="AtguiguInput">
    // 接收props
    defineProps(['modelValue'])
    // 声明事件
    const emit = defineEmits(['update:modelValue'])
  </script>
  

 多个绑定

<template>
  <div class="bg">
    <h1>父组件</h1>
    <h4>{{ userName }}</h4>
    <AtguiguInput v-model:account="userName" v-model:passWord="passWord"/>
     <!-- 上面代码的本质如下 -->
    <!-- <AtguiguInput :abc="userName" @update:abc="userName = $event" /> -->
  </div>
</template>

<script setup>
import AtguiguInput from "./AtGuiGuInput.vue";
import { ref } from "vue";
let userName = ref("zhangsan");
let passWord = ref("123456");
</script>

<style scoped>
.bg {
  padding: 10px;
  background-color: aqua;
}
</style>


<template>
    <div class="box">
      <input 
         type="text" 
         :value="account" 
         @input="emit('update:account',(<HTMLInputElement>$event.target).value)"
      >
      <br>
      <input 
         type="text" 
         :value="passWord" 
         @input="emit('update:passWord',(<HTMLInputElement>$event.target).value)"
      >
    </div>
  </template>
  
  <script setup lang="ts" name="AtguiguInput">
    // 接收props
    defineProps(['account','passWord'])
    // 声明事件
    const emit = defineEmits(['update:account','update:passWord'])
  </script>
  

$attrs

祖给孙

<template>
  <div class="bg">
    <h1>父组件</h1>
    <h4>{{ a }}</h4>
    <h4>{{ b }}</h4>
    <h4>{{ c }}</h4>
    <h4>{{ d }}</h4>
    <Child :a="a" :b="b" v-bind="{ x: 100, y: 200 }" :updateA="updateA" />
  </div>
</template>

<script setup>
import Child from "./Child.vue";
import { ref } from "vue";
let a = ref(1);
let b = ref(2);
let c = ref(3);
let d = ref(4);
function updateA(val) {
  a.value += val;
}
</script>

<style scoped>
.bg {
  padding: 10px;
  background-color: aqua;
}
</style>
<template>
  <div class="bg1">
    <h2>子组件1</h2>
    <h4>{{ $attrs }}</h4>
    <GrandChild v-bind="$attrs" />
  </div>
</template>

<script setup>
import { ref } from "vue";
import GrandChild from "./GrandChild.vue";

</script>

<style scoped>
.bg1 {
  padding: 10px;
  background-color: blanchedalmond;
}
</style>
<template>
  <div class="bg2">
    <h2>孙组件</h2>
    <h4>{{ $attrs }}</h4>
    <h4>{{ a }}</h4>
    <br>
    <button @click="updateA(6)">更新A</button>
  </div>
</template>
<script setup>
defineProps(["a", "updateA"]);
</script>

<style scoped>
.bg2 {
  padding: 10px;
  background-color: blueviolet;
}
</style>

$refs &parent

<template>
  <div class="bg">
    <h1>父组件</h1>
    <h4>房子:{{ house }}</h4>
    <button @click="changeToy">修改CHILD1玩具</button>
    <button @click="changeComputer">修改CHILD2电脑</button>
    <button @click="changeChild($refs)">获取所有子组件,书变多</button>
    <hr />
    <br />
    <Child1 ref="c1" />
    <Child2 ref="c2" />
  </div>
</template>

<script setup lang="ts">
import Child1 from "./Child1.vue";
import Child2 from "./Child2.vue";
import { ref } from "vue";

let house = ref(4);
let c1 = ref();
let c2 = ref();

function changeToy() {
  c1.value.toy = "小猪佩奇";
}
function changeComputer() {
  c2.value.computer = "华为";
}
function changeChild(refs: { [key: string]: any }) {
  for (let key in refs) {
    refs[key].book += 1;
  }
}
defineExpose({ house });
</script>

<style scoped>
.bg {
  padding: 10px;
  background-color: aqua;
}
</style>
<template>
  <div class="bg1">
    <h4>子组件1</h4>
    <h4>玩具:{{ toy }}</h4>
    <h4>书:{{ book }}本</h4>
    <button @click="minHouse($parent)">减掉父亲房产</button>
  </div>
</template>

<script setup>
import { ref } from "vue";

let toy = ref("奥特曼");
let book = ref(1);
function minHouse(parent) {
  parent.house -= 1;
}
//把数据交给外部
defineExpose({ toy, book });
</script>

<style scoped>
.bg1 {
  padding: 10px;
  background-color: blanchedalmond;
}
</style>
<template>
  <div class="bg2">
    <h4>子组件2</h4>
    <h4>电脑:{{ computer }}</h4>
    <h4>书:{{ book }}本</h4>
  </div>
</template>

<script setup>
import { ref } from "vue";

let computer = ref("联想");
let book = ref(3);
defineExpose({ computer, book });
</script>
<style scoped>
.bg2 {
  padding: 10px;
  background-color: blueviolet;
}
</style>

provide_inject

<template>
    <h1>父亲</h1>
    <h2>银子:{{ money }}</h2>
    <h2>车:{{ car }}</h2>

    <Child></Child>
</template>

<script setup lang="ts" name="Father">
import Child from './Child.vue'
import { ref, reactive, provide } from 'vue'

let money = ref(100)
let car = reactive({ brand: '奔驰', price: 100 })
function changeMoney(val: number) {
    car.price += val
}
provide('moneyContext', { money: money, changeMoney })
provide('car', car)
</script>
<template>

        <h3>孙组件</h3>
        <h2>银子:{{ money }}</h2>
        <h2>车:{{ car.brand }}</h2>
        <h2>价格:{{ car.price }}</h2>
        <button @click="changeMoney(6)"> 修改钱</button>

</template>

<script setup lang="ts" name="GrandChild">
import { inject } from 'vue'
let { money, changeMoney } = inject('moneyContext', { money: 0, changeMoney: (x: number) => { } })
let car = inject('car', { brand: '', price: 0 })

</script>
<template>
    <h1>孩子</h1>
    <GrandChild />
    </template>

    <script setup lang="ts" name="Child">
    import GrandChild from './GrandChild.vue'

</script>

slot

默认插槽

<template>
    <div class="father">
        <div class="content">
            <Category title="热门游戏">
                <ul>
                    <li v-for="g in games" :key="g.id">{{ g.name }} </li>
                </ul>
            </Category>
            <Category title="今日美食">
                <img :src=imgUrl>
            </Category>
            <Category title="影视推荐">
<video :src=videoUlr controls></video>
            </Category>
        </div>

    </div>
</template>

<script setup lang="ts" name="Father">
import Category from './Category.vue'
import { reactive } from "vue";
let games = reactive([
    { id: 'asgdytsa01', name: '英雄联盟' },
    { id: 'asgdytsa02', name: '王者荣耀' },
    { id: 'asgdytsa03', name: '红色警戒' },
    { id: 'asgdytsa04', name: '斗罗大陆' }
])
let imgUrl = 'https://msdn.itellyou.cn/images/20221006234339-min.png'
let videoUlr = 'https://video.shipin520.com/video_listen/588ku_video/19/08/13/18/08/33/video5d528c21df2bc.mp4'
</script>
<style scoped>
    .father {
        background-color: aqua;
        padding: 20px;
        border-radius: 10px;
    }

    .content {
        display: flex;
        justify-content: space-evenly;
    }

    img,
    video {
        width: 100%;
    }


</style>
<template>
   <div class="category">
    <h2>{{title}}</h2>
    <slot>默认内容</slot>
   </div>
</template>

<script setup lang="ts" name="Category">
defineProps(['title'])
</script>
<style scoped>
    .category {
        background-color: skyblue;
        border-radius: 10px;
        box-shadow: 0 0 10px;
        padding: 10px;
        width: 200px;
        height: 300px;
    }
    h2{
        background-color: orange;
        text-align: center;
        font-size: 20px;
        font-weight: 800;
    }
</style>

具名插槽

<template>
    <div class="father">
        <div class="content">


            <Category>
                <template v-slot:s2>
                    <ul>
                        <li v-for="g in games" :key="g.id">{{ g.name }} </li>
                    </ul>
                </template>
                <template v-slot:s1>
                    <h2>热门游戏</h2>
                </template>
            </Category>

            <Category>
                <template #s2>
                    <img :src=imgUrl>
                </template>
                <template #s1>
                    <h2>热门游戏</h2>
                </template>
            </Category>

            <Category>
                <template #s2>
                    <video :src=videoUlr controls></video>
                </template>
                <template #s1>
                    <h2>热门游戏</h2>
                </template>
            </Category>

        </div>

    </div>
</template>

<script setup lang="ts" name="Father">
import Category from './Category.vue'
import { reactive } from "vue";
let games = reactive([
    { id: 'asgdytsa01', name: '英雄联盟' },
    { id: 'asgdytsa02', name: '王者荣耀' },
    { id: 'asgdytsa03', name: '红色警戒' },
    { id: 'asgdytsa04', name: '斗罗大陆' }
])
let imgUrl = 'https://msdn.itellyou.cn/images/20221006234339-min.png'
let videoUlr = 'https://video.shipin520.com/video_listen/588ku_video/19/08/13/18/08/33/video5d528c21df2bc.mp4'
</script>
<style scoped>
    .father {
        background-color: aqua;
        padding: 20px;
        border-radius: 10px;
    }

    .content {
        display: flex;
        justify-content: space-evenly;
    }

    img,
    video {
        width: 100%;
    }


</style>
<template>
    <div class="category">
        <slot name="s1"></slot>
        <slot name="s2"></slot>
    </div>
</template>

<script setup lang="ts" name="Category">
defineProps(['title'])
</script>
<style scoped>
    .category {
        background-color: skyblue;
        border-radius: 10px;
        box-shadow: 0 0 10px;
        padding: 10px;
        width: 200px;
        height: 300px;
    }

    h2 {
        background-color: orange;
        text-align: center;
        font-size: 20px;
        font-weight: 800;
    }



</style>

作用域

<template>
    <div class="father">
        <div class="content">
            <Game>
                <template v-slot="{ games }">
                    <ul>
                        <li v-for="g in games" :key="g.id">{{ g.name }} </li>
                    </ul>
                </template>
            </Game>
            <Game>
                <template v-slot="{ games }">
                    <ol>
                        <li v-for="g in games" :key="g.id">{{ g.name }} </li>
                    </ol>
                </template>
            </Game>
            <Game>
                <template v-slot="{ games }">
                    <h4>
                        <li v-for="g in games" :key="g.id">{{ g.name }} </li>
                    </h4>
                </template>
            </Game>
        </div>

    </div>
</template>

<script setup lang="ts" name="Father">
import Category from './Category.vue'
import Game from './Game.vue'
import { reactive } from "vue";
let games = reactive([
    { id: 'asgdytsa01', name: '英雄联盟' },
    { id: 'asgdytsa02', name: '王者荣耀' },
    { id: 'asgdytsa03', name: '红色警戒' },
    { id: 'asgdytsa04', name: '斗罗大陆' }
])
let imgUrl = 'https://msdn.itellyou.cn/images/20221006234339-min.png'
let videoUlr = 'https://video.shipin520.com/video_listen/588ku_video/19/08/13/18/08/33/video5d528c21df2bc.mp4'
</script>
<style>
    .father {
        background-color: aqua;
        padding: 20px;
        border-radius: 10px;
    }

    .content {
        display: flex;
        justify-content: space-evenly;
    }

    img,
    video {
        width: 100%;
    }

    h2 {
        background-color: orange;
        text-align: center;
        font-size: 20px;
        font-weight: 800;
    }


</style>
<template>
    <div class="game">
        <h2>热门游戏</h2>
        <slot :games="games"></slot>
    </div>
</template>

<script setup lang="ts" name="Category">
import { reactive } from "vue";
let games = reactive([
    { id: 'asgdytsa01', name: '英雄联盟' },
    { id: 'asgdytsa02', name: '王者荣耀' },
    { id: 'asgdytsa03', name: '红色警戒' },
    { id: 'asgdytsa04', name: '斗罗大陆' }
])
</script>
<style scoped>
    .game {
        background-color: skyblue;
        border-radius: 10px;
        box-shadow: 0 0 10px;
        padding: 10px;
        width: 200px;
        height: 300px;
    }
</style>

其它API

shallowRef和shallowReactive

提升性能,绕开深度响应

<template>
  <Header></Header>
  {{ person }}
  <br>
  {{ car }}
  <br>

  <button @click="changezs">改张三</button>
  <br>
  <button @click="changeren">改车</button>
</template>
<script setup name="App" lang="ts">
import { shallowReactive, shallowRef } from 'vue';

//shallowRef 改不成功 关注是否整体修改
let person = shallowRef({
  name: '张三',
  age: 18
})
function changezs() {
  person.value.age += 1
}

//shallowRef 改不成功 关注是否整体修改
let car = shallowReactive({
  brand: '奔驰',
  options: {
    color: '红色',
    engine: 'V8'
  }
})
function changeren() {
  car.options.engine ="V9"
}



</script>
<style scoped></style>

readonly shallowReadonly

<template>
  <Header></Header>
  {{ sum1 }}
  {{ sum2 }}
  <button @click="changeSum1">改sum1</button>
  <button @click="changeSum2">改sum2</button>
  <br>
</template>
<script setup name="App" lang="ts">
// 当给别人数据,但是不希望别人改数据
// shallowReadonly只处理浅层的只读,第二层之后就可以改了
import { ref, readonly } from 'vue';
let sum1 = ref(0)
let sum2 = readonly(sum1)
function changeSum1() {
  sum1.value += 1
}
function changeSum2() {
  sum2.value += 1
}
</script>
<style scoped></style>

toRaw markRaw

toraw

<template>
  <Header></Header>
  {{ person.name }}
  {{ person.age }}
  <hr>
  {{ person2.name }}
  {{ person2.age }}

  <button @click="changeAge">改AGE 响应式</button>
  <button @click="changeAgeRaw">改AGE RAW</button>
  <br>
</template>
<script setup name="App" lang="ts">
import { toRaw, reactive } from 'vue';
let person = reactive({
  name: 'tony',
  age: 18
})

// 获取响应式对象的原始数据 用途:比如临时读取,有些临时修改,最好才保存的场景
let person2 = toRaw(person)
function changeAge() {
  person.age += 1
}
function changeAgeRaw() {
  person2.age += 1
}
</script>
<style scoped></style>

markRaw

<template>
  <Header></Header>
  {{ car2 }}
  <button @click="changeAge">改AGE 响应式</button>
  <br>
</template>
<script setup name="App" lang="ts">
import { markRaw, reactive } from 'vue';
let car = markRaw ({
  brand: '奔驰',
  price: 100
})
let car2 = reactive(car)

function changeAge() {
  car2.price += 1
}

</script>
<style scoped></style>

customRef

<template>
  <h2>MSG:{{ msg }}</h2>
  <input type="text" v-model="msg" />
</template>
<script setup lang="ts">
import useMsgRef from "./hoos/useMsgRef";
let {msg} = useMsgRef("你好", 2000);
</script>
<style scoped></style>

import { customRef } from "vue";
export default function (initValue: string, delay: number) {
  let timer: number;
  let msg = customRef((track, trigger) => {
    return {
      //读取时
      get() {
        //对数据持续关注
        track();
        return initValue;
      },
      //修改时
      set(value) {
        clearTimeout(timer);
        timer = setTimeout(() => {
          initValue = value;
          //通知VUE数据发生变化了
          trigger();
        }, delay);
      },
    };
  });
  return { msg };
}

新组件

Teleport

<template>
  <div class="outer">
    我是APP组件
    <hr>
    <Modal />
  </div>
</template>
<script setup lang="ts" name="APP">
import Modal from "./Modal.vue";
</script>
<style scoped>
.outer {
  background-color: aliceblue;
  border-radius: 10px;
  padding: 5px;
  box-shadow: 0 0 10px;
  width: 400px;
  height: 400px;
  text-align: center;
  filter: saturate(10%);
}
</style>
<template>
  
  <button @click="isShow = true">展示弹窗</button>
  <teleport to="body">
  <div class="modal" v-show="isShow">
    <h2>弹窗标题</h2>
    <p>弹窗的内容</p>
    <p>弹窗的内容</p>
    <button @click="isShow = false">关闭弹窗</button>
  </div>
</teleport>
</template>
<script setup lang="ts" name="Modal">
import { ref } from "vue";
let isShow = ref(false);
</script>
<style scoped>
.modal {
  width: 200px;
  height: 200px;
  background-color: aquamarine;
  border-radius: 10px;
  padding: 5px;
  box-shadow: 0 0 5px;
  text-align: center;
  position: fixed;
  left: 50%;
  margin-left: -100px;
  top: 20px;
}
</style>

Suspense

<template>
  <div class="outer">
    我是APP组件
    <hr />
    <Suspense>
      <template v-slot:default>
        <Child />
      </template>
      <template v-slot:fallback> 加载中 </template>
    </Suspense>
  </div>
</template>
<script setup lang="ts" name="APP">
import Child from "./Child.vue";
import { Suspense } from "vue";
</script>
<style scoped></style>
<template>我是子组件</template>
<script setup lang="ts" name="Modal">
import axios from "axios";
let {data:{content}} = await axios.get("https://api.uomg.com/api/rand.qinghua?format=json");
</script>
<style scoped></style>

全局API转移到应用对象

app.component全局组件

app.config 全局属性

declare 申明

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值