nextTick
js事件循环机制
所有的同步任务都是在主进程执行的形成一个执行栈,主线程之外,还存在一个"任务队列",异步任务执行队列中先执行宏任务,然后清空当次宏任务中的所有微任务,然后进行下一个tick如此形成循环。
nextTick
就是创建一个异步任务,那么它自然要等到同步任务执行完成后才执行。
案例:
写一个聊天框要求在每次发送完新的信息之后,导航条滑到最低端
TypeScript
<template>
<div ref="box" class="wraps">
<div>
<div class="item" v-for="item in chatList">
<div>{{ item.name }}:</div>
<div>{{ item.message }}</div>
</div>
</div>
</div>
<div class="ipt">
<div>
<textarea v-model="ipt" type="text" />
</div>
<div>
<button @click="send">send</button>
</div>
</div>
<HelloWorld></HelloWorld>
</template>
<script setup lang='ts'>
import { reactive,ref,nextTick } from 'vue'
let chatList = reactive([
{ name: '张三', message: "xxxxxxxxx" },
])
let box = ref<HTMLDivElement>()
let ipt = ref('')
//Vue 更新dom是异步的 数据更新是同步
//我们本次执行的代码是同步代码
//当我们操作dom 的时候发现数据读取的是上次的 就需要使用nextIick
const send = async () => {
chatList.push({
name:"李四",
message:ipt.value
})
//1.回调函数模式
// nextTick(() => {
// box.value!.scrollTop = 99999999
// })
//2.async await 写法 await以下全部为异步代码
await nextTick()
box.value!.scrollTop = 99999999
}
</script>
<style scoped>
.wraps {
margin: 10px auto;
width: 500px;
height: 400px;
overflow: auto;
overflow-x: hidden;
background: #fff;
border: 1px solid #ccc;
}
.wraps .item {
width: 100%;
height: 50px;
background: #ccc;
display: flex;
align-items: center;
padding: 0 10px;
border-bottom: 1px solid #fff;
}
.ipt {
margin: 10px auto;
width: 500px;
height: 40px;
background: #fff;
border: 1px solid #ccc;
}
.ipt textarea {
width: 100%;
height: 100%;
border: none;
outline: none;
}
.ipt button {
width: 100px;
margin: 10px 0;
float: right;
}
</style>
函数式编程
主要使用h函数去写模板,为什么要使用h函数,因为h函数会直接调用createVNode函数,生成虚拟dom性能上面会有所提升
h函数接受三个参数
- type 元素的类型
- propsOrChildren 数据对象, 这里主要表示(props, attrs, dom props, class 和 style)
- children 子节点
案例:
定义一个按钮
TypeScript
<script setup lang='ts'>
import { ref,h } from 'vue'
const fs = ref("16px")
const tableRef = ref([
{ name: '张三', age: 18, gender: '男' },
{ name: '李四', age: 20, gender: '女' },
{ name: '王五', age: 22, gender: '男' },
{ name: '赵六', age: 24, gender: '女' },
])
type Props = {
text: string
}
const Btn = (props:Props,ctx:any) => {
return h("button",{
style:{
width:"100px",
height:"30px",
fontSize:fs.value,
},
onClick:()=>{
console.log("按钮被点击了")
console.log(props.text)
}
},ctx.slots.default())
}
</script>
<template>
<div class="btn">
<button @click="fs = '15px'">小</button>
<button @click="fs = '20px'">中</button>
<button @click="fs = '22px'">大</button>
</div>
<table border="1">
<thead>
<tr>
<th>姓名</th>
<th>年龄</th>
<th>性别</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr v-for="item in tableRef" :key="item.name">
<td>{{ item.name }}</td>
<td>{{ item.age }}</td>
<td>{{ item.gender }}</td>
<td>
<Btn text="这是要被传入props的">编辑</Btn>
<Btn>删除</Btn>
</td>
</tr>
</tbody>
</table>
</template>
<style scoped>
.btn {
width: 50%;
margin: 0 auto;
}
.btn button {
margin: 0 10px;
padding: 5px 10px;
font-size: 16px;
border: 1px solid #ccc;
border-radius: 5px;
cursor: pointer;
}
table {
width: 50%;
margin: 20px auto;
border-collapse: collapse;
font-size: v-bind(fs);
text-align: center;
}
</style>
编译宏
Vue 3.3新增了一些语法糖和宏,包括泛型组件、defineSlots、defineEmits、defineOptions
defineProps
父子组件传参
案例:
父组件
<script setup lang='ts'>
import { ref } from 'vue'
import B from './components/B.vue'
const text = ref('hello')
</script>
<template>
<B :text="text"></B>
</template>
<style scoped>
</style>
子组件
<script setup lang="ts">
const props = defineProps<{
text: string
}>()
console.log(props.text)
</script>
<template>
<h1>{{text}}</h1>
</template>
<style scoped>
</style>
vue3.3 新增可以给defineProps增加一个泛型
<script setup generic="T" lang="ts">
const props = defineProps<{
text: T[]
}>()
console.log(props.text)
</script>
<template>
<h1>{{text}}</h1>
</template>
<style scoped>
</style>
这样的话,text的类型就更加的灵活
defineEmits
父组件
TypeScript
<script setup lang='ts'>
import { ref } from 'vue'
import B from './components/B.vue'
const text = ref([1, 2, 3])
function handleEmit(data: any) {
console.log(data)
}
</script>
<template>
<B :text="text" @change="handleEmit"></B>
</template>
<style scoped>
</style>
子组件常规方法派发事件
TypeScript
<script setup generic="T" lang="ts">
import {onMounted} from "vue";
const props = defineProps<{
text: T[]
}>()
const emit = defineEmits<{
(e: 'change', value: string): void
}>()
onMounted(() => {
emit('change',"我已经传值")
})
console.log(props.text)
</script>
<template>
<h1>{{text}}</h1>
</template>
<style scoped>
</style>
Vue3.3
新写法更简短
TypeScript
<script setup generic="T" lang="ts">
import {onMounted} from "vue";
const props = defineProps<{
text: T[]
}>()
const emit = defineEmits<{
change: [string]
}>()
onMounted(() => {
emit('change',"我已经传值")
})
console.log(props.text)
</script>
<template>
<h1>{{text}}</h1>
</template>
<style scoped>
</style>
环境变量
环境变量:他的主要作用就是让开发者区分不同的运行环境,来实现 兼容开发和生产
例如 npm run dev 就是开发环境 npm run build 就是生产环境等等
Vite 在一个特殊的 import.meta.env
对象上暴露环境变量。这里有一些在所有情况下都可以使用的内建变量
- BASE_URL: "/"
- DEV: true
- MODE: "development"
- PROD: false
- SSR: false
注意:环境变量不能通过变量的形式添加或者修改即: import.meta.env[mode] = xxx
因为这些环境变量在打包的时候是通过硬编码通过Json.stringify的方式注入到浏览器的
配置额外的环境变量
在开发环境中:
- 在更目录下创建文件.env.development
- 修改启动命令
在 package json 配置 --mode env文件名称
这样就配置完成,可以在env上看到了
在生产环境中
创建 .env.production 在执行npm run build 的时候他会自己加载这个文件
在文件中写入配置的变量即可