Vite+Typescript+Vue3学习笔记

Vite+Typescript+Vue3学习笔记

1、项目搭建

1.1、创建项目(yarn)

D:\WebstromProject>yarn create vite
yarn create v1.22.19
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...success Installed "create-vite@4.4.1" with binaries:- create-vite- cva
√ Project name: ... vite-project
√ Select a framework: » Vue
√ Select a variant: » TypeScriptScaffolding project in D:\WebstromProject\vite-project...Done. Now run:cd vite-projectyarnyarn devDone in 14.81s.

在这里插入图片描述

1.2、项目配置

1、配置vue文件识别

vite默认情况下不识别.vue后缀的文件,需在vite-env.d.ts配置下

/// <reference types="vite/client" />
declare module "*.vue" {import { DefineComponent } from "vue"const component: DefineComponent<{}, {}, any>export default component
}

2、Api选择

/* Options API */
export default {props: {},data(){},computed: {},watch: {},methods: {},created(),components:{}// ...other options
}
/* Composition API */
export default {props: {},setup(),components:{}
}

Vue3推荐使用Composition API,这里关闭Vue2的Option Api

import {defineConfig} from 'vite'
import vue from '@vitejs/plugin-vue'// https://vitejs.dev/config/
export default defineConfig({define: {// 关闭Vue2 Options Api__VUE_OPTIONS_API__: false},plugins: [vue(),],
})

1.3、常用依赖

1、@types/node

ts需安装node的类型,否则使用node相关会提示找不到

# @types/node
yarn add -D @types/node

2、auto-import

用于简化Vue3中ref、reactive**、**watch和UI组件的导入

# unplugin-vue-components、unplugin-auto-import
yarn add -D unplugin-vue-components unplugin-auto-import

3、sass

# sass
yarn -D add sass

2、Composition API

2.1、响应式

可以在chrome浏览器开启自定义格式化,便于查看

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sEWfdHAM-1690717347682)(C:\Users\lianxin\AppData\Roaming\Typora\typora-user-images\image-20230728093837507.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3UMPZ6T4-1690717347682)(C:\Users\lianxin\AppData\Roaming\Typora\typora-user-images\image-20230728093754299.png)]

1、ref

ref通常用于声明基础类型响应式数据,引用类型也可以,会隐式调用reactive,同时取值赋值都需要.value

<script setup lang="ts">
import {Ref} from "vue";
// 非响应式
// let number: number = Math.random()
// console.log(isRef(number))// 响应式
// let number = ref(Math.random())
// 显式类型约束
let number: Ref<number> = ref<number>(Math.random())
console.log(isRef(number))
const h1click = () => {// 非响应式// number = Math.random()// 响应式number.value = Math.random()console.log(number);
}
</script><template><div><h1 @click="h1click">{{ number }}</h1></div>
</template><style scoped></style>

2、shallowRef

只处理基本数据类型的响应式, 不进行对象的响应式处理(不能与ref一起用,否则会被迫更新视图)

<script setup lang="ts">
import {isShallow, Ref} from "vue";let number = shallowRef<number>(Math.random())
console.log(isShallow(number))
const h1click = () => {number.value = Math.random()console.log(number);
}
</script><template><div><h1 @click="h1click">{{ number }}</h1></div>
</template><style scoped></style>

3、reactive

reactive用于声明引用类型响应式数据,且对象解构后会失去响应式

<script setup lang="ts">let person = reactive({name: "xumeng"
})
console.log(isReactive(person))
const h1click = () => {person.name = "xumeng03"console.log(person);
}
</script><template><div><h1 @click="h1click">{{ person }}</h1></div>
</template><style scoped></style>

4、shallowReactive

只处理对象最外层属性的响应式(浅响应式),(不能与reactive一起用,否则会被迫更新视图)

<script setup lang="ts">let person = shallowReactive({name: "xumeng",hobby: ["game","code"]
})
console.log(isReactive(person))
const h1click = () => {// 浅层次数据// person.name = "xumeng03"// 深层次数据(如果浅层次&深层次数据一起变化,则会一起更新)person.hobby[0] = 'movie'console.log(person);
}
</script><template><div><h1 @click="h1click">{{ person }}</h1></div>
</template><style scoped></style>

5、toRef

将对象某个属性变为响应式

<script setup lang="ts">let person = reactive({name: "xumeng"
})
// 如果person非响应式对象,则不会引起视图更新
let name = toRef(person, 'name')
const h1click = () => {name.value = "xumeng03"console.log(person);
}
</script><template><div><h1 @click="h1click">{{ person }}</h1></div>
</template><style scoped></style>

6、toRefs

将对象的一些解构属性变为响应式

<script setup lang="ts">let person = reactive({name: "xumeng",age: 22
})
// 解构别名
let {name: pname, age: page} = toRefs(person)
const h1click = () => {pname.value = "xumeng03"page.value = 23console.log(pname, page);
}
</script><template><div><h1 @click="h1click">{{ person }}</h1></div>
</template><style scoped></style>

7、toRaw

把响应式对象变为普通对象

