Vue基础学习
前言
本教程参考:B站视频1 BV1Rs4y127j8 B站视频2 BV1nV411Q7RX
Vue 安装
这里介绍的 Vue3 的安装,需要 15.0 或更高版本的Node.js
使用
node -v
显示版本号
在cmd界面找到需要存放Vue的文件夹,进入后使用下述命令创建:
npm init vue@latest
配置完相关信息后:
cd <Project-name>
npm install
npm run dev
即可启动Vue项目
目录结构说明:
.vscode --- 工具的配置文件
node_modules --- Vue项目的运行依赖文件
public --- 资源文件夹(浏览器图标)
src --- 源码文件夹
.gitignore --- git忽略文件
index.html --- HTML文件
package.json --- 信息描述文件
README.md --- 注释文件
vite.config.js --- Vue配置文件
Vue选项式Api学习-Vue2风格
app.vue引用模块
在 src
中的 components
创建 test.vue
,然后在 App.vue
和 test.vue
中加入以下代码,即可引用:
<!-- src/App.vue -->
<script setup>
import test from './components/test.vue'
</script>
<template>
<!-- 注意这里需要添加引用的文件名 -->
<test/>
</template>
<!-- src/components/test.vue -->
<template>
</template>
<script>
export default{
data(){
return{
}
}
}
</script>
文本插值
在标签中使用 {{ }}
形式添加定义的变量,来直接展示变量的值:
<template>
<h3>模板语法</h3>
<p>{{ msg }}</p>
</template>
<script>
export default{
data(){
return{
msg:"神奇的语法",
}
}
}
</script>
嵌套html代码
在要嵌套的标签中添加属性 v-html=""
其中放入变量 html
<template>
<h3>模板语法</h3>
<p v-html="html"> </p>
</template>
<script>
export default{
data(){
return{
html:"<a href='https://romcere.top'>romcere</a>"
}
}
}
</script>
插入属性
添加 v-bind:
实现添加变量属性:
<template>
<div v-bind:class="msg"></div>
</template>
<script>
export default{
data(){
return{
msg:"active"
}
}
}
</script>
如果给
msg
赋值null
或undefined
会移除这个属性
v-bind:
也可以简写为 :
,即:<div :class="msg"></div>
同时,也可以使用 v-bind=""
添加多个属性:
<template>
<button v-bind="obj">button</button>
</template>
<script>
export default{
data(){
return{
obj:{
id:"ID",
class:"CLASS"
}
}
}
}
</script>
条件渲染
Vue提供两个属性 v-if=""
和 v-else
用于判断是否显示该标签:
<template>
<div v-if="flag">你能看见我吗</div>
<div v-else-if="">你应该能看见我</div>
<div v-else>那你还是看见我吧</div>
</template>
<script>
export default{
data(){
return{
flag:false
}
}
}
</script>
当
v-if
的标签未显示,则展示v-else
的标签
v-show=""
的使用:
<template>
<div v-show="flag">你能看见我吗</div>
</template>
v-if
和 v-show
的区别:
v-if
是通过添加和删除来实现的v-show
是通过添加css属性display:none来实现的- 如果需要频繁切换则使用
v-show
,如果很少切换则使用v-if
列表渲染
使用 v-for
遍历列表:
<template>
<p v-for="item in names">{{ item }}</p>
</template>
<script>
export default{
data(){
return{
names:["nums1","nums2","nums3"]
}
}
}
</script>
v-for
也可以接收数组的索引:
<template>
<p v-for="(item,index) in names">{{ item }}-{{ index }}</p>
</template>
如果用 v-for
遍历对象,则:
<template>
<p v-for="(value,key,index) in user">{{ value }}-{{ key }}-{{ index }}</p>
</template>
添加 key
属性,来添加唯一索引,防止遍历出错:
<template>
<p v-for="(item,index) in user" :key="item.id"></p>
</template>
key
的值一般建议使用id来添加唯一索引,让每一条数据变得唯一
事件处理
使用 v-on
来监听DOM事件,使用方法:v-on:click=""
或 @click=""
<template>
<!-- 内联式,直接使用方法 -->
<button @click="count1++">count:{{count1}} </button>
<!-- 方法事件处理 -->
<button @click="addCount()">count:{{count2}} </button>
</template>
<script>
export default{
data(){
return{
count1:0,
count2:0
}
},
// !!!所有的方法都放在这里
methods:{
addCount(){
// 使用this调用外部变量
this.count2++;
}
}
}
</script>
获取 event
对象:
<template>
<!-- 不加() -->
<button @click="addCount($event)">test</button>
</template>
<script>
export default{
data(){
return{
count:0
}
},
methods:{
// event简写成e,这里的event就是原生JS的Event对象
addCount(e){
e.target.innerHTML = "Add:" + this.count;
this.count++;
}
}
}
</script>
传递参数:
<template>
<button @click="addCount('hello',$event)">test</button>
</template>
<script>
export default{
data(){
return{
count:0
}
},
methods:{
// 传递参数
addCount(msg,e){
console.log(msg)
e.target.innerHTML = "Add:" + this.count;
this.count++;
}
}
}
</script>
事件修饰符:即常用的 event.xxx
方法
具体参考:https://cn.vuejs.org/guide/essentials/event-handling.html#event-modifiers
例如:
<template>
<a @click="clickHiden($event)" href="https://romcere.top">romcere</a>
</template>
<script>
export default{
data(){
return{
count:0
}
},
methods:{
clickHiden(e){
// 阻止默认点击事件
e.preventDefault();
console.log("点击了");
}
}
}
</script>
<!-- 或者直接使用@click.prevent="" -->
<a @click.prevent="clickHiden()" href="https://romcere.top">romcere</a>
数组变化侦测
<template>
<button @click="click()">点我</button>
<p v-for="item in names">{{ item }}</p>
</template>
<script>
export default{
data(){
return{
names:["nums1","nums2","nums3"]
}
},
methods:{
click(){
// 使用此方法会直接更新数组信息
// this.names.push("nums4");
// 使用此方法不会直接变更,需要重新赋值
this.names = this.names.concat("nums4")
}
}
}
</script>
计算属性
computed
总是在响应式计算更新时才计算,而 methods
总在页面重渲染时执行;使用 computed
可以减少缓存
<template>
<!-- 这里len不要加(),因为它不是函数 -->
<p>{{ len }}</p>
<!-- 常规写法 -->
<p>{{ this.names.length > 1 ? 'Yes' : 'NO' }}</p>
</template>
<script>
export default{
data(){
return{
names:["nums1","nums2","nums3"]
}
},
// !!!放置计算数学的方法
computed:{
len(){
return this.names.length > 1 ? 'Yes' : 'NO';
}
}
}
</script>
Class与Style增强
绑定class类有很多种方法:
<template>
<!-- 使用isActive来判断active类是否显示 -->
<p :class="{'active':isActive}" >测试文字1</p>
<!-- 使用对象添加类 -->
<p :class="activeOBJ" >测试文字2</p>
<!-- 数组添加或数组嵌套对象 -->
<p :class="[isActive,activeOBJ]" >测试文字3</p>
</template>
<script>
export default{
data(){
return{
isActive:false,
activeOBJ:{
'active':true
}
}
}
}
</script>
<style>
.active{
color:red;
}
</style>
绑定Style:
<template>
<!-- 使用此方法动态添加style -->
<p :style="{color:activrColor,fontSize:fontSize + 'px'}" >测试文字</p>
<!-- 以对象方式添加 -->
<p :style="styleOBJ" >测试文字</p>
</template>
<script>
export default{
data(){
return{
activeColor:'green',
fontSize:30,
styleOBJ:{
color:"red",
fontSize:"30px"
}
}
}
}
</script>
侦听器
用于侦听数据的更改
<template>
<!-- 侦听的是此数据的变化 -->
<p>{{ msg }}</p>
<button @click="edit">修改</button>
</template>
<script>
export default{
data(){
return{
msg:"hello"
}
},
methods:{
edit(){
this.msg="world"
}
},
<!-- 侦听器 -->
watch:{
<!-- 这里的函数名必须与侦听的数据名保持一致 -->
msg(newValue,oldValue){
// 数据发生变化,自动执行的函数
console.log(newValue,oldValue)
}
}
}
</script>
表单输入绑定
input
输入的内容,可以实时读取:
<template>
<form>
<input type="text" v-model="msg">
<p>{{ msg }}</p>
</form>
</template>
<script>
export default{
data(){
return{
msg:""
}
}
}
</script>
修饰符:.lazy
:失去焦点后得到、.number
:去掉数字得到、.trim
:去掉前后空格得到
获取DOM操作
如果没有特别的需求,不需要操作DOM:
<template>
<!-- 使用ref属性 -->
<div ref="container">{{ content }}</div>
<button @click="getItem">获取元素</button>
</template>
<script>
export default{
data(){
return{
content:"内容"
}
},
methods:{
getItem(){
// 使用this.$refs.<ref-name>获取DOM
console.log(this.$refs.container)
}
}
}
</script>
引用组件
在 App.vue
中写入以下代码来引用组件:
<template>
<test/>
</template>
<script>
import test from './components/test.vue'
export default{
// 在components中放入组件名
components:{
test
}
}
</script>
组合式API学习
ref-reactive区别
ref为引用类型,需要使用.value才能访问到值;reactive则可以直接访问到数据
reactive一般用来存储复杂数据类型;ref一般存储变量、方法
v-on 点击事件
可简写为 @
<el-button v-on:click="add"/>
<el-button @click="add"/>
@keyup.xxx 按键修饰符
<!-- 输入enter键时,执行该输入框的方法 -->
<el-input @keyup.enter="add"/>
v-show 显示与隐藏
提前渲染,适用于频繁切换显示状态
<!-- isShow为true时展示 -->
<p v-show="isShow">Romcere romcere.top</p>
v-if 条件渲染
是否渲染元素,不适用于频繁切换显示状态,否则对性能有影响
<p v-if="isShow">这是v-if</p>
<p v-else-if="isShow">这是v-else-if</p>
<!-- 当不满足上述条件时,则渲染 -->
<p v-else>这是v-else</p>
v-bind 动态属性绑定
可简写为 :
<img v-bind:src="imageUrl" >
<img :src="imageUrl" >
v-for 遍历循环
<el-input v-for="item in dataForm"/>
v-model 双向数据绑定
<!-- 当修改inputValue值时,inputValue被同时更改 -->
<el-input v-model="inputValue" />
<!-- 只能赋给输入框初值,不能获取到输入框的值;即inputValue不能被更改 -->
<el-input :value="inputValue" />
v-model.xxx 修饰符
<!-- 可以在v-model后加.xxx来对inputValue值提前进行处理 -->
<el-input v-model.trim="inputValue" />
v-text v-html 渲染数据
<h3 v-text="romcere.top" />
<!-- 此时会将<i>标签解析嵌套入<h3>标签内,然后显示文本 -->
<h3 v-html="<i style="color:blue">romcere.top</i> />
computed 计算属性
<template>
<h3> add:{{add}} </h3>
<h3> add:{{add}} </h3>
<!-- 调用两次sub方法,但实际上只调用了一次(只打印了一次sub),说明有缓存 -->
<h3> sub:{{sub}} </h3>
<h3> sub:{{sub}} </h3>
</template>
<script setup>
const x = ref(10)
const y = ref(20)
const add = ref(()=>{
console.log("add") // 打印两次
return x+y
})
const sub = computed(()=>{
console.log("sub") // 打印一次,有缓存可以提高性能
return x+y
})
</script>
watch 侦听器
<template>
<el-input v-model="inputValue" />
</template>
<script setup>
const inputValue = ref('')
// 侦听inputValue,当其值变化时进行操作
watch(inputValue,(newValue,oldValue)=>{
console.log('newValue:',newValue,'oldValue:',oldValue)
})
</script>
watchEffect 自动侦听器
<template>
<el-input v-model="inputValue" />
</template>
<script setup>
const inputValue = ref('')
// 使用此方法,会在页面渲染后就开始监听
watchEffect(()=>{
console.log("----开始监听----")
console.log(inputValue.value)
console.log("----监听结束----")
})
</script>
defineProps 父传子
<!-- 子组件 文件名为Web.vu -->
<template>
<span>{{web}}</span>
</template>
<script setup>
const props=defineProps({
web:String
})
</script>
<!-- 父组件 -->
<template>
<Web :temp="Romcere."></Web>
</template>
<script setup>
import Web from '@/xxx'
</script>
defineEmits 子传父-事件传递
<!-- 子组件 -->
<script setup>
const emits=defineEmits(['getWeb'])
// 第一个参数为要传递方法名,第二个参数为传递的数据
emits('getWeb',[url:'Romcere.'])
</script>
<!-- 父组件 -->
<template>
<Web @getWeb="emitsGetWeb"></Web>
</template>
<script setup>
import Web from '@/xxx'
// 这里的data为子组件传递的数据
const emitsGetWeb=(data)=>{
console.log(data.url)
}
</script>
defineExpose 子传父-暴露自己的属性或方法
<!-- 子组件 -->
<script setup>
function show(){
console.log("这是子组件")
}
defineExpose({
show,
count:1
})
</script>
<!-- 父组件 -->
<template>
<Temp ref="childRef"></Temp>
<el-button @click="handleClick"></el-button>
</template>
<script setup>
import Temp from '@/xxx'
// 需先定义ref
const childRef = ref(null)
function handleClick(){
childRef.value.show()
console.log(childRef.value.count)
}
</script>
provide-inject 跨组件通信-依赖注入
该方法可以将父组件数据传到子组件的子组件
<!-- 父组件 -->
<script setup>
const web = ref({
url:'romcere.top'
})
// 第一个参数为传递的方法名,第二个参数为传递的数据
provide('provideWeb',web)
</script>
<!-- 子子组件 -->
<script setup>
// 接收到父父组件的数据
const web=inject('provideWeb')
console.log('provideWeb',web)
</script>
slot 匿名插槽-具名插槽
<!-- 子组件 -->
<template>
<slot name="web"></slot>
</template>
<!-- 父组件 -->
<template>
<Web>
<!-- v-slot:web也可简写为#web -->
<template v-slot:web>
<a href='romcere.top'>romcere.top</a>
</template>
</Web>
</template>
<script setup>
import Web from '@/xxx'
</script>
作用域插槽
子组件可以向父组件传递数据
<!-- 子组件 -->
<template>
<slot name="web" title="Romcere."></slot>
</template>
<!-- 父组件 -->
<template>
<Web>
<!-- 这里的data用于接收子组件传递的数据 -->
<template #web="data">
<a href='romcere.top'>{{data.title}}</a>
</template>
</Web>
</template>
<script setup>
import Web from '@/xxx'
</script>
生命周期函数
定义:指从组件实例从创建到销毁的过程中,不同时间点 自动调用 的函数
挂载阶段:
onBeforeMount:在组件实例即将
被挂载到DOM树之前调用;常用于执行初始化操作。
如:获取异步数据、设置初始属性值等
onMounted:在组件
成功挂载到DOM并完成首次渲染后调用;此时可访问和操作DOM元素。
更新阶段:
onBeforeUpdate(由于响应式数据变化):在
组件更新前即将重新渲染时调用;根据新的参数判断是否要进行处理,甚至可以选择阻止此次更新
onUpdate:在
组件完成更新并重新渲染后调用,可以基于渲染结果处理更新后的数据
卸载阶段:
onBeforeUnmount:在
组件从DOM中销毁前调用;用于释放资源
如:清理计时器、解绑事件监听器
onUnmounted:在
组件已经从DOM中移除并销毁后调用;确保组件所占用的资源被释放
错误处理:
onErrorCaptured:在
捕获到组件中的错误时调用;用于处理错误
如:记录错误日志
toRef toRefs 转换为ref对象
toRefs将一个响应式对象的所有属性转换为ref对象
toRef将一个响应式对象的某个属性转化为ref变量
<template>
</template>
<script setup>
let web={
name:"Romcere.",
url:"romcere.top"
}
let web=toRefs(web)
// 第一个参数为要转换的对象,第二个参数为要转换属性名
let web=toRef(web,url)
console.log(typeof web.url)
</script>
Pinia-stores 状态管理
解决问题:1.全局状态管理 2.简化组件间通信 3.状态持久化