一、数据响应
修改数据
<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 申明