<script setup lang="ts">let person = reactive({name: "xumeng",age: 22
})let rperson = toRaw(person)
const h1click = () => {rperson.name = "xumeng03"rperson.age = 23console.log(rperson);
}
</script><template><div><h1 @click="h1click">{{ person }}</h1></div>
</template><style scoped></style>

2.2、修饰符

1、readonly

<script setup lang="ts">let person = reactive({name: "xumeng"
})
let rperson = readonly(person)
const h1click = () => {// 正常赋值person.name = "xumeng03"// 报错// rperson.name = "xumeng03"console.log(person);
}
</script><template><div><h1 @click="h1click">{{ person }}</h1></div>
</template><style scoped></style>

2.3、computed

1、选项式写法

参数为对象,需传入一个get和set函数自定义存取操作

<script setup lang="ts">let person = reactive({name: "xumeng03",nickName: '眼眸流转',age: 22
})
let people = computed({get() {return person.name + '-' + person.nickName},set(newValue) {[person.name, person.nickName] = newValue.split('-')}
})
const h1click = () => {people.value = '徐梦-眼眸'
}
</script><template><div><h1 @click="h1click">{{ people }}</h1></div>
</template><style scoped></style>

2、函数式写法

<script setup lang="ts">let person = reactive({name: "xumeng03",nickName: '眼眸流转',age: 22
})
let people=computed(()=>{return person.name + '-' + person.nickName
})
const h1click = () => {// 不支持修改// people.value = '徐梦-眼眸'
}
</script><template><div><h1 @click="h1click">{{ people }}</h1></div>
</template><style scoped></style>

2.4、监听

1、watch

基本类型

<script setup lang="ts">let age = ref(22)
const h1click = () => {age.value++
}
watch(age, (value, oldValue) => {console.log("监听到变化:", value, oldValue);
})
</script><template><div><h1 @click="h1click">{{ age }}</h1></div>
</template><style scoped></style>

引用类型

<script setup lang="ts">let person = reactive({name: "xumeng03",nickName: '眼眸流转',age: 22
})
let person1 = reactive({name: "xumeng03",nickName: '眼眸流转',age: 22
})
const h1click = () => {person.age++
}
let people = computed(() => {return person.name + '-' + person.nickName + '-' + person.age
})// 此时若监听person会发现新旧数据一致,可以使用computed处理一下返回(如返回新的信息或深拷贝原引用数据)
// watch(person, (value, oldValue) => {
//     console.log("监听到变化:", value, oldValue);
// }, {
//     // 深度监听,reactive默认就是深度监听
//     deep: true,
//     // 立即执行一次
//     immediate: true,
//     // 刷新时机
//     flush: 'pre'
// })// 监听整个引用数据
watch(people, (value, oldValue) => {console.log("监听到变化:", value, oldValue);
}, {// 深度监听,reactive默认就是深度监听deep: true,// 立即执行一次immediate: true,// 刷新时机flush: 'pre'
})// 监听引用对象某个属性
watch(() => person.age, (value, oldValue) => {console.log("监听到变化:", value, oldValue);
}, {// 深度监听,reactive默认就是深度监听deep: true,// 立即执行一次immediate: true,// 刷新时机flush: 'pre'
})// 监听多个数据源
watch([person, person1], (value, oldValue) => {console.log("监听到变化:", value, oldValue);
}, {// 深度监听,reactive默认就是深度监听deep: true,// 立即执行一次immediate: true,// 刷新时机flush: 'pre'
})
</script><template><div><h1 @click="h1click">{{ people }}</h1></div>
</template><style scoped></style>

2、watchEffect

 <script setup lang="ts">let age = ref(22)
const h1click = () => {age.value++
}
// watchEffect返回一个停止监听函数
const stopwatch = watchEffect((oninvalidate) => {oninvalidate(() => {console.log("变化前");})console.log(age);
})
// 停止监听
// stopwatch()
</script><template><div><h1 @click="h1click">{{ age }}</h1></div>
</template><style scoped></style>

3、组件

3.1、全局组件

全局组件

<script setup lang="ts"></script><template><div>这是一个card</div>
</template><style scoped lang="scss"></style>

注册

import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import router from "./router";
import Card from "./components/Card.vue";
// 这里要注册下组件
createApp(App).component('Card',Card).use(router).mount('#app')
// 批量注册
// let app = createApp(App)
// import Card from "./components/Card.vue";
// const components = [
//     Card
// ];
// for (const componentsKey in components) {
//     app.component(componentsKey, components[componentsKey])
// }

使用

