前言
由于hexo不单独支持vue的语法高亮,因此部分vue的高亮使用的是html。
什么是Vite?
vite是一个现在化的前端开发构建工具,能够帮助开发者更加便捷管理安装的npm包,更快的启动和更新修改后的前端页面,是Vue官方主推的构建工具。
Vite | 下一代的前端工具链 (vitejs.dev)
创建一个Vite项目
在项目文件夹中使用命令
输入后会让我们输入一些指令,按照提示输入即可:
1 2 3 4 5 6 7 8 9 10 11 12
| D:\Web\vite_test>npm create vite@latest √ Project name: ... demo √ Select a framework: » Vue √ Select a variant: » JavaScript
Scaffolding project in D:\Web\vite_test\demo...
Done. Now run:
cd demo npm install npm run dev
|
之后就会看见一个名为demo的文件夹,其中的文件为
1 2 3 4 5 6
| ─demo ├─.vscode ├─public └─src ├─assets └─components
|
按照提示继续输入:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| D:\Web\vite_test>cd demo
D:\Web\vite_test\demo>npm install
added 27 packages in 6s
D:\Web\vite_test\demo>npm run dev
> demo@0.0.0 dev > vite
VITE v5.2.11 ready in 467 ms
➜ Local: http://localhost:5173/ ➜ Network: use --host to expose ➜ press h + enter to show help
|
点击链接打开本地服务器即可看到vite的原始界面。
之后可以将默认的HelloWorld.vue和style.css删除,并在main.js和App.vue中删除导入即可。
之后你就会得到一个空的vue文件
1 2 3 4 5 6 7 8 9 10 11
| <script setup>
</script>
<template>
</template>
<style scoped>
</style>
|
VSCode插件
VSCode本身其实就是一个文本编辑器,如果想要让他支持vue的开发,那么必须下载一些其他的插件。
- Vue-Official - 支持Vue语法高亮
- Vue VSCode Snippets - 快速生成vue3模版
- 别名路径跳转 - 替换@和/
安装了2之后可以通过以下命令创建初始模版:
创建一个如下的空模版
1 2 3 4 5 6 7 8 9 10 11 12 13
| <template> <div>
</div> </template>
<script setup>
</script>
<style lang="scss" scoped>
</style>
|
但是现在vue默认的模版中template已经不需要div包裹了,因此我们需要修改一下插件的格式,进入C:\Users\用户名\.vscode\extensions\sdras.vue-vscode-snippets-3.1.1\snippets
,找到vue.json
,搜索vbase-3-setup
和vbase-3-ts-setup
,将div
和lang="scss"
删除,将template和script调换位置。
修改为如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| "Vue Single File Component Setup Composition API": { "prefix": "vbase-3-setup", "body": [ "<script setup>", "", "</script>", "", "<template>", "", "</template>", "", "<style scoped>", "", "</style>" ], "description": "Base for Vue File Setup Composition API with SCSS" },
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| "Vue Single File Component Setup Composition API with Typescript": { "prefix": "vbase-3-ts-setup", "body": [ "<script setup lang=\"ts\">", "", "</script>", "", "<template>", "", "</template>", "", "<style scoped>", "", "</style>" ], "description": "Base for Vue File Setup Composition API - Typescript" },
|
修改完记得重启VSCode
接下来在vue文件中编写html标签会出现没有提示的情况,这时候可以在设置中搜索includeLanguages
,在Emmet
中添加至如下参数,重启后编写就有提示。
或者直接在settings.json
中添加如下设置文件:
1 2 3 4
| "emmet.includeLanguages": { "vue-html": "html", "vue": "html" }
|
这时候如果返回去打开其他html文件会发现ts-plugin
这个插件导致全部Code冒红,这时候在在设置中搜索Validate
,然后关闭TyScript的语法检查。
这个插件开启后VSCode的所有html都会冒红
代码迁移到Vue
之前使用html编写vue代码,可以体会到还是很麻烦的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body>
<div id="app"> {{web.show}} <p v-show="web.show">gcnanmu学Vue</p>
<hr>
<button @click="toggle">切换显示状态</button> </div>
<script type="module"> import {createApp, reactive} from "./js/vue.esm-browser";
createApp({ setup() {
const web = reactive({ show: true })
const toggle = () => { web.show = !web.show }
return { web, toggle } } }).mount("#app") </script> </body> </html>
|
如果要将其迁移到vue文件中只需要这样编写:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <script setup> import { reactive } from "vue"; const web = reactive({ show: true, });
const toggle = () => { web.show = !web.show; }; </script>
<template> {{ web.show }} <p v-show="web.show">gcnanmu学Vue</p>
<hr />
<button @click="toggle">切换显示状态</button> </template>
<style scoped> </style>
|
可以看到
- 不再需要编写return 和 setup
- 导入的时候只需要指定
vue
,不再需要指定到特定的vue.js
- 想要预览需要在终端使用
npm run dev
命令
父组件与子组件
在Vite中,我们一般都将vue组件放在components
文件夹中,组件其实就是vue文件,我们先在components
中创建header.vue
和footer.vue
两个组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <script setup>
</script>
<template>
<h3>header</h3>
<h3>footer</h3> </template>
<style scoped>
</style>
|
之后在App.vue
中导入两个组件
1 2 3 4 5 6 7 8 9 10 11 12
| <script setup> import Header from "./components/header"; import Footer from "./components/footer"; </script>
<template> <Header /> hello world <Footer /> </template>
<style scoped></style>
|
可以看到导入和在template中使用的时候组件的名字需要大写。在这个例子中,App.vue
是父组件,header.vue
和footer.vue
是子组件。
使用npm run dev
命令运行,可以在显示出的页面中看到效果。
父子组件传值
父传子 defineProps
使用语法为:
父组件
1 2 3 4 5 6
| <Header propsName="百度" propWeb="baidu.com" />
<button @click="userAdd">添加用户</button>
<Footer :="propWeb"/>
|
子组件
1 2 3 4
| <script setup> const props = defineProps(["propsName", "propWeb"]); console.log(props); </script>
|
或者以对象的方式接收
1 2 3 4 5 6 7 8 9
| <script setup> const props = defineProps({ users:Number, url:String })
console.log(props.users); console.log(props.url); </script>
|
也可以在组件中设定一些传递的规则:
1 2 3 4 5 6 7 8 9 10 11 12
| <script setup> const props = defineProps({ users: Number, url: { type: String, required: true, default: "baidu.com", }, }) </script>
|
完整代码:
App.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| <script setup> import Header from "./components/header.vue"; import Footer from "./components/footer.vue"; import { reactive } from "vue";
const propWeb = reactive({ users: 10, url: "www.baidu.com", });
const userAdd = () => { propWeb.users++; console.log(propWeb.users); }; </script>
<template> <Header propsName="百度" propWeb="baidu.com" /> <button @click="userAdd">添加用户</button> <Footer :="propWeb" /> </template>
<style scoped></style>
|
Header.vue
1 2 3 4 5 6 7 8 9 10
| <script setup> const props = defineProps(["propsName", "propWeb"]); console.log(props); </script>
<template> <h3>header</h3> </template>
<style scoped></style>
|
Footer.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <script setup> const props = defineProps({ users: Number, url: { type: String, required: true, default: "baidu.com", }, })
console.log(props); </script>
<template> <h3>footer</h3> {{ props.users }} </template>
<style scoped></style>
|
子传父 defineEmits
语法为:
子组件:
1 2 3 4 5 6 7 8
| <script setup> const emits = defineEmits(["getWeb","addUser"]) emits("getWeb","www.baidu.com")
const add = () =>{ emits("addUser",10) } </script>
|
父组件:
1 2 3
| <template> <Header @getWeb="emitsGetWeb" @addUser="emitsUserAdd"/> </template>
|
完整代码:
App.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| <script setup> import Header from "./components/header.vue"; import { reactive,ref } from "vue";
const web = reactive({ name:"百度", url: "baidu.com", })
let users = ref(0);
const emitsGetWeb = (data) =>{ web.url = data; console.log(web.url); }
const emitsUserAdd = (data) =>{ users.value += data; console.log(users.value); } </script>
<template> <Header @getWeb="emitsGetWeb" @addUser="emitsUserAdd"/>
{{ web.url }} {{ users }} </template>
<style scoped></style>
|
header.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <script setup> const emits = defineEmits(["getWeb","addUser"]) emits("getWeb","www.baidu.com")
const add = () =>{ emits("addUser",10) } </script>
<template> <h3>header</h3> <button @click="add">添加用户</button> </template>
<style scoped></style>
|
跨组件通信 provide inject
这个方法只能实现父组件向子组件传递数据,父组件使用provide,子组件使用的是inject
语法为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <script setup> import Header from "./components/header.vue"; import { reactive, ref, provide } from "vue";
const web = reactive({ name: "百度", url: "baidu.com", })
provide("provideWeb", web);
let users = ref(0);
const userAdd = () => { users.value++; }
provide("provideFuncUserAdd", userAdd);
</script>
|
子组件语法为:
1 2 3 4 5 6 7
| <script setup> import {inject} from "vue";
const web = inject("provideWeb");
const funcUserAdd = inject("provideFuncUserAdd"); </script>
|
完整代码为:
App.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| <script setup> import Header from "./components/header.vue"; import { reactive, ref, provide } from "vue";
const web = reactive({ name: "百度", url: "baidu.com", })
provide("provideWeb", web);
let users = ref(0);
const userAdd = () => { users.value++; }
provide("provideFuncUserAdd", userAdd);
</script>
<template> <h3>App top</h3> users:{{ users }}
<Header/> </template>
<style scoped></style>
|
header.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <script setup> import Nav from "./nav.vue"; import { inject } from "vue";
const funcUserAdd = inject("provideFuncUserAdd"); console.log("funcUserAdd", funcUserAdd); </script>
<template> <h3>header middle</h3> <Nav/> <button @click="funcUserAdd">添加用户</button> </template>
<style scoped></style>
|
nav.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <script setup>
import {inject} from "vue";
const web = inject("provideWeb"); console.log("provideWeb",web);
</script>
<template> <h3>nav button</h3> </template>
<style scoped>
</style>
|
匿名插槽 v-slot
我们一开始渲染子组件使用的都是自闭和的形式<Header />
和<Footer />
,插槽即为<Header><Header/>
匿名插槽的语法为:
父组件:
1 2 3
| <Header> <a href="www.baidu.com">百度</a> </Header>
|
子组件:
如果想要使用name进行标签的定义,可以这样写:
父组件:
1 2 3 4 5 6 7
| <Footer > <template #url> <a href="tencent.com">腾旭</a> </template> </Footer>
|
子组件:
完整代码:
App.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| <script setup> import Header from './components/header.vue'; import Footer from './components/footer.vue';
</script>
<template> <h3>App vue</h3>
<Header> <a href="www.baidu.com">百度</a> </Header>
<Footer > <template #url> <a href="tencent.com">腾旭</a> </template> </Footer> </template>
<style scoped>
</style>
|
Header.vue
1 2 3 4 5 6 7 8 9 10
| <script setup>
</script>
<template> <h3>header vue</h3> <slot /> </template>
<style scoped></style>
|
Footer.vue
1 2 3 4 5 6 7 8 9 10 11 12
| <script setup>
</script>
<template> <h3>footer vue</h3> <slot name="url"/> </template>
<style scoped>
</style>
|
作用域插槽 #name
他的作用是来让子组件向父组件传递数据,并在父组件的模版中渲染
语法为:
子组件:
1
| <slot name="url" title="vue" url="vuejs.org" />
|
父组件:
1 2 3 4 5 6 7 8
|
<template #url="{title, url}"> {{ title }} {{ url }} <a href="tencent.com">腾旭</a> </template>
|
生命周期函数
- 挂载阶段 - onMounted onBeforeMount
- 更新阶段 - onBeforeUpdate onUpdated
- 卸载阶段 - onBeforeUnmout onUnmounted
- 错误处理 - onErrorCoptured
下面是一个挂载和更新的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| <script setup> import { onMounted,onUpdated,ref } from 'vue';
onMounted(() => { console.log('App.vue mounted'); });
onUpdated(() => { console.log('App.vue updated'); });
const user =ref(0)
console.log("user:",user);
</script>
<template> {{ user }} <button @click="user++">添加用户</button>
</template>
<style scoped>
</style>
|
当网页刚加载时,会打印“App.vue mounted”,当按钮被点击的时候,控制台会打印出多次”App.vue updated”。
toRef和toRefs
这两个方式是为了将响应式对象的属性转化为Ref对象。
- toRef - 将单个属性转化
- toRefs - 将整个对象转化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| <script setup> import { reactive, toRefs, toRef } from 'vue';
let web = reactive({ name: "百度", url: "www.baidu.com" })
console.log(typeof web.url)
let { name, url } = toRefs(web)
console.log("name:", name, "url:", url)
const changeUrl = toRef(web.name) </script>
<template> {{ web.url }} {{ changeUrl }} </template>
<style scoped></style>
|