知道:vue3的现状以及它特点
大致内容:
具体落地:
2020 年 9 月 18 日发布,许多开发者还在观望。2022 年 2 月 7 日称为默认版本,意味着vue3是现在也是未来。
组件(插件)名称 | 官方地址 | 简介 |
---|---|---|
ant-design-vue | https://antdv.com/docs/vue/introduce-cn/ | ant-design-vue 是 Ant Design 的 Vue 实现,组件的风格与 Ant Design 保持同步 |
element-plus | https://element-plus.gitee.io/#/zh-CN | Element Plus,一套为开发者、设计师和产品经理准备的基于 Vue 3.0 的桌面端组件库 |
vant | https://vant-contrib.gitee.io/vant/v3/#/zh-CN | 有赞前端团队开源的移动端组件库,于 2016 年开源,已持续维护 4 年时间 |
Naive UI | https://www.naiveui.com/zh-CN/ | 一个 Vue 3 组件库比较完整,主题可调,使用 TypeScript,不算太慢,有点意思 |
VueUse | https://vueuse.org/ | 基于composition组合api的常用集合,小兔鲜儿项目会部分使用 |
相关文档
了解框架优点特点
总结:
掌握:使用vue-cli完成项目创建知道初始化代码含义
大致步骤:
具体落地:
// 1. 导入一个创建App的函数
import { createApp } from 'vue'
// 2. 导入根组件
import App from './App.vue'
// 3. 根据根组件创建vue应用实例,挂载到html的app元素上
createApp(App).mount('#app')
其他发现:
总结:
知道:什么是选项API什么是组合API,对比它们之间的代码组织特点
大致内容:
具体落地:
总结:
体验:组合API实现couter和显示隐藏
大致步骤:
落地代码:
<template>
<button @click="toggle">显示隐藏图片</button>
<img v-show="show" alt="Vue logo" src="./assets/logo.png" />
<hr />
计数器:{{ count }} <button @click="increment">累加</button>
</template>
<script>
export default {
name: "App",
data() {
return {
show: true,
count: 0,
};
},
methods: {
toggle() {
this.show = !this.show;
},
increment() {
this.count++;
},
},
};
</script>
<template>
<button @click="toggle">显示隐藏图片</button>
<img v-show="show" alt="Vue logo" src="./assets/logo.png" />
<hr />
计数器:{{ count }} <button @click="increment">累加</button>
</template>
<script>
import { ref } from 'vue';
export default {
name: "App",
setup () {
// 显示隐藏
const show = ref(true)
const toggle = () => {
show.value = !show.value
}
// 计数器
const count = ref(0)
const increment = () => {
count.value ++
}
return { show, toggle, count, increment }
}
};
</script>
<template>
<button @click="toggle">显示隐藏图片</button>
<img v-show="show" alt="Vue logo" src="./assets/logo.png" />
<hr />
计数器:{{ count }} <button @click="increment">累加</button>
<hr />
计数器:{{ count1 }} <button @click="increment1">累加</button>
</template>
<script>
import { ref } from "vue";
// 逻辑抽离
const useCounter = () => {
const count = ref(0);
const increment = () => {
count.value++;
};
return { count, increment };
};
export default {
name: "App",
setup() {
// 显示隐藏
const show = ref(true);
const toggle = () => {
show.value = !show.value;
};
// 逻辑复用
const { count, increment } = useCounter();
const { count: count1, increment: increment1 } = useCounter();
return { show, toggle, count, increment, count1, increment1 };
},
};
</script>
总结:
掌握:setup使用和它的执行时机。
大致内容:
具体落地:
<template>
<div>根组件</div>
</template>
<script>
export default {
name: "App",
setup() {
// 组合API入口函数
console.log("setup执行了");
console.log(this);
},
beforeCreate() {
console.log("beforeCreate执行了");
console.log(this);
},
};
</script>
总结:
掌握:使用reactive函数把普通对象转换成响应式数据
使用步骤:
vue
中导出 reactive
函数setup
函数中,使用 reactive
函数,传入一个普通对象,返回一个响应式数据对象setup
函数返回一个对象,包含该响应式对象即可,模板中可使用落地代码:
<template>
<div>
<p>姓名:{{state.name}}</p>
<p>年龄:{{state.age}} <button @click="state.age++">一年又一年</button></p>
</div>
</template>
<script>
// 1. 导入函数
import { reactive } from "vue";
export default {
name: "App",
setup() {
// 2. 创建响应式数据对象
const state = reactive({ name: 'tom', age: 18 })
// 3. 返回数据
return { state }
}
};
</script>
总结:
reactive
传入普通对象可以转换成响应式对象掌握:使用ref函数创建响应式数据
使用步骤:
vue
中导出 ref
函数setup
函数中,使用 ref
函数,传入一个普通数据(简单or复杂),返回一个响应式数据setup
函数返回一个对象,包含该响应式数据即可ref
创建的数据,js
中需要 .value
,template
中可省略落地代码:
<template>
<div>
<p>
计数器:{{ count }}
<button @click="count++">累加1</button>
<!-- template中使用可省略.value -->
<button @click="increment">累加10</button>
</p>
</div>
</template>
<script>
// 1. 导入函数
import { ref } from "vue";
export default {
name: "App",
setup() {
// 2. 创建响应式数据对象
const count = ref(0);
const increment = () => {
// js中使用需要.value
count.value += 10;
};
// 3. 返回数据
return { count, increment };
},
};
</script>
总结:
ref
可以把简单数据或者复杂数据转换成响应式数据,注意使用加上 .value
,不过模板可省略。ref
还是 reactive
呢?知道:在定义响应式数据的时候如何选择reactive和ref
开始分析:
reactive
可以转换对象成为响应式数据对象,但是不支持简单数据类型。ref
可以转换简单数据类型为响应式数据对象,也支持复杂数据类型,但是操作的时候需要 .value
。推荐用法:
reactive
转成响应式数据,其他一概使用 ref
。这样就没有 心智负担 。参考代码:
// 1. 明确表单对象有两个字段
const form = reactive({
username: '',
password: ''
})
// 2. 后台返回的数据对象
const data = ref(null)
const res = await axios.get('/user/100')
data.value = res.data
总结:
reactive
其他都使用 ref
函数掌握:在使用reactive创建的响应式数据被展开或解构的时候使用toRefs保持响应式
大致步骤:
reactive
创建响应式数据,踩坑toRefs
处理响应式数据,爬坑toRefs
函数的作用,与使用场景落地代码:
<template>
<div>
<p>姓名:{{ user.name }}</p>
<p>年龄:{{ user.age }} <button @click="user.age++">一年又一年</button></p>
</div>
</template>
<script>
import { reactive } from "vue";
export default {
name: "App",
setup() {
const user = reactive({ name: "tom", age: 18 });
return { user };
},
};
</script>
reactive
创建响应式数据,踩坑<template>
<div>
+ <p>姓名:{{ name }}</p>
+ <!-- 响应式丢失 -->
+ <p>年龄:{{ age }} <button @click="age++">一年又一年</button></p>
</div>
</template>
<script>
import { reactive } from "vue";
export default {
name: "App",
setup() {
const user = reactive({ name: "tom", age: 18 });
+ return { ...user };
},
};
</script>
toRefs
处理响应式数据,爬坑+import { reactive, toRefs } from "vue";
export default {
name: "App",
setup() {
const user = reactive({ name: "tom", age: 18 });
+ // 展开前使用 toRefs 处理
+ return { ...toRefs(user) };
},
};
toRefs
函数的作用,与使用场景
总结:
reactive
的响应式数据对象使用 toRefs
保持响应式掌握:使用 computed 函数定义计算属性
大致步骤:
vue
中导出 computed
函数setup
函数中,使用 computed
函数,传入一个函数,函数返回计算好的数据setup
函数返回一个对象,包含该计算属性数据即可,然后模板内使用落地代码:
<template>
<div>
<p>分数:{{ scoreList }}</p>
<p>优秀:{{ betterList }}</p>
</div>
</template>
<script>
import { ref, computed } from "vue";
export default {
name: "App",
setup() {
const scoreList = ref([80, 100, 90, 70, 60]);
// 计算属性
const betterList = computed(() =>
scoreList.value.filter((item) => item >= 90)
);
// 改变数据,计算属性改变
setTimeout(() => {
scoreList.value.push(92, 66);
}, 3000);
return {
scoreList,
betterList,
};
},
};
</script>
总结:
computed
定义计算属性,场景:当需要依赖一个数据得到新的数据使用计算属性掌握:使用watch函数监听数据的变化
大致内容:
watch
监听一个响应式数据watch
监听多个响应式数据watch
监听响应式对象数据中的一个属性(简单)watch
监听响应式对象数据中的一个属性(复杂),配置深度监听watch
监听,配置默认执行落地代码:
watch
监听一个响应式数据<template>
<p>计数器:{{ count }}</p>
</template>
<script>
import { ref, watch } from "vue";
export default {
name: "App",
setup() {
const count = ref(0);
// 1. 监听一个响应式数据
// watch(数据, 改变后回调函数)
watch(count, () => {
console.log("count改变了");
});
// 2s改变数据
setTimeout(() => {
count.value++;
}, 2000);
return { count };
},
};
</script>
watch
监听多个响应式数据<template>
<p>计数器:{{ count }}</p>
<p>
姓名:{{ user.name }} 性别:{{ user.info.gender }} 年龄:{{ user.info.age }}
</p>
</template>
<script>
import { reactive, ref, watch } from "vue";
export default {
name: "App",
setup() {
const count = ref(0);
const user = reactive({
name: "tom",
info: {
gender: "男",
age: 18,
},
});
// 2. 监听多个响应式数据
// watch([数据1, 数据2, ...], 改变后回调函数)
watch([count, user], () => {
console.log("数据改变了");
});
// 2s改变数据
setTimeout(() => {
count.value++;
}, 2000);
// 4s改变数据
setTimeout(() => {
user.info.age++;
}, 4000);
return { count, user };
},
};
</script>
watch
监听响应式对象数据中的一个属性(简单)<template>
<p>
姓名:{{ user.name }} 性别:{{ user.info.gender }} 年龄:{{ user.info.age }}
</p>
</template>
<script>
import { reactive, watch } from "vue";
export default {
name: "App",
setup() {
const user = reactive({
name: "tom",
info: {
gender: "男",
age: 18,
},
});
// 3. 监听响应式对象数据的一个数据,简单类型
// watch(()=>数据, 改变后回调函数)
watch(()=>user.name, () => {
console.log("数据改变了");
});
// 2s改变数据
setTimeout(() => {
user.name = 'jack';
}, 2000);
// 4s改变数据
setTimeout(() => {
user.info.age = 60;
}, 4000);
return { user };
},
};
</script>
watch
监听响应式对象数据中的一个属性(复杂),配置深度监听<template>
<p>
姓名:{{ user.name }} 性别:{{ user.info.gender }} 年龄:{{ user.info.age }}
</p>
</template>
<script>
import { reactive, watch } from "vue";
export default {
name: "App",
setup() {
const user = reactive({
name: "tom",
info: {
gender: "男",
age: 18,
},
});
// 4. 监听响应式对象数据的一个数据,复杂类型
// watch(()=>数据, 改变后回调函数, {deep: true})
watch(
() => user.info,
() => {
console.log("数据改变了");
},
{
// 开启深度监听
deep: true,
}
);
// 2s改变数据
setTimeout(() => {
user.info.age = 60;
}, 2000);
return { user };
},
};
</script>
watch
监听,配置默认执行 {
// 开启深度监听
deep: true,
+ // 默认执行一次
+ immediate: true
}
总结:
watch('需要监听的数据',数据改变执行函数,配置对象)
来进行数据的侦听deep
深度监听 immediate
默认执行掌握:vue3的常用生命周期函数
使用步骤:
on打头
的生命周期钩子函数具体内容:
选项式API下的生命周期函数使用 | 组合式API下的生命周期函数使用 |
---|---|
beforeCreate | 不需要(直接写到setup函数中) |
created | 不需要(直接写到setup函数中) |
beforeMount | onBeforeMount |
mounted | onMounted |
beforeUpdate | onBeforeUpdate |
updated | onUpdated |
beforeDestroyed | onBeforeUnmount |
destroyed | onUnmounted |
activated | onActivated |
deactivated | onDeactivated |
<template>
<div>生命周期函数</div>
</template>
<script>
import { onMounted } from "vue";
export default {
name: "App",
setup() {
// 生命周期函数:组件渲染完毕
onMounted(()=>{
console.log('onMounted触发了')
})
onMounted(()=>{
console.log('onMounted也触发了')
})
},
};
</script>
总结:
onMounted
组件渲染完毕:发请求,操作dom,初始化图表...掌握:在组合API中父子通讯的过程
知识梳理:
具体代码:
父组件
<template>
<div class="app">
父组件:{{ money }}
<hr />
<SonCom :money="money" />
</div>
</template>
<script>
import SonCom from "./SonCom.vue";
export default {
name: "App",
components: { SonCom },
setup () {
const money = ref(10000)
return { money }
}
};
</script>
子组件
<template>
<div class="son">子组件:{{ money }}</div>
</template>
<script>
export default {
name: "SonCom",
props: {
money: {
type: Number,
},
},
setup(props) {
console.log("数据money:", props.money);
},
};
</script>
子组件
<template>
<div class="son">
子组件:{{ money }} <button @click="changeMoney">买手机</button>
</div>
</template>
<script>
export default {
name: "SonCom",
props: {
money: {
type: Number,
},
},
// vue3规范,自定义事件需要在这声明
emits: ["change-money"],
setup(props, { emit }) {
console.log("数据money:", props.money);
// 通过emit触发自定义事件
const changeMoney = () => {
emit("change-money", props.money - 3999);
};
return { changeMoney };
},
};
</script>
父组件
<template>
<div class="app">
父组件:{{ money }}
<hr />
<SonCom :money="money" @change-money="money = $event" />
</div>
</template>
<script>
import SonCom from "./SonCom.vue";
export default {
name: "App",
components: { SonCom },
setup () {
const money = ref(10000)
return { money }
}
};
</script>
总结:
第一个参数就是props
第二个参数解构出emit函数
,emits选项需要声明自定义事件名称掌握:通过 provide 和 inject 函数实现跨级组件通讯
大致内容:
使用
祖先组件的数据,祖传后修改
祖先组件的数据,后传祖具体落地:
provide
和 inject
从 vue
中导入provide('数据名称', 响应式数据)
提供数据的祖先组件使用const data = inject('数据名称')
注入数据的后代组件使用App.vue
<template>
<div class="app">
根组件:{{ money }}
<hr />
<ParentCom />
</div>
</template>
<script>
import { ref, provide } from 'vue';
import ParentCom from "./ParentCom.vue";
export default {
name: "App",
components: { ParentCom },
setup () {
const money = ref(10000)
// 提供数据给后代
provide('money', money)
return { money }
}
};
</script>
ParentCom.vue
<template>
<div class="parent-com" style="padding-left:50px">
父组件:
<hr />
<ChildCom />
</div>
</template>
<script>
import ChildCom from './ChildCom.vue'
export default {
name: 'ParentCom',
components: { ChildCom }
}
</script>
ChildCom.vue
<template>
<div class="child-com" style="padding-left:50px">
子组件:{{money}}
</div>
</template>
<script>
import { inject } from 'vue'
export default {
name: 'ChildCom',
setup () {
// 注入祖先组件提供的数据
const money = inject('money')
return { money }
}
}
</script>
provide('数据名称', 修改函数)
提供函数的祖先组件使用const changeMoney = inject('数据名称')
注入函数的后代组件使用App.vue
<template>
<div class="app">
根组件:{{ money }}
<hr />
<ParentCom />
</div>
</template>
<script>
import { ref, provide } from 'vue';
import ParentCom from "./ParentCom.vue";
export default {
name: "App",
components: { ParentCom },
setup () {
const money = ref(10000)
// 提供数据给后代
provide('money', money)
+ // 提供函数给后代
+ provide('changeMoney', newMoney => {
+ money.value = newMoney
+ })
return { money }
}
};
</script>
ChildCom.vue
<template>
<div class="child-com" style="padding-left: 50px">
子组件:{{ money }}
+ <button @click="changeMoney(money - 3999)">买手机</button>
</div>
</template>
<script>
import { inject } from "vue";
export default {
name: "ChildCom",
setup() {
// 注入祖先组件提供的数据
const money = inject("money");
+ // 注入祖先组件提供的函数
+ const changeMoney = inject("changeMoney");
+ return { money , changeMoney};
},
};
</script>
总结:
provide
提供数据,使用 inject
注入数据。
掌握:使用 ref 属性获取DOM元素或者组件实例
大致内容:
落地代码:
<template>
<div class="app">
<!-- 2. 使用ref属性绑定响应式数据 -->
<h1 ref="refH">App组件</h1>
</div>
</template>
<script>
import { ref, onMounted } from 'vue';
export default {
name: "App",
setup () {
// 1. 声明响应式数据并返回给模板使用
const refH = ref(null)
// 3. 组件渲染后查看dom
onMounted(()=>{
console.log(refH.value)
})
return { refH }
}
};
</script>
App.vue
<template>
<div class="app">
App组件
<!-- 2. 使用ref属性绑定响应式 -->
<ChildCom ref="refCom" />
</div>
</template>
<script>
import { ref, onMounted } from 'vue';
import ChildCom from "./ChildCom.vue";
export default {
name: "App",
components: { ChildCom },
setup () {
// 1. 声明响应式数据并返回给模板使用
const refCom = ref(null)
// 3. 组件渲染后查看组件实例,可以调用组件函数
onMounted(()=>{
console.log(refCom.value)
refCom.value.show()
})
return { refCom }
}
};
</script>
ChildCom.vue
<template>
<div class="child-com">
子组件
</div>
</template>
<script>
export default {
name: 'ChildCom',
setup () {
const show = () => {
console.log('组件内函数执行了')
}
return { show }
}
}
</script>
总结:
了解:一些不兼容vue2的一些改变
参考文档:非兼容的变更
不再支持:
filter
:visible.sync="dialogFormVisible"
怎么替代:
总结:
掌握:axios 和 组合API 配合开发
克隆代码 git@gitee.com:zhoushugang/vue3-case.git
模板代码分析
import { createApp } from 'vue'
import App from './App.vue'
+// element-plus 支持vue3的ui组件库,使用和element-ui一致
+import ElementUI from 'element-plus'
+import 'element-plus/dist/index.css'
+// use(ElementUI) 使用组件库
+createApp(App).use(ElementUI).mount('#app')
<template>
<div class="app">
<el-table :data="list">
<el-table-column label="ID" prop="id"></el-table-column>
<el-table-column label="姓名" prop="name" width="150"></el-table-column>
<el-table-column label="籍贯" prop="place"></el-table-column>
<el-table-column label="操作" width="100">
<template v-slot="{ row }">
<el-button type="text" @click="delRow(row.id)">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
import { onMounted, ref } from "vue";
import axios from 'axios'
export default {
name: "App",
setup() {
// 获取列表数据
const list = ref([])
const geList = async () => {
const res = await axios.get('/list')
list.value = res.data
}
onMounted(() => {
geList()
})
// 删除数据
const delRow = async (id) => {
await axios.delete(`/del?id=${id}`)
geList()
}
return { list, delRow }
}
};
</script>
<style>
.app {
width: 980px;
margin: 100px auto 0;
}
</style>
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。