初识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' import './style.css' import App from './App.vue'
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> <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>
|
事件冒泡控制台输出:
阻止事件冒泡控制台输出:
事件捕获
.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>
|
控制台输出: