初识vue

创建vue3项目

手动创建项目的命令

使用npm或者yarn包管理工具都可以搭配vite手动创建项目

1
2
3
4
#使用npm create命令创建项目
npm create vite@latest
#使用yarn create命令创建项目
yarn create vite

示例

创建之后可以在终端输入yarn安装项目的全部依赖

安装完之后输入 yarn dev 启动本地服务器

通过模板自动创建项目

1
2
3
4
5
6
#使用npm6或更低版本创建项目
npm create vite@latest <项目名称> --template <模板名称>
#使用npm7或更高版本创建项目
npm create vite@latest <项目名称> -- --template <模板名称>
#使用yarn create命令创建项目
yarn create vite <项目名称> --template <模板名称>

示例

vue3目录结构

.vscode : 存放vscode编辑器的相关配置

node_modules:存放通过npm或yarn安装的所有依赖包和插件

public:存放的不可编译的静态资源文件,如图像、字体文件、favicon.ico等,使用绝对路径进行访问

src:存放的开发者编写的源代码,,通常包括组件、样式、逻辑、API等

assets:存放的可编译的静态资源文件,如图像、样式表、JavaScript文件等,使用相对路径进行访问

components:存放单文件组件

App.vue:项目的根组件,也是 Vue组件的入口文件,通常包含整个应用的主要框架结构

main.js:项目的入口文件,通常会在这里创建Vue实例,并挂载到DOM上

style.css:项目的全局样式文件

.gitignore:向git上传代码时需要忽略的文件列表

index.html:默认的主渲染文件,项目的HTML模板,通常在这里包含项目的主要静态元素,并在<body>中挂载Vue应用

package.json:项目的配置文件,定义了项目的基本信息、依赖、脚本等

README:项目的使用说明文件

vite.config.js:存放的vite的相关配置,比如插件、路径别名、开发服务器等

yarn.lock: 用于确保每次安装依赖时都使用相同版本的锁文件。它由yarn管理,确保依赖的稳定性

vue运行过程

创建vue实例

在 Vue 项目中,main.js 文件是整个应用的入口文件。在执行 npm run dev 命令时,Vite 或 Webpack 会从 src/main.js 开始加载应用。

main.js

1
2
3
4
5
import { createApp } from 'vue'   // 引入 Vue
import './style.css' // 引入全局样式
import App from './App.vue' // 引入根组件
// 创建 Vue 实例并挂载到 #app 元素上
createApp(App).mount('#app')

生成虚拟 DOM 和组件渲染

在 Vue 3 中,组件的渲染分为结构、样式和交互三个部分。在 App.vue 中,我们通常看到三个部分:<template><script><style>

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
31
<!--交互-->
<script setup>
import HelloWorld from './components/HelloWorld.vue'
</script>
<!--结构-->
<template>
<div>
<a href="https://vite.dev" target="_blank">
<img src="/vite.svg" class="logo" alt="Vite logo" />
</a>
<a href="https://vuejs.org/" target="_blank">
<img src="./assets/vue.svg" class="logo vue" alt="Vue logo" />
</a>
</div>
<HelloWorld msg="Vite + Vue" />
</template>
<!--样式-->
<style scoped>
.logo {
height: 6em;
padding: 1.5em;
will-change: filter;
transition: filter 300ms;
}
.logo:hover {
filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.vue:hover {
filter: drop-shadow(0 0 2em #42b883aa);
}
</style>

交互:使用 <script setup> 语法,引入子组件 HelloWorld.vue

结构:模板部分,定义页面的 HTML 结构。

样式:使用 <style scoped> 编写组件的样式。

App.vue 渲染时,它首先加载 HelloWorld 组件,并在模板中渲染该组件。Vue 会将模板转换成虚拟 DOM,并根据响应式数据的变化来更新视图。

创建入口文件

index.html 是项目的首页,入口页,也是整个项目唯一的HTML页面

index.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + Vue</title>
</head>
<body>
<div id="app"></div> <!-- Vue 会将应用挂载到这个元素 -->
<script type="module" src="/src/main.js"></script> <!-- 引入入口文件 -->
</body>
</html>

这个页面的 #app 元素将是 Vue 实例的挂载点。

script 标签引入了 main.js 文件,这是整个 Vue 应用的入口。

vue开发基础

单文件组件

每个单文件组件由模板、样式和逻辑3个部分构成

1
2
3
4
5
6
7
8
9
<template>
<!-此处编写组件的结构->
</template>
<script>
/*此处编写组件的逻辑*/
</script>
<style>
/休此处编写组件的样式*/
</style>

初始数据绑定

定义数据:

1
2
3
4
5
6
7
8
9
<script>
export default{
setup(){
return{
数据名:数据值
}
}
}
</script>

使用setup语法糖来定义数据的语法格式如下。

1
2
3
<script setup>
const数据名=数据值
</script>

当页面渲染时,模板中的会被替换为实际的数据

在Mustache语法中还可以将表达式的值作为输出内容。表达式的值可以是字符串、数字等类型,示例代码如下

1
2
3
4
5
{{'Hello Vue.js'}}
{{number+1}}
{{obj.name }}
{{ok 'YES':'NO'}}
{{'<div>HTML标签</div>'}}

数据绑定的实现

创建src\components\Message.vue文件

1
2
3
4
5
6
<template>
{{ message }}
</template>
<script setup>
const message = '不积跬步无以至千里'
</script>

更改main.js

1
2
3
4
5
import { createApp } from 'vue'
import './style.css'
import App from './components/Message.vue'

createApp(App).mount('#app')

将vue引入HTML页面

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
</head>
<body>
<div id="app">
<p>{{message}}</p>
</div>

<script>
const vm=Vue.createApp({
setup(){
return{
message:'hello world'
}
}
})
vm.mount('#app')
</script>
</body>
</html>

响应式数据绑定

vue为开发者提供了如下函数定义响应式数据

ref()

1
2
3
4
5
6
7
8
9
10
<template>
{{ Message }}
</template>
<script setup>
import { ref } from 'vue'
const Message = ref('Hello World')
setTimeout(() => {
Message.value = 'Hello Vue 3.0'
}, 2000)
</script>

reactive()

1
2
3
4
5
6
7
8
9
10
11
<template>
{{obj.message}}
</template>
<script setup>
import { reactive } from 'vue'
const obj=reactive({message:'Hello World'})
setTimeout(() => {
obj.message = 'Hello Vue 3.0'
}, 2000);
</script>

toRef()

1
2
3
4
5
6
7
8
9
10
11
12
13
<template>
<div>message的值:{{message}}</div>
<div>obj.message的值:{{obj.message}}</div>
</template>
<script setup>
import { reactive, toRef } from 'vue'
const obj = reactive({ message: 'hello' })//创建一个响应式对象
const message=toRef(obj,'message') // 将响应式对象obj中的message属性转换为响应式引用
setTimeout(() => {
message.value = 'world'
}, 2000)

</script>

toRefs()

1
2
3
4
5
6
7
8
9
10
11
12
<template>
<div>message的值:{{message}}</div>
<div>obj.message的值:{{obj.message}}</div>
</template>
<script setup>
import { reactive, toRefs } from 'vue'
const obj = reactive({ message: 'hello'})
let {message} = toRefs(obj)
setTimeout(() => {
message.value = 'world'
}, 2000)
</script>

区别

**使用 reactive**:当你需要处理 对象数组 的响应式数据时,reactive 更自然,因为它能深度响应式地处理这些类型的数据,并且不需要 .value 访问对象的属性。

**使用 ref**:当你需要处理 基本类型(如字符串、数字、布尔值)时,ref 更适合,因为它是为这些类型专门设计的,能够轻松管理单一数据。

**使用 toRef**:当你想将 响应式对象 的某个属性转换为单独的响应式引用时,使用 toRef。它会返回一个新的响应式引用 Ref,你可以直接通过 .value 访问这个属性。

**使用 toRefs**:当你需要将 整个响应式对象 中的每个属性转换为响应式引用时,使用 toRefs。它返回一个新的对象,包含响应式对象中每个属性的 ref 引用。

内容渲染指令

v-text用于渲染DOM元素的文本内容,如果文本内容中包含HTML标签,那么浏览器不会对其进行解析。

1
2
3
4
5
6
7
<template>
<div v-text="Message">
</div>
</template>
<script setup>
const Message = '<span>Hello World</span>'
</script>

在使用Vue进行内容渲染时,如果内容中包含HTML标签并且希望这些标签被浏览器解析,则可以使用v-html。v-html用于渲染DOM元素的HTML内容,其用法与v-text相似。

1
2
3
4
5
6
7
<template>
<div v-html="html">
</div>
</template>
<script setup>
const html = '<strong>Hello World</strong>'
</script>

属性绑定指令

在Vue开发中,有时需要绑定DOM元素的属性,从而更好地控制属性的值,此时可以使用属性绑定指令v-bind来实现。

v-bind还支持将属性与字符串拼接表达式绑定。

1
2
3
4
5
6
7
8
<template>
<p><input type="text" v-bind:placeholder="username"></p>
<p><input type="password" :placeholder="password"></p>
</template>
<script setup>
const username = ref('请输入用户名')
const password = ref('请输入密码')
</script>

事件绑定指令

在Vue开发中,有时需要给DOM元素绑定事件,从而利用事件实现交互效果,这时可以利用事件绑定指令v-on来实现。

v-on还有简写形式,可以将”v-on:事件名”简写为“@事件名”

1
<标签名 V-on:事件名="事件处理器"></标签名>
1
2
3
4
5
6
7
8
<template> 
<button @click="showInfo">输出信息</button>
</template>
<script setup>
const showInfo = () => {
console.log('我是一个按钮');
}
</script>

双向数据绑定指令

Vue为开发者提供了v-model指令来实现双向数据绑定,使用它可以在input、textarea和select元素上创建双向数据绑定,它会根据使用的元素自动选取对应的属性和事件组合,负责监听用户的输入事件并更新数据。

1
<标签名 v-model=:"数据名"></标签名>

为了方便对用户输入的内容进行处理,v-model提供了3个修饰符。v-model的修饰符如下表所示:

.number (如果不加.number默认是字符串类型)

1
2
3
4
5
6
7
8
9
10
11
<template>
请输入姓名:<input type="text" v-model="username">
<div>姓名是: {{username}}</div>
<input type="text" v-model.number="n1">+<input type="text" v-model.number="n2">={{n1+n2}}
</template>
<script setup>
import { ref } from 'vue'
const username = ref('zhangsan')
const n1 = ref(1)
const n2 = ref(2)
</script>

条件渲染指令

在Vue中,当需要根据不同的判断结果显示不同的DOM元素时,可以通过条件渲染指令来实现。条件渲染指令可以辅助开发者按需控制DOM元素的显示与隐藏。

条件渲染指令如下。

v-if

1
2
3
4
5
6
7
8
9
10
11
12
13
<template>
小明的学习评定等级为:
<p v-if="type === 'A'">优秀</p>
<p v-else-if="type === 'B'">良好</p>
<p v-else>差</p>
<button @click="type ='A'">切换成优秀</button>
<button @click="type ='B'">切换成良好</button>
<button @click="type ='C'">切换成差</button>
</template>
<script setup>
import { ref } from 'vue'
const type = ref('B')
</script>

v-show

v-show的原理是通过为元素添加或移除display:none样式来实现元素的显示或隐藏。当需要频繁切换某个元素的显示或隐藏时,使用V-show会更节省性能开销;而当只需要切换一次显示或隐藏时,使用V-f更合理。

1
2
3
4
5
6
7
8
9
<template>
<p v-if="flag">通过v-if控制的元素</p>
<p v-show="flag">通过v-show控制的元素</p>
<button @click="flag = !flag">显示/隐藏</button>
</template>
<script setup>
import { ref } from 'vue'
const flag = ref(true)
</script>

列表渲染指令

Vue提供了列表渲染指令V-for。开发者只需在模板中定义一件商品的结构,V-for便会根据开发者提供的数据自动渲染商品列表中所有的商品

1
2
3
4
5
6
7
8
9
<template>
<div v-for="(item,index) in list":key="index">
索引是:{{index}} ---元素的内容是:{{item}}
</div>
</template>
<script setup>
import {reactive} from 'vue'
const list=reactive(['张三','李四','王五'])
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
<template>
<div v-for="item in list" :key="item.id">
id是: {{ item.id }} --- 元素的内容是: {{ item.message }}
</div>
</template>
<script setup>
import {reactive} from 'vue'
const list = reactive([
{ id: 1, message: 'hello' },
{ id: 2, message: 'world' },
{ id: 3, message: 'vue' },
])
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
<template>
<div v-for="(value,name) in user" :key="name">
属性名是:{{name}} --- 属性值是:{{value}}
</div>
</template>
<script setup>
import {reactive} from 'vue'
const user=reactive({
id:1,
name:'张三',
gender:'男'
})
</script>

事件对象

通过事件方法的参数获取事件对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<template>
<div>count的值为:{{ count }}</div>
<button @click="addCount">count+1</button>
</template>
<script setup>
import { ref } from 'vue'
const count = ref(1)
const addCount = event => {
count.value++
if(count.value%2 === 0){
event.target.style.border="3px dotted"
}else{
event.target.style.border="3px solid"
}
}
</script>

通过$event获取事件对象

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
<template>
<div>count的值为:{{ count }}</div>
<button @click="addCount">count+1</button>
<button @click="addCountN(3,$event)">count+n</button>
</template>
<script setup>
import { ref } from 'vue'
const count = ref(1)
const addCount = event => {
count.value++
if(count.value%2 === 0){
event.target.style.border="3px dotted"
}else{
event.target.style.border="3px solid"
}
}
const addCountN =(n,event)=>{
count.value+=n
if(count.value%2 === 0){
event.target.style.border="3px dotted"
}else{
event.target.style.border="3px solid"
}
}

</script>

事件修饰符

阻止默认事件行为

.prevent

1
<a href="test.html" v-on:click.prevent>阻止默认跳转行为</a>

阻止事件冒泡

.stop

1
2
3
4
5
6
7
8
9
<template>
<div v-on:click ="show('我是父元素的事件')">
<button v-on:click="show('我是子元素的事件')">事件冒泡</button>
<button v-on:click.stop="show('我是子元素的事件')">阻止事件冒泡</button>
</div>
</template>
<script setup>
let show=message =>console.log(message)
</script>

事件冒泡控制台输出:

1
2
我是子元素的事件
我是父元素的事件

阻止事件冒泡控制台输出:

1
我是子元素的事件

事件捕获

.captrue

1
2
3
4
5
6
<div v-on:click.capture ="show('我是父元素的事件')">
<button v-on:click="show('我是子元素的事件')">事件冒泡</button>
<button v-on:click.stop="show('我是子元素的事件')">阻止事件冒泡</button>
<!-- 事件捕获 -->
<button v-on:click="show('我是子元素的事件')">事件捕获</button>
</div>

控制台输出:

1
2
我是父元素的事件
我是子元素的事件