<script setup lang="ts">import HomeView from "./view/HomeView.vue";let HomeViewFlag = ref(true)
</script><template><div><a @click="()=>{HomeViewFlag=!HomeViewFlag}"><img src="/vite.svg" class="logo" alt="Vite logo"/></a><a @click="()=>HomeViewFlag=!HomeViewFlag"><img src="./assets/vue.svg" class="logo vue" alt="Vue logo"/></a></div><HomeView v-if="HomeViewFlag"/><Card/>
</template><style scoped lang="scss">
.logo {height: 6em;padding: 1.5em;will-change: filter;transition: filter 300ms;&:hover {filter: drop-shadow(0 0 2em #646cffaa);}.vue {&:hover {filter: drop-shadow(0 0 2em #42b883aa);}}
}
</style>

3.2、局部组件

局部组件

<script setup lang="ts">
let age = ref(22)
const h1click = () => {age.value++
}
</script><template><div><h1 @click="h1click">年龄:{{ age }}</h1></div>
</template>
<style scoped lang="scss">
h1 {color: $theColor;
}
</style>

使用

<script setup lang="ts">import HomeView from "./view/HomeView.vue";let HomeViewFlag = ref(true)
</script><template><div><a @click="()=>{HomeViewFlag=!HomeViewFlag}"><img src="/vite.svg" class="logo" alt="Vite logo"/></a><a @click="()=>HomeViewFlag=!HomeViewFlag"><img src="./assets/vue.svg" class="logo vue" alt="Vue logo"/></a></div><HomeView v-if="HomeViewFlag"/>
</template><style scoped lang="scss">
.logo {height: 6em;padding: 1.5em;will-change: filter;transition: filter 300ms;&:hover {filter: drop-shadow(0 0 2em #646cffaa);}.vue {&:hover {filter: drop-shadow(0 0 2em #42b883aa);}}
}
</style>

3.3、递归组件

组件

<script setup lang="ts">
interface Tree {name: string,checked: boolean,children?: Tree[]
}const props = defineProps<{data: Tree[]
}>()// 自定义名称
defineOptions({name: "myTree"
})
</script><template><div v-for="item in data"><input type="checkbox" :checked="item.checked"/> <span>{{ item.name }}</span><!--<Tree v-if="item?.children?.length" :data="item?.children"/>--><myTree v-if="item?.children?.length" :data="item?.children"/></div>
</template><style scoped lang="scss"></style>

使用

<script setup lang="ts">
let age = ref(22)
const h1click = () => {age.value++
}interface Tree {name: string,checked: boolean,children?: Tree[]
}const data = reactive<Tree[]>([{name: "1",checked: true,children: [{name: "1-1",checked: false,children: [{name: "1-1-1",checked: true},]},{name: "1-2",checked: true},]},{name: "2",checked: false,children: [{name: "2-1",checked: false},{name: "2-2",checked: true},{name: "2-3",checked: true},]},{name: "3",checked: false,children: [{name: "3-1",checked: false},]}
])
</script><template><div><h1 @click="h1click">年龄:{{ age }}</h1></div><div><Tree :data="data"></Tree></div>
</template>
<style scoped lang="scss">
h1 {color: $theColor;
}
</style>

3.4、父子组件传参

1、父传子(defineProps)

父组件

<script setup lang="ts">
let PtoC1 = ref(1)
let PtoC2 = ref({name: 'xumeng03',age: 22
})
</script><template><div>我是父组件<hr><Child :PtoC1="PtoC1" :PtoC2="PtoC2"/></div>
</template><style scoped lang="scss"></style>

子组件

<script setup lang="ts">
// js形式
// const props = defineProps({
//     PtoC1: {
//         type: Number,
//         default: '默认值'
//     },
//     PtoC2: {
//         type: Object,
//         default: {}
//     }
// })// typescript类型约束
const props = defineProps<{PtoC1: number,PtoC2: {name: string,age: number}
}>()// typescript默认值
withDefaults(defineProps<{PtoC1: number,PtoC2: {name: string,age: number}
}>(), {PtoC1: 0, PtoC2: () => ({name: 'name', age: 0})
})
</script><template><div>我是子组件<br><!--来自父组件的消息1: {{ FtoC }}-->来自父组件的消息1: {{ props.PtoC1 }}<br>来自父组件的消息2: {{ props.PtoC2 }}</div>
</template><style scoped lang="scss"></style>

2、子传父(defineEmits)

父组件

<script setup lang="ts">
let Pmessage1 = ref<string>()
let Pmessage2 = reactive<{name: string,age: number
}>({name: 'name',age: 0
})
const getChildMessage1 = (message: string) => {Pmessage1.value = message
}
const getChildMessage2 = (message: {name: string,age: number
}) => {Pmessage2 = message
}
</script><template><div>我是父组件<br>来自父组件的消息1: {{ Pmessage1 }}<br>来自父组件的消息1: {{ Pmessage2 }}<hr><Child @getChildMessage1="getChildMessage1" @getChildMessage2="getChildMessage2"/></div>
</template><style scoped lang="scss"></style>

子组件

<script setup lang="ts">
let message1 = ref("xumeng03")
let message2 = reactive({name: 'xumeng03',age: 22
})
// const emit = defineEmits(['getChildMessage1', 'getChildMessage2'])
const emit = defineEmits<{(e: 'getChildMessage1', message: string): void,(e: 'getChildMessage2', message: {name: string,age: number}): void
}>()
const transValue = () => {emit('getChildMessage1', message1.value)emit('getChildMessage2', message2)
}
</script><template><div @click="transValue">我是子组件</div>
</template><style scoped lang="scss"></style>

3、父组件访问子组件(defineExpose)

父组件

<script setup lang="ts">
import Child from "@/components/Child.vue";const child1 = ref<InstanceType<typeof Child>>()
const childAttributes = () => {console.log(child1.value.username)child1.value.changeName('xumeng03' + Math.ceil(Math.random() * 10))
}
</script><template><div @click="childAttributes">我是父组件<br>子组件属性:{{ child1 }}<hr><Child ref="child1"/></div>
</template><style scoped lang="scss"></style>

子组件

<script setup lang="ts">
let username = ref("child")
const changeName = (newName: string) => {console.log("newName:" + newName)username.value = newName
}defineExpose({username,changeName
})
</script><template><div>我是子组件</div>
</template><style scoped lang="scss"></style>

3.5、动态组件(component)

<script setup lang="ts">
import Card from "@/components/Card.vue";
import Tree from "@/components/Tree.vue";
import {DefineComponent} from "vue";let age = ref(22)
const h1click = () => {age.value++
}interface Tree {name: string,checked: boolean,children?: Tree[]
}const data = reactive<Tree[]>([{name: "1",checked: true,children: [{name: "1-1",checked: false,children: [{name: "1-1-1",checked: true},]},{name: "1-2",checked: true},]},{name: "2",checked: false,children: [{name: "2-1",checked: false},{name: "2-2",checked: true},{name: "2-3",checked: true},]},{name: "3",checked: false,children: [{name: "3-1",checked: false},]}
])
const buttons = [{name: '组件1',component: Card},{name: '组件2',component: Tree},
]
const btnclick = (item: {name: string,component: DefineComponent<{}, {}, any>
}) => {componentDefault.value = item.component
}
// 使用shallowRef节约性能
let componentDefault = shallowRef(Card)
</script><template><div><h1 @click="h1click">年龄:{{ age }}</h1><div><button @click="btnclick(item)" v-for="item in buttons">{{ item.name }}</button></div><component :is="componentDefault" :data="data"></component></div>
</template>
<!--注意style必须加上lang="scss"-->
<style scoped lang="scss">
h1 {color: $theColor;
}
</style>

3.6、插槽(slot)

1、匿名插槽

匿名插槽在一个组件中只能有一个

<script setup lang="ts"></script><template><div><slot><!--插槽默认值--><span>这个插槽好像是空的?</span></slot></div>
</template><style scoped lang="scss"></style>

使用

<script setup lang="ts">let age = ref(22)
const h1click = () => {age.value++
}</script><template><div><h1 @click="h1click">年龄:{{ age }}</h1><Card>测试插槽</Card></div>
</template>
<!--注意style必须加上lang="scss"-->
<style scoped lang="scss">
h1 {color: $theColor;
}
</style>

2、具名插槽

<script setup lang="ts"></script><template><div><div><slot name="title"><!--插槽默认值--><span>这个组件标题好像是空的?</span></slot></div><div><slot name="content"><!--插槽默认值--><span>这个组件内容好像是空的?</span></slot></div><div><slot><!--插槽默认值--><span>这个组件操作项好像是空的?</span></slot></div></div>
</template><style scoped lang="scss"></style>

使用

<script setup lang="ts">let age = ref(22)
const h1click = () => {age.value++
}</script><template><div><h1 @click="h1click">年龄:{{ age }}</h1><Card><template #title>组件标题</template><template v-slot:content>组件标题</template><template v-slot>组件操作项</template></Card></div>
</template>
<!--注意style必须加上lang="scss"-->
<style scoped lang="scss">
h1 {color: $theColor;
}
</style>

3、插槽传参

组件

<script setup lang="ts">
let titleData = ref("slot中的值")
</script><template><div><div><slot name="title" :data="titleData"><!--插槽默认值--><span>这个组件标题好像是空的?</span></slot></div><div><slot name="content"><!--插槽默认值--><span>这个组件内容好像是空的?</span></slot></div><div><slot><!--插槽默认值--><span>这个组件操作项好像是空的?</span></slot></div></div>
</template><style scoped lang="scss"></style>

使用

<script setup lang="ts">let age = ref(22)
const h1click = () => {age.value++
}
</script><template><div><h1 @click="h1click">年龄:{{ age }}</h1><Card><template #title="children">组件标题-{{ children.data }}</template><template v-slot:content>组件标题</template><template v-slot>组件操作项</template></Card></div>
</template>
<!--注意style必须加上lang="scss"-->
<style scoped lang="scss">
h1 {color: $theColor;
}
</style>

4、动态插槽

组件

<script setup lang="ts">
let titleData = ref("slot中的值")
</script><template><div><div><slot name="title" :data="titleData"><!--插槽默认值--><span>这个组件标题好像是空的?</span></slot></div><div><slot name="content" :data="titleData"><!--插槽默认值--><span>这个组件内容好像是空的?</span></slot></div><div><slot :data="titleData"><!--插槽默认值--><span>这个组件操作项好像是空的?</span></slot></div></div>
</template><style scoped lang="scss"></style>

使用

<script setup lang="ts">let age = ref(22)
const h1click = () => {age.value++
}
let position = 'content'
</script><template><div><h1 @click="h1click">年龄:{{ age }}</h1><Card><template #[position]="children">组件-{{ children.data }}</template></Card></div>
</template>
<!--注意style必须加上lang="scss"-->
<style scoped lang="scss">
h1 {color: $theColor;
}
</style>

3.7、异步组件(Suspense)

组件

<script setup lang="ts">
const title = ref('')
const init = () => {return new Promise((resolve, reject) => {setTimeout(() => {title.value = "xumeng03"resolve()}, 2000);})
}
await init()
</script><template>{{ title }}
</template><style scoped lang="scss"></style>

使用

<script setup lang="ts">let age = ref(22)
const h1click = () => {age.value++
}
// 必须异步导入组件
const Async = defineAsyncComponent(() => import('@/components/Async.vue'))
</script><template><div><h1 @click="h1click">年龄:{{ age }}</h1><Suspense><template #default><Async></Async></template><template #fallback>"还没有准备好哦"</template></Suspense></div>
</template><style scoped lang="scss">
h1 {color: $theColor;
}
</style>

3.8、传送组件(Teleport)

组件

<script setup lang="ts"></script><template><div id="teleport">被传送节点</div>
</template><style scoped lang="scss">
#teleport {position: absolute;
}
</style>

使用

<script setup lang="ts">let age = ref(22)
const h1click = () => {age.value++
}
</script><template><div><h1 @click="h1click">年龄:{{ age }}</h1><!--<Modal></Modal>--><!--disabled是否启用传送,to把组件放在哪里--><Teleport :disabled="false" to="body"><Modal></Modal></Teleport></div>
</template><style scoped lang="scss">
h1 {color: $theColor;
}
</style>

3.9、缓存组件(keep-alive)

keep-alive会新增onActivated、onDeactivated生命周期

// 挂载keep-alive内组件
onActivated(() => {console.log('keep-alive组件挂载');
})
// 卸载keep-alive内组件
onDeactivated(() => {console.log('keep-alive组件卸载');
})

使用

<script setup lang="ts">
import Card from "@/components/Card.vue";
import Tree from "@/components/Tree.vue";
import {DefineComponent} from "vue";let age = ref(22)
const h1click = () => {age.value++
}interface Tree {name: string,checked: boolean,children?: Tree[]
}const data = reactive<Tree[]>([{name: "1",checked: true,children: [{name: "1-1",checked: false,children: [{name: "1-1-1",checked: true},]},{name: "1-2",checked: true},]},{name: "2",checked: false,children: [{name: "2-1",checked: false},{name: "2-2",checked: true},{name: "2-3",checked: true},]},{name: "3",checked: false,children: [{name: "3-1",checked: false},]}
])
const buttons = [{name: '组件1',component: Card},{name: '组件2',component: Tree},
]
const btnclick = (item: {name: string,component: DefineComponent<{}, {}, any>
}) => {componentDefault.value = item.component
}
// 使用shallowRef节约性能
let componentDefault = shallowRef(Card)
</script><template><div><h1 @click="h1click">年龄:{{ age }}</h1><div><button @click="btnclick(item)" v-for="item in buttons">{{ item.name }}</button></div><keep-alive :exclude="['Card']"><component :is="componentDefault" :data="data">测试插槽</component></keep-alive></div>
</template>
<!--注意style必须加上lang="scss"-->
<style scoped lang="scss">
h1 {color: $theColor;
}
</style>

3.10、组件过渡(transition)

  • v-if 所触发的切换
  • v-show 所触发的切换
  • <component> 切换的动态组件

1、name指定动画

<script setup lang="ts">let age = ref(22)
const h1click = () => {age.value++
}
let flag = ref(true)
</script><template><div><h1 @click="h1click">年龄:{{ age }}</h1><button @click="()=>flag=!flag">切换</button><transition name="v"><div v-if="flag" id="div">我是一个div</div><!--<div v-show="flag" id="div">--><!--    我是一个div--><!--</div>--></transition></div>
</template>
<!--注意style必须加上lang="scss"-->
<style scoped lang="scss">
h1 {color: $theColor;
}#div {background-color: lightgreen;
}.v-enter-active,.v-leave-active{transition: all 0.5s;
}
.v-enter-from,.v-leave-to{transform: translateY(-20px);opacity: 0;
}
.v-enter-to,.v-leave-from{transition: all 0.5s;
}
</style>

2、class指定动画

<script setup lang="ts">let age = ref(22)
const h1click = () => {age.value++
}
let flag = ref(true)
</script><template><div><h1 @click="h1click">年龄:{{ age }}</h1><button @click="()=>flag=!flag">切换</button><transition:duration="{enter: 50,leave:500}"enter-from-class="v-enter-from"enter-to-class="v-enter-to"enter-active-class="v-enter-active"leave-from-class="v-leave-from"leave-active-class="v-leave-active"leave-to-class="v-leave-to"><div v-if="flag" id="div">我是一个div</div></transition></div>
</template>
<!--注意style必须加上lang="scss"-->
<style scoped lang="scss">
h1 {color: $theColor;
}#div {background-color: lightgreen;
}.v-enter-active, .v-leave-active {transition: all 0.5s;
}.v-enter-from, .v-leave-to {transform: translateY(-20px);opacity: 0;
}.v-enter-to, .v-leave-from {transition: all 0.5s;
}
</style>

3、生命周期

<script setup lang="ts">let age = ref(22)
const h1click = () => {age.value++
}
let flag = ref(true)
const onBeforeEnter = () => {console.log('元素进入前');
}
const onEnter = () => {console.log('元素进入时');
}
const onAfterEnter = () => {console.log('元素进入后');
}
const onEnterCancelled = () => {console.log('动画进入被打断');
}
const onBeforeLeave = () => {console.log('元素离开前');
}
const onLeave = () => {console.log('元素离开时');
}
const onAfterLeave = () => {console.log('元素离开后');
}
const onLeaveCancelled = () => {console.log('动画离开被打断');
}
</script><template><div><h1 @click="h1click">年龄:{{ age }}</h1><button @click="()=>flag=!flag">切换</button><transition:duration="{enter: 50,leave:500}"enter-from-class="v-enter-from"enter-to-class="v-enter-to"enter-active-class="v-enter-active"leave-from-class="v-leave-from"leave-active-class="v-leave-active"leave-to-class="v-leave-to"@before-enter="onBeforeEnter"@enter="onEnter"@after-enter="onAfterEnter"@enter-cancelled="onEnterCancelled"@before-leave="onBeforeLeave"@leave="onLeave"@after-leave="onAfterLeave"@leave-cancelled="onLeaveCancelled"><div v-if="flag" id="div">我是一个div</div></transition></div>
</template>
<!--注意style必须加上lang="scss"-->
<style scoped lang="scss">
h1 {color: $theColor;
}#div {background-color: lightgreen;
}.v-enter-active, .v-leave-active {transition: all 0.5s;
}.v-enter-from, .v-leave-to {transform: translateY(-20px);opacity: 0;
}.v-enter-to, .v-leave-from {transition: all 0.5s;
}
</style>

