VUE3.0学习
1、CDN使用Vue
引入Vue.js
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
vite脚手架安装
先下载node.js并安装,在终端下使用npm安装vite
#安装脚手架
npm init vue@latest
#或
#vue-xu01是创建项目名称
npm init vite@latest vue-xu01 -- --template vue
#按y下一步
cd vue-xu01
#进入目录安装
npm install
#在目录下运行
npm run dev
Axios网络请求库使用
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
使用方法
axios.get("地址").then((response)=>{
//准确返回
},(err)=>{
//错误返回
})
2、创建第一个应用
每个 Vue 应用都是通过 createApp 函数创建一个新的 应用实例
import { createApp } from 'vue'
const app = createApp({
/* 根组件选项 */
})
const { createApp } = Vue
createApp({
data() {
return {
message: 'Hello Vue!',
age:18
}
}
}).mount('#app')
多个应用实例
const app1 = createApp({
/* ... */
})
app1.mount('#container-1')
const app2 = createApp({
/* ... */
})
app2.mount('#container-2')
3、模板语法
文本插值
<span>Message: {{ msg }}</span>
v-html网页化
<p>Using text interpolation: {{ rawHtml }}</p>
<p>Using v-html directive: <span v-html="rawHtml"></span></p>
v-bind属性绑定
<div v-bind:id="dynamicId"></div>
<div :id="dynamicId"></div>
<div v-bind:class="dynamicId"></div>
<div :class="dynamicId"></div>
动态绑定多个值
data() {
return {
objectOfAttrs: {
id: 'container',
class: 'wrapper'
}
}
}
//html
<div v-bind="objectOfAttrs"></div>
动态参数
<!--
注意,参数表达式有一些约束,
attributeName可以设定id、class……
-->
<a v-bind:[attributeName]="url"> ... </a>
<!-- 简写 -->
<a :[attributeName]="url"> ... </a>
v-on监听 DOM 事件
<a v-on:click="doSomething"> ... </a>
<!-- 简写 -->
<a @click="doSomething"> ... </a>
JavaScript 表达式
Vue 实际上在所有的数据绑定中都支持完整的 JavaScript 表达式
{{ number + 1 }}
{{ ok ? 'YES' : 'NO' }}
{{ message.split('').reverse().join('') }}
<div :id="`list-${id}`"></div>
v-if判断真假
seen 的值的真假来显示 p元素
<p v-if="seen">Now you see me</p>
4、响应式
声明响应式状态
响应式对象其实是 JavaScript Proxy
export default {
data() {
return {
count: 1
}
},
// `mounted` 是生命周期钩子,之后我们会讲到
mounted() {
// `this` 指向当前组件实例
console.log(this.count) // => 1
// 数据属性也可以被更改
this.count = 2
}
}
声明方式
export default {
data() {
return {
count: 0
}
},
methods: {
increment() {
this.count++
}
},
mounted() {
// 在其他方法或是生命周期中也可以调用方法
this.increment()
}
}
//html
<button @click="increment">{{ count }}</button>
DOM 更新时机
DOM 更新完成,你可以使用 nextTick() 这个全局 API
import { nextTick } from 'vue'
export default {
methods: {
increment() {
this.count++
nextTick(() => {
// 访问更新后的 DOM
})
}
}
}
深层响应性
export default {
data() {
return {
obj: {
nested: { count: 0 },
arr: ['foo', 'bar']
}
}
},
methods: {
mutateDeeply() {
// 以下都会按照期望工作
this.obj.nested.count++
this.obj.arr.push('baz')
}
}
}
有状态方法
防抖的事件,限制项目中同一时间段内的连续click事件,防止前端触发多次事件
import { debounce } from 'lodash-es'
export default {
methods: {
// 使用 Lodash 的防抖函数
click: debounce(function () {
// ... 对点击的响应 ...
}, 500)
}
}
保持每个组件实例的防抖函数都彼此独立,我们可以改为在 created
生命周期钩子中创建这个预置防抖的函数:
export default {
created() {
// 每个实例都有了自己的预置防抖的处理函数
this.debouncedClick = _.debounce(this.click, 500)
},
unmounted() {
// 最好是在组件卸载时
// 清除掉防抖计时器
this.debouncedClick.cancel()
},
methods: {
click() {
// ... 对点击的响应 ...
}
}
}
5、计算属性
computed:计算属性值会基于其响应式依赖被缓存
export default{
data() {
return {
messages: 'Hello Vue!',
age:18,
isButtonDisabled:false,
};
},
computed:{//计算属性,有缓存
reverseMsg(){
return this.messages.split('').reverse().join('')
}
},
methods:{
reverseMessage(){
return this.messages.split('').reverse().join('')
}
},
}
//html
<p>{{ messages.split('').reverse().join('') }}</p>
<p>{{ reverseMsg }}computed计算属性</p>
<p>{{ reverseMessage() }}methods响应式</p>
可写计算属性
get() 和 set()方法
export default{
data() {
return {
messages: 'Hello Vue!',
age:18,
isButtonDisabled:false,
};
},
computed:{//计算属性,有缓存
reverseMsg:{
get(){//get是默认方法
return this.messages.split('').reverse().join('')
},
set(){
//set设置后显示方式
},
}
},
methods:{
reverseMessage(){
return this.messages.split('').reverse().join('')
}
},
}
6、watch侦听
export default {
data() {
return {
message: "你好",
age: 0,
user: {
name: "张三",
age: 18,
sex: "男",
},
};
},
methods: {},
watch: {
message:function(newValue,oldValue){
console.log(newValue);
console.log(oldValue);
//执行异步操作,或者复杂逻辑代码
if(newValue.length<5 || newValue.length>10){
console.log("输入框的内容不能小于5或者大于10");
}
}
},
}
深层侦听器
export default {
watch: {
someObject: {
handler(newValue, oldValue) {
// 注意:在嵌套的变更中,
// 只要没有替换对象本身,
// 那么这里的 `newValue` 和 `oldValue` 相同
},
deep: true
}
}
}
watch: {
"user.name": { //使用字符串的形式进行优化,只会单独监听对象中对应的属性
handler(newValue) {
console.log(newValue);
},
deep: true, //表示是否深度监听,侦听器会一层层的向下遍历,给对象每个属性都加上侦听器
},
},
即时回调的侦听器
watch: {
message: {
immediate: true, //初始化的时候即时调用函数
handler: function (newValue) {
console.log(newValue);
if (newValue.length < 5 || newValue.length > 10) {
console.log("输入框的内容不能小于5或者大于10");
}
},
},
},
7、Class 与 Style 绑定
对象语法
<div :class="{ active: isActive }"></div>
//或
data() {
return {
classObject: {
active: true,
'text-danger': false
}
}
},
computed: {
classObjectCom() {
return {
active: this.isActive && !this.error,
'text-danger': this.error && this.error.type === 'fatal'
}
}
}
//html
<div :class="classObjectCom"></div>
数组语法
data() {
return {
activeClass: 'active',
errorClass: 'text-danger'
}
}
//html
<div :class="[activeClass, errorClass]"></div>
//可以使用三元表达式
<div :class="[isActive ? activeClass : '', errorClass]"></div>
绑定内联样式
data() {
return {
activeColor: 'red',
fontSize: 30
}
}
//html
<div :style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
直接绑定一个样式对象通常是一个好主意,这样可以使模板更加简洁:
data() {
return {
styleObject: {
color: 'red',
fontSize: '13px'
}
}
}
//html
<div :style="styleObject"></div>
绑定数组
<div :style="[baseStyles, overridingStyles,{color: 'red'}]"></div>
//样式多值
<div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }"></div>
//数组仅会渲染浏览器支持的最后一个值。在这个示例中,在支持不需要特别前缀的浏览器中都会渲染为 display: flex
8、条件渲染
v-if
<h1 v-if="awesome">Vue is awesome!</h1>
v-else
<button @click="awesome = !awesome">Toggle</button>
<h1 v-if="awesome">Vue is awesome!</h1>
<h1 v-else>Oh no 😢</h1>
v-else-if
<div v-if="type === 'A'">
A
</div>
<div v-else-if="type === 'B'">
B
</div>
<div v-else-if="type === 'C'">
C
</div>
<div v-else>
Not A/B/C
</div>
template 上的 v-if最后渲染的结果并不会包含这个元素
<template v-if="ok">
<h1>Title</h1>
<p>Paragraph 1</p>
<p>Paragraph 2</p>
</template>
9、列表渲染
v-for
data() {
return {
yy: ['张三','李四','老刘']
}
}
//html
<li v-for="item in yy" :key="item">
{{ item }}
</li>
//key唯一标识,方便它跟踪每个节点的身份,快速找到这个节点,减少渲染次数
data() {
return {
xx: [{ message: 'Foo' }, { message: 'Bar' }]
}
}
//html
<li v-for="item in xx">
{{ item.message }}
</li>
//也支持使用可选的第二个参数index表示当前项的位置索引
<li v-for="(item, index) in xx">
{{ index }} - {{ item.message }}
</li>
v-for 与对象
data() {
return {
myObject: {
title: 'How to do lists in Vue',
author: 'Jane Doe',
publishedAt: '2016-04-10'
}
}
}
//html
<ul>
<li v-for="value in myObject">
{{ value }}
</li>
</ul>
//第二个参数表示属性名 (例如 key):
<li v-for="(value, key) in myObject">
{{ key }}: {{ value }}
</li>
//第三个参数表示位置索引(例如 index):
<li v-for="(value, key, index) in myObject">
{{ index }}. {{ key }}: {{ value }}
</li>
数组方法使用
this.list[5]='xx'
push()//给数组末尾添加元素
pop()//删除末尾元素
shift()//给数组的第一位进行删除
unshift()//给数组第一位添加元素
//splice本质是设定范围先删后插
splice()//删除元素、插入元素、替换元素:参数:1、开始位置下标 2、范围数量 3、插入元素
sort()//排序,默认按照字符串顺序对值从小到大进行排序
reverse()//反转元素顺序
使用案例
data() {
return {
yy: ['张三','李四','老刘']
}
},
methods:{
changList(){
this.yy[0]='九妹'
this.yy.push('老大','老二')
},
},
//html
<button @click="changList">改变按钮</button>
<button @click="this.yy.pop()">删除末尾按钮</button>
<button @click="this.yy.shift()">第一位进行删除按钮</button>
<button @click="this.yy.unshift('我是第一位老大')">第一位添加数据</button>
//splice本质是设定范围先删后插
<button @click="this.yy.splice(2,4)">splice删除[2]-[5]元素</button>
<button @click="this.yy.splice(2,0,'我插一个','我不要插入')">splice插入[2]后面元素</button>
<button @click="this.yy.splice(2,2,'我替换1','我替换2')">splice替换[2]后面元素</button>
<button @click="this.yy.sort()">排序</button>
<button @click="this.yy.reverse()">反转</button>
<li v-for="item in yy" :key="item">
{{ item }}
</li>
10、事件处理
事件修饰符
.stop//阻止其他父类单击事件
.prevent//阻止表单提交默认行为
.self
.capture
.once//只会触发一次
.passive
<!-- 单击事件将停止传递 -->
<a @click.stop="doThis"></a>
<!-- 提交事件将不再重新加载页面 -->
<form @submit.prevent="onSubmit"></form>
<!-- 修饰语可以使用链式书写 -->
<a @click.stop.prevent="doThat"></a>
<!-- 也可以只有修饰符 -->
<form @submit.prevent></form>
<!-- 仅当 event.target 是元素本身时才会触发事件处理器 -->
<!-- 例如:事件处理器不来自子元素 -->
<div @click.self="doThat">...</div>
<!-- 添加事件监听器时,使用 `capture` 捕获模式 -->
<!-- 例如:指向内部元素的事件,在被内部元素处理前,先被外部处理 -->
<div @click.capture="doThis">...</div>
<!-- 点击事件最多被触发一次 -->
<a @click.once="doThis"></a>
<!-- 滚动事件的默认行为 (scrolling) 将立即发生而非等待 `onScroll` 完成 -->
<!-- 以防其中包含 `event.preventDefault()` -->
<div @scroll.passive="onScroll">...</div>
按键修饰符
<!-- 仅在 `key` 为 `Enter` 时调用 `submit` -->
<input @keyup.enter="submit" />
<input @keyup.page-down="onPageDown" />
按键别名
Vue 为一些常用的按键提供了别名:
.enter
.tab
.delete (捕获“Delete”和“Backspace”两个按键)
.esc
.space
.up
.down
.left
.right
系统按键修饰符#
你可以使用以下系统按键修饰符来触发鼠标或键盘事件监听器,只有当按键被按下时才会触发。
.ctrl
.alt
.shift
.meta
.exact 修饰符允许控制触发一个事件所需的确定组合的系统按键修饰符。
鼠标按键修饰符#
.left
.right
.middle
举例
<!-- Alt + Enter -->
<input @keyup.alt.enter="clear" />
<!-- Ctrl + 点击 -->
<div @click.ctrl="doSomething">Do something</div>
<!-- 当按下 Ctrl 时,即使同时按下 Alt 或 Shift 也会触发 -->
<button @click.ctrl="onClick">A</button>
//.exact 修饰符允许控制触发一个事件所需的确定组合的系统按键修饰符。
<!-- 仅当按下 Ctrl 且未按任何其他键时才会触发 -->
<button @click.ctrl.exact="onCtrlClick">A</button>
<!-- 仅当没有按下任何系统按键时触发 -->
<button @click.exact="onClick">A</button>
11、表单输入绑定
v-model
//v-model
本质是两个操作
1、v-bind绑定一个value属性
2、v-on给当前元素添加一个input事件
<p>输入内容是: {{ message }}</p>
<input v-model="message" placeholder="输入内容" />
多行文本
//style="white-space: pre-line;"以保留textarea里面的格式,包括空格、回车、tab、换行
<span>多行文本展示:</span>
<p style="white-space: pre-line;">{{ message }}</p>
<textarea v-model="message" placeholder="输入内容"></textarea>
点选框
export default {
data() {
return {
checked: true
}
}
}
//html
<input type="checkbox" id="checkbox" v-model="checked" />
<label for="checkbox">{{ checked }}</label>
多选框
export default {
data() {
return {
checkedNames: []
}
}
}
//html
<div>选择有: {{ checkedNames }}</div>
<input type="checkbox" id="jack" value="苹果" v-model="checkedNames">
<label for="jack">苹果</label>
<input type="checkbox" id="john" value="梨子" v-model="checkedNames">
<label for="john">梨子</label>
<input type="checkbox" id="mike" value="香蕉" v-model="checkedNames">
<label for="mike">香蕉</label>
单选按钮
export default {
data() {
return {
picked: 'One'
}
}
}
//html
<div>单选按钮: {{ picked }}</div>
<input type="radio" id="one" value="One" v-model="picked" />
<label for="one">One</label>
<input type="radio" id="two" value="Two" v-model="picked" />
<label for="two">Two</label>
单个选择器
export default {
data() {
return {
selected: ''
}
}
}
//html
<div>下拉菜单单选择: {{ selected }}</div>
<select v-model="selected">
<option disabled value="">请选择</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
单选择
export default {
data() {
return {
selected: 'A',
options: [
{ text: 'One', value: 'A' },
{ text: 'Two', value: 'B' },
{ text: 'Three', value: 'C' }
]
}
}
}
//html
<select v-model="selected">
<option v-for="option in options" :value="option.value">
{{ option.text }}
</option>
</select>
<div>选择: {{ selected }}</div>
多选(按ctrl或下拉多个)
export default {
data() {
return {
selected: []
}
}
}
//html
<div>多选框: {{ selected }}</div>
<select v-model="selected" multiple>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<style>
select[multiple] {
width: 100px;
}
</style>
修饰符
v-model.lazy//在 "change" 事件后同步更新而不是 "input"
v-model.number//输入自动转换为数字
v-model.trim//默认自动去除用户输入内容中两端的空格
举例
<input v-model.lazy="message" placeholder="输入内容后确定就会变化" />
12、组件基础
定义在一个单独的 .vue
文件
//命名xo.vue
<script>
export default {
data() {
return {
count: 0
}
}
}
</script>
<template>
<button @click="count++">You clicked me {{ count }} times.</button>
</template>
//-------------------------------------
//使用组件
<script setup>
//引入xo组件
import xo from './components/Xo.vue'
</script>
//使用 <xo />
<template>
<h1>Here is a child component!</h1>
<xo />
</template>
传递数据 props
<!-- xo.vue -->
//props传递
<script>
export default {
props: ['title']
}
</script>
<template>
<h4>{{ title }}</h4>
</template>
//index
<xo title="My journey with Vue" />
<xo title="Blogging with Vue" />
<xo title="Why Vue is so fun" />
实际应用中,我们可能在父组件中会有如下的一个博客文章数组
export default {
// ...
data() {
return {
posts: [
{ id: 1, title: 'My journey with Vue' },
{ id: 2, title: 'Blogging with Vue' },
{ id: 3, title: 'Why Vue is so fun' }
]
}
}
}
//index
<xo
v-for="post in posts"
:key="post.id"
:title="post.title"
/>