4、首次进入显示动画

<script setup lang="ts">let age = ref(22)
const h1click = () => {age.value++
}
let flag = ref(true)
const onBeforeEnter = () => {console.log('元素进入前');
}
const onEnter = () => {console.log('元素进入时');
}
const onAfterEnter = () => {console.log('元素进入后');
}
const onEnterCancelled = () => {console.log('动画进入被打断');
}
const onBeforeLeave = () => {console.log('元素离开前');
}
const onLeave = () => {console.log('元素离开时');
}
const onAfterLeave = () => {console.log('元素离开后');
}
const onLeaveCancelled = () => {console.log('动画离开被打断');
}
</script><template><div><h1 @click="h1click">年龄:{{ age }}</h1><button @click="()=>flag=!flag">切换</button><transitionappearenter-from-class="v-enter-from"enter-to-class="v-enter-to"enter-active-class="v-enter-active"leave-from-class="v-leave-from"leave-active-class="v-leave-active"leave-to-class="v-leave-to"@before-enter="onBeforeEnter"@enter="onEnter"@after-enter="onAfterEnter"@enter-cancelled="onEnterCancelled"@before-leave="onBeforeLeave"@leave="onLeave"@after-leave="onAfterLeave"@leave-cancelled="onLeaveCancelled"><div v-if="flag" id="div">我是一个div</div></transition></div>
</template>
<!--注意style必须加上lang="scss"-->
<style scoped lang="scss">
h1 {color: $theColor;
}#div {background-color: lightgreen;
}.v-enter-active, .v-leave-active {transition: all 0.5s;
}.v-enter-from, .v-leave-to {transform: translateY(-20px);opacity: 0;
}.v-enter-to, .v-leave-from {transition: all 0.5s;
}
</style>

5、transition-group

<script setup lang="ts">let age = ref(22)
const h1click = () => {age.value++
}
const arr = reactive([{number: 1},{number: 2}
])
</script><template><div><h1 @click="h1click">年龄:{{ age }}</h1><button @click="arr.push({number: Math.ceil(Math.random() * 10)})">添加</button><button @click="()=>arr.pop()">删除</button><transition-groupappearenter-from-class="v-enter-from"enter-to-class="v-enter-to"enter-active-class="v-enter-active"leave-from-class="v-leave-from"leave-active-class="v-leave-active"leave-to-class="v-leave-to"><div v-for="(item,index) in arr" :key="index" class="div">{{ item.number }}</div></transition-group></div>
</template>
<!--注意style必须加上lang="scss"-->
<style scoped lang="scss">
h1 {color: $theColor;
}.div {background-color: lightgreen;
}.v-enter-active, .v-leave-active {transition: all 0.5s;
}.v-enter-from, .v-leave-to {transform: translateY(-20px);opacity: 0;
}.v-enter-to, .v-leave-from {transition: all 0.5s;
}
</style>

4、生命周期

<script setup lang="ts">
let age = ref(22)
let h1 = ref<HTMLElement>()
// 生命周期(setup模式下无beforeCreate和created)// 挂载前
onBeforeMount(() => {console.log('挂载前', h1.value);
})
// 挂载完成
onMounted(() => {console.log('挂载完成', h1.value);
})// 更新前
onBeforeUpdate(() => {console.log('更新前', h1.value?.innerText);
})
// 更新完成
onUpdated(() => {console.log('更新完成', h1.value?.innerText);
})// 销毁前
onBeforeUnmount(() => {console.log('销毁前');
})
// 销毁后
onBeforeUnmount(() => {console.log('销毁后');
})
const h1click = () => {age.value++
}
</script><template><div><h1 @click="h1click" ref="h1">{{ age }}</h1></div>
</template><style scoped></style>

5、样式

5.1、全局样式/变量

@/style/variables.scss

$theColor: lightblue;h1 {font-size: 100px;
}

vite.config.ts

import {defineConfig} from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'
// 自动导入vue中ref、reactive、watch等
import AutoImport from "unplugin-auto-import/vite"
// 自动导入ui组件
import Components from 'unplugin-vue-components/vite';// https://vitejs.dev/config/
export default defineConfig({define: {// 关闭Vue2 Options Api__VUE_OPTIONS_API__: false},plugins: [vue(),AutoImport({// 在组件中不用再导入ref、reactive、watch等imports: ['vue', 'vue-router'],// 声明文件存放的位置,会自动生成,无需自己维护dts: "src/auto-import.d.ts",}),Components({// 引入组件的存放的位置,包括自定义组件dts: "src/components.d.ts",}),],resolve: {// 配置路径别名alias: {"@": path.resolve(__dirname, "./src"),},},css: {preprocessorOptions: {scss: {additionalData: `@import "@/style/variables.scss";`}}},
})

使用

<script setup lang="ts">
let age = ref(22)
const h1click = () => {age.value++
}
</script><template><div><h1 @click="h1click">年龄:{{ age }}</h1></div>
</template>
<!--注意style必须加上lang="scss"-->
<style scoped lang="scss">
h1 {color: $theColor;
}
</style>

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

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

相关文章

2023-将jar包上传至阿里云maven私有仓库(云效制品仓库)

一、背景介绍 如果要将平时积累的代码工具jar包&#xff0c;上传至云端&#xff0c;方便团队大家一起使用&#xff0c;一般的方式就是上传到Maven中心仓库&#xff08;但是这种方式步骤多&#xff0c;麻烦&#xff0c;而且上传之后审核时间比较长&#xff0c;还不太容易通过&a…

Python语法(二、内置函数)

数学计算库 Python ​math ​模块提供了许多对浮点数的数学运算函数。 Python ​cmath ​模块包含了一些用于复数运算的函数。 import math 内置函数 关键字 自定义函数 Python函数的定义。定义函数需要用def 关键字实现&#xff0c;具体的语法格式如下&#xff1a; def 函…

CAN学习笔记3:STM32 CAN控制器介绍

STM32 CAN控制器 1 概述 STM32 CAN控制器&#xff08;bxCAN&#xff09;&#xff0c;支持CAN 2.0A 和 CAN 2.0B Active版本协议。CAN 2.0A 只能处理标准数据帧且扩展帧的内容会识别错误&#xff0c;而CAN 2.0B Active 可以处理标准数据帧和扩展数据帧。 2 bxCAN 特性 波特率…

部署问题集合(十八)Windows环境下使用两个Tomcat

下载Tomcat Tomcat镜像下载地址&#xff1a;https://mirrors.cnnic.cn/apache/tomcat/进入如下地址&#xff1a;zip的是压缩版&#xff0c;exe是安装版 修改第二个Tomcat配置文件 第一步&#xff1a;编辑conf/server.xml文件&#xff0c;修改三个端口&#xff0c;有些版本改…

3d激光slam建图与定位(1)_基于ndt算法定位

一.代码实现流程 二.ndt算法原理 一.该算法定位有三个进程文件 1.map_loader.cpp用于点云地图的读取&#xff0c;从文件中读取点云后对这个点云地图进行旋转平移后发布点云地图到ros #include "map_loader.h"MapLoader::MapLoader(ros::NodeHandle &nh){std::st…

【嵌入式Linux项目】基于Linux的全志H616开发板智能家居项目(语音控制、人脸识别、安卓APP和PC端QT客户端远程操控)有视频功能展示

目录 一、功能需求 二、开发环境 1、硬件&#xff1a; 2、软件&#xff1a; 3、引脚分配&#xff1a; 三、关键点 1、设计模式之工厂模式 2、wiringPi库下的相关硬件操作函数调用 3、语音模块的串口通信 4、线程 5、摄像头的实时监控和拍照功能 6、人脸识别 四、编…

Spring Boot实践四 --集中式缓存Redis

随着时间的积累&#xff0c;应用的使用用户不断增加&#xff0c;数据规模也越来越大&#xff0c;往往数据库查询操作会成为影响用户使用体验的瓶颈&#xff0c;此时使用缓存往往是解决这一问题非常好的手段之一。Spring 3开始提供了强大的基于注解的缓存支持&#xff0c;可以通…

ios私钥证书的创建方法

ios私钥证书是苹果公司为ios开发者打包app&#xff0c;推出的一种数字证书&#xff0c;只有同一个苹果开发者账号生成的ios私钥证书打的包&#xff0c;才能上架同一个开发者账号的app store。因此不要指望别人给你共享私钥证书和描述文件&#xff0c;因为别人的证书和描述文件打…

Nginx下载、安装与使用

Nginx下载 简介&#xff1a; Nginx是一个高性能的HTTP和反向代理web服务器&#xff0c;同时也提供了IMAP/POP3/SMTP服务&#xff08;邮件服务&#xff09;。 官网下载地址&#xff1a; https://nginx.org/en/download.html 国内镜像地址&#xff1a; https://mirrors.huawe…

基于RASC的keil电子时钟制作(瑞萨RA)(6)----定时器驱动数码管

基于RASC的keil电子时钟制作6_定时器驱动数码管 概述硬件准备视频教程选择定时器定时器做计数器配置定时器回调函数timer_smg.ctimer_smg.h演示效果主程序 概述 要想让每个数码管显示不同的数字&#xff0c;但是数码管必须依次地被持续驱动&#xff0c;数码管之间的刷新速度应…

【图论】Prim算法

一.介绍 Prim算法是一种用于解决最小生成树问题的贪心算法。最小生成树问题是指在一个连通无向图中找到一个生成树&#xff0c;使得树中所有边的权重之和最小。 Prim算法的基本思想是从一个起始顶点开始&#xff0c;逐步扩展生成树&#xff0c;直到覆盖所有顶点。具体步骤如下…

SpringBoot面试题及答案整理

1、什么是 Spring Boot&#xff1f; 多年来&#xff0c;随着新功能的增加&#xff0c;spring 变得越来越复杂。访问spring官网页面&#xff0c;我们就会看到可以在我们的应用程序中使用的所有 Spring 项目的不同功能。如果必须启动一个新的 Spring 项目&#xff0c;我们必须添…

动脑学院Jetpack Compose学习笔记

最近b站学习了一下Compose相关内容&#xff0c;整理了相关笔记&#xff0c;仅供大家参考。 资源链接如下&#xff0c;象征性收取1个积分 https://download.csdn.net/download/juliantem/88125198

SOC FPGA介绍及开发设计流程

目录 一、SoC FPGA简介 二、SoC FPGA开发流程 2.1 硬件开发 2.2 软件开发 一、SoC FPGA简介 SOC FPGA是在FPGA架构中集成了基于ARM的硬核处理器系统(HPS)&#xff0c;包括处理器、外设和存储器控制器。相较于传统的仅有ARM处理器或 FPGA 的嵌入式芯片&#xff0c;SOC FPGA既…

CSS Flex 笔记

1. Flexbox 术语 Flex 容器可以是<div> 等&#xff0c;对其设置属性&#xff1a;display: flex, justify-content 是沿主轴方向调整元素&#xff0c;align-items 是沿交叉轴对齐元素。 2. Cheatsheet 2.1 设置 Flex 容器&#xff0c;加粗的属性为默认值 2.1.1 align-it…

1,复杂度和简单排序算法【p2-p3】

复杂度和简单排序算法 1&#xff0c;时间复杂度1.1选择排序1.2冒泡排序1.3异或运算1.3.1性质&#xff1a;1.3.2案例例1例2 1.4插入排序1.5二分法1.5.1在一个有序数组中&#xff0c;找某个数是否存在1.5.2在一个有序数组中&#xff0c;找>某个数最左侧的位置1.5.3局部最小值问…

Individual household electric power consumption个人家庭用电量数据挖掘与时序预测建模

今天接到一个任务就是需要基于给定的数据集来进行数据挖掘分析相关的计算&#xff0c;并完成对未来时段内数据的预测建模&#xff0c;话不多说直接看内容。 官方数据详情介绍在这里&#xff0c;如下所示&#xff1a; 数据集中一共包含9个不同的字段&#xff0c;详情如下&#…

手把手一起实现Visual Studio 2022本地工程提交(和克隆)Gitee

1、VS2022本地工程提交Gitee 登录Gitee&#xff0c;创建空仓库&#xff0c;如图&#xff1a; 新建仓库&#xff1a; 打开Visual Studio 2022创建的工程&#xff0c;点击创建Git存储库&#xff1a; 复制Gitee仓库URL&#xff1a; 将URL填入&#xff0c;点击创建并推送&#xff…

Windows 10 安装 PostgreSQL 12.x 报错 ‘psql‘ 不是内部或外部命令 由于找不到文件libintl-9.dll等问题

目录 序言一、问题总结问题 1 psql 不是内部或外部命令&#xff0c;也不是可运行的程序或批处理文件。问题 2 “由于找不到文件libintl-9.dll&#xff0c;无法继续执行代码&#xff0c;重新安装程序可能会解决此问题。“1、卸载2、安装3、安装 Stack Builder &#xff08;这个可…

LeetCode.189(轮转数组)

对于轮转数组这个题&#xff0c;文章一共提供三种思路&#xff0c;对于每种思路均提供其对应代码的时间、空间复杂度。 目录 1. 创建变量来保存最后一个数&#xff0c;并将其余数组向前挪动一位 &#xff1a; 1.1 原理解析&#xff1a; 1.2 代码实现&#xff1a; 2.创建一个…