Vue2基础语法
Vue2基础语法
【一】插值语法
- 语法:
{{ 变量、js语法、三目表达式 }}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>插值语法</title>
<!-- 此处我下在了本地-->
<script src="./js/vue/vue.js"></script>
<!-- 也可以使用cdn链接-->
<!-- <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.7.14/vue.min.js"></script>-->
</head>
<body>
<div id="app">
<ul>
<li>字符串:{{name}}</li>
<li>数值:{{age}}</li>
<li>数组:{{list1}}</li>
<li>对象:{{obj1}}</li>
<li>html标签字符串:{{link1}} <small>依旧以字符串形式显示</small></li>
<li>运算:{{10 + 20 + 30 + 40}}</li>
<li>三目运算符:{{10 > 20 ? '是' : '否'}}</li>
</ul>
</div>
</body>
<script>
var vm = new Vue({
el: '#app',
data: {
name: 'User', // 字符串
age: 18, // 数值
list1: [1,2,3,4], // 数组
obj1: {name: 'User', age: 18}, // 对象
link1: '<a href="https://www.baidu.com">百度一下 你就知道</a>'
},
methods: {},
computed: {}
})
</script>
</html>
【补】响应式
-
在 Vue 中,当你把一个普通的 JavaScript 对象传递给 Vue 实例作为数据对象时,Vue 将遍历此对象所有的属性,并使用
Object.defineProperty
把这些属性全部转为getter/setter
,这样 Vue 就能追踪数据的变化。 -
当数据发生变化时,所有依赖于该数据的地方都会自动更新,这包括 DOM 中绑定了该数据的元素。这种自动的响应式更新使得开发者无需手动操作 DOM,只需关注数据的变化即可。
-
值得注意的是,Vue 在初始化实例时会递归地将所有的属性转为 getter/setter,这使得 Vue 能够在数据被访问时添加依赖,从而在数据变化时通知更新。这也意味着,当你添加新属性时,它不会触发视图更新,因此需要提前声明所有的根级响应式属性。
简单来讲,当你修改Vue中的数据时,Dom上对应的元素将会改变
【二】指令
【1】 文本指令
指令 | 释义 |
---|---|
v-html | 让HTML渲染成页面 |
v-text | 标签内容显示js变量对应的值 |
v-show | 放1个布尔值:为真 标签就显示;为假 标签就不显示 |
v-if | 放1个布尔值:为真 标签就显示;为假 标签就不显示 |
v-show
与v-if
的区别:
- v-show:标签还在,只是不显示了(
display: none
)- v-if:直接操作DOM,删除/插入 标签
<body>
<div id="app">
<h2>文本指令</h2>
<ul>
<li v-text="name"></li>
<li v-text="age"></li>
<li v-text="list1"></li>
<li v-text="obj1"></li>
<li v-html="link1"></li>
<li v-show="1">show显示标签</li>
<li v-show="0">show隐藏标签</li>
<li v-if="1">if显示标签</li>
<li v-if="0">show删除标签</li>
</ul>
</div>
</body>
<script>
var vm = new Vue({
el: '#app',
data: {
name: 'User', // 字符串
age: 18, // 数值
list1: [1,2,3,4], // 数组
obj1: {name: 'User', age: 18}, // 对象
link1: '<a href="https://www.baidu.com">百度一下 你就知道</a>'
},
methods: {},
computed: {}
})
</script>
</html>
通过修改
li标签
属性展示v-show=false
的标签
【2】事件指令
指令 | 释义 |
---|---|
v-on | 触发事件 |
@ | 触发事件 |
@[event] | 触发event事件(可以是其他任意事件) |
例如:
v-on:click
可以缩写成@click
【2.1】常见的事件指令
- 常见的事件类型有
click
、input
、change
、mouseover
、keydown
等
<body>
<div id="app">
<h2>事件指令</h2>
<p>{{eventS}}</p>
<ul>
<li>
<button v-on:click="handleClick">点击事件</button>
</li>
<li><input type="text" @input="handleInput">input事件:输入的内容【{{stringI}}】</li>
<li><input type="text" @change="handleChange">change事件:修改的内容【{{stringC}}】</li>
<li><span @mouseover="handleOver" @mouseout="handleOut">悬浮事件</span></li>
<li>
<button @keydown="handleKD" @keyup="handleKO">键盘事件</button>
按下的键【{{keycode}}】
</li>
</ul>
</div>
</body>
<script>
var vm = new Vue({
el: '#app',
data: {
eventS: '事件名称',
stringI: '',
stringC: '',
keycode:''
},
methods: {
handleClick(event) {
this.eventS = '点击事件';
},
handleInput(event) {
this.eventS = 'input事件';
this.stringI = event.data;
console.log(event)
},
handleChange(event) {
this.eventS = 'change事件'
this.stringC = event.target.value
console.log(event)
},
handleOver(event) {
this.eventS = 'mouseover事件'
console.log(event)
},
handleOut(event) {
this.eventS = 'mouseout事件'
console.log(event)
},
handleKD(event) {
this.eventS = 'mousekeydown事件'
this.keycode=event.key
console.log(event)
},
handleKO(event) {
this.eventS = 'mousekeyon事件'
console.log(event)
}
},
computed: {}
})
</script>
【2.2】input标签的事件处理
# input 当输入框进行输入的时候 触发的事件
# change 当元素的值发生改变时 触发的事件
# blur 当输入框失去焦点的时候 触发的事件
# focus 当获得焦点的时候 触发的事件
<body>
<div id="app">
<h1>input事件</h1>
<input type="text" v-model="name1" @input="handleInput">-->{{name1}}
<h1>change事件</h1>
<input type="text" v-model="name2" @change="handleChange">-->{{name2}}
<h1>blur事件</h1>
<input type="text" v-model="name3" @blur="handleBlur">-->{{name3}}
<h1>focus事件</h1>
<input type="text" v-model="name4" @focus="handleFocus">-->{{name4}}
</div>
</body>
<script>
var vm = new Vue({
el: '#app',
data: {
name1: '',
name2: '',
name3: '',
name4: '提示信息',
},
methods: {
handleInput(event) {
console.log('输入的值:',event.data)
},
handleChange() {
console.log('handleChange:只有离开输入框,且内容发生变化才会触发,如果内容不变也不触发')
},
handleBlur() {
console.log('handleBlur:失去焦点触发')
},
handleFocus() {
console.log('Focus:获得焦点触发,可以执行清空输入框')
this.name4 = ''
}
},
computed: {}
})
</script>
【补】数据双向绑定v-model
# 1 针对 input 标签--》页面中输入值--》js中有对应变量
# 2 数据单向绑定:变量变,页面变 --》页面变,变量不会变
# 3 数据双向绑定:相互影响
<body>
<div id="app">
<h1>数据单向绑定</h1>
<input type="text" :value="name1">-----------> 通过插值语法查看值{{name1}}
<h1>数据双向绑定</h1>
<input type="text" v-model="name2">----------->{{name2}}
</div>
</body>
<script>
var vm = new Vue({
el: '#app',
data: {
name1: '',
name2: ''
},
methods: {},
computed: {}
})
</script>
【2.3】事件修饰符
- 在事件处理程序中调用
event.preventDefault()
或event.stopPropagation()
是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。 - 为了解决这个问题,Vue.js 为
v-on
提供了事件修饰符。之前提过,修饰符是由点开头的指令后缀来表示的。.stop
:阻止事件冒泡,即不再向上层元素派发事件。.prevent
:阻止事件的默认行为,例如阻止表单提交或者超链接跳转。.capture
:事件捕获模式,即事件将在捕获阶段触发,而不是在冒泡阶段触发。.self
:只有当事件是由元素自身触发时才触发事件处理函数,而不是子元素触发的。.once
:事件只会触发一次,即事件处理函数只会执行一次,之后便移除监听。.passive
:告诉浏览器不要阻止事件的默认行为,可以用来提升移动端的滚动性能。
使用修饰符时,顺序很重要;相应的代码会以同样的顺序产生。因此,用
v-on:click.prevent.self
会阻止所有的点击,而v-on:click.self.prevent
只会阻止对元素自身的点击。
事件冒泡:当一个事件发生在DOM元素上时,它会从最具体的元素(文档中嵌套层次最深的那个节点)开始向上逐级触发,直到触发到最顶层的文档对象(document对象)为止
【2.3.1】self和stop
<style>
.div1 {
width: 300px;
height: 300px;
}
.father {
background-color: #0d6efd;
}
.son {
background-color: #20c997;
}
</style>
<body>
<div id="app">
<div @click.self="handleFunc" class="div1 father">
<h2>@click.self 阻止父标签的冒泡事件</h2>
<p>当为事件指定self修饰符时,该事件只有当前标签触发</p>
<div @click.stop="handleFunc2" class="div1 son">
<h3>@click.stop 阻止子标签的冒泡事件</h3>
<p>当为事件指定stop修饰符时,该事件不会向上层元素派发事件,也就是不会触发click</p>
</div>
</div>
</div>
</body>
<script>
var vm = new Vue({
el: '#app',
data: {},
methods: {
handleFunc() {
alert('父标签的点击事件')
},
handleFunc2() {
alert('子标签的点击事件')
}
},
computed: {}
})
</script>
【2.3.2】once
<body>
<div id="app">
<div>
<p>{{count}}</p>
<p><button @click="handleCount">点击数字加1</button></p>
<p><button @click.once="handleCount">点击数字加1【仅触发一次】</button></p>
</div>
</div>
</body>
<script>
var vm = new Vue({
el: '#app',
data: {
count: 0
},
methods: {
handleCount() {
this.count += 1
}
},
computed: {}
})
</script>
【2.4】键盘事件的按键修饰符
<body>
<div id="app">
<h1>按键事件</h1>
<input type="text" v-model="keyname" @keyup="handleKeyUp">-->{{keyname}}
<hr>
<h2>按键修饰符</h2>
<input type="text" v-model="keyname2" @keyup.ctrl="handleKeyCtrl">-->{{keyname2}}
<br>
<h3>使用keycode对应码表</h3>
<input type="text" @keyup.65="handleKey13">
</div>
</body>
<script>
var vm = new Vue({
el: '#app',
data: {
keyname: '',
keyname2: '',
},
methods: {
handleKeyUp(event) {
console.log(event)
console.log('按下', event.key)
this.keyname = event.key
},
handleKeyCtrl() {
alert('按下了【ctrl】')
},
handleKey13() {
alert('按下了【A】')
}
},
computed: {}
})
</script>
【2.4】案例:过滤筛选
<body>
<div id="app">
<h1>过滤案例</h1>
<input type="text" v-model="myText" @input="handleInput">
<hr>
<ul>
<li v-for="item in newdataList">{{item}}</li>
</ul>
</div>
</body>
<script>
var vm = new Vue({
el: '#app',
data: {
myText: '',
dataList: ['a', 'at', 'atom', 'be', 'beyond', 'cs', 'csrf', 'atome', 'atomem'],
newdataList: ['a', 'at', 'atom', 'be', 'beyond', 'cs', 'csrf', 'atome', 'atomem'],
},
methods: {
handleInput(event) {
console.log(event)
this.newdataList = this.dataList.filter((item) => item.indexOf(this.myText) >= 0)
// this.dataList.filter((item) => 布尔值 : 数组过滤 array.filter(function(){return 布尔值})
// item.indexOf(this.myText) >= 0 : 如果不存在indexof返回【-1】
},
},
computed: {}
})
</script>
【3】属性指令
- 为标签动态属性
指令 | 释义 |
---|---|
v-bind | 直接写js的变量或语法 |
: | 直接写js的变量或语法 |
例如:
v-bind:class='js变量'
可以缩写成::class='js变量'
【3.1】属性
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>属性指令</title>
<script src="../js/vue/vue.js"></script>
</head>
<body>
<div id="app">
<div>
<!-- 所有的属性都可以用v-bind或【:】-->
<div v-bind:id="idDiv"></div>
<img :src="imgUrl" :alt="">
<a :href="imgUrl">跳转</a>
</div>
</div>
</body>
<script>
var vm = new Vue({
el: '#app',
data: {
imgUrl: 'https://pic.netbian.com/uploads/allimg/240105/002731-17043856512195.jpg',
idDiv: '1'
},
methods: {},
computed: {}
})
</script>
</html>
【3.2】style属性和class属性
- 都是可以使用三种形式来进行属性的指定
- 字符串
- 数组:对于class属性,数组是最适合的
- 对象:对于style属性,对象是最适合的
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>属性指令</title>
<script src="../js/vue/vue.js"></script>
</head>
<style>
.div1 {
height: 300px;
width: 300px;
background-color: #0a53be;
}
.div2 {
height: 300px;
width: 300px;
background-color: #0a53be;
}
.div3 {
height: 300px;
width: 300px;
background-color: #0a53be;
}
</style>
<body>
<div id="app">
<h2>style属性三种方式</h2>
<div style="display: flex;justify-content: space-around">
<div v-bind:style="styleStr">
<p>style属性:str</p>
</div>
<div :style="styleList">
<p>style属性:list</p>
</div>
<div :style="styleObj">
<p>style属性:obj</p>
</div>
</div>
<hr>
<h2>class属性的三种方式</h2>
<div style="display: flex;justify-content: space-around">
<div :class="classStr">
<p>class属性:str</p>
</div>
<div :class="classList">
<p>class属性:list</p>
</div>
<div :class="classObj">
<p>class属性:obj</p>
</div>
</div>
</div>
</body>
<script>
var vm = new Vue({
el: '#app',
data: {
// 字符串形式
styleStr: 'width: 300px;height: 300px;background-color: #c5e8ef',
// 数组形式 : [{},{},{}]
styleList: [{width: '300px'}, {height: '300px'}, {backgroundColor: '#c5e8ef'}],
// 对象形式 : {k:v,k:v} // 对于style,对象是最适合的
styleObj: {width: '300px', height: '300px', backgroundColor: '#c5e8ef'},
// 字符串形式
classStr: 'div1 div2 div3',
// 数组形式 ['','',''] // 对于class,数组是最适合的
classList: ['div1', 'div2', 'div3'],
// 对象形式 {k:true/false,k:true/false}
classObj: {div1: true, div2: true, div3: true},
},
methods: {},
computed: {}
})
</script>
</html>
【3.3】案例:使用点击事件动态修改样式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>属性指令</title>
<script src="../js/vue/vue.js"></script>
</head>
<style>
.div1 {
height: 300px;
width: 300px;
background-color: #0a53be;
}
.div2 {
height: 300px;
width: 300px;
background-color: #0a53be;
}
.div3 {
height: 300px;
width: 300px;
background-color: #0a53be;
}
.div_add {
font-size: 50px;
font-family: FangSong;
}
</style>
<body>
<div id="app">
<h2>style属性三种方式</h2>
<div style="display: flex;justify-content: space-around">
<div v-bind:style="styleStr">
<p>style属性:str</p>
</div>
<div :style="styleList">
<p>style属性:list</p>
</div>
<div :style="styleObj">
<p>style属性:obj</p>
</div>
</div>
<hr>
<h2>class属性的三种方式</h2>
<div style="display: flex;justify-content: space-around">
<div :class="classStr">
<p>class属性:str</p>
</div>
<div :class="classList">
<p>class属性:list</p>
</div>
<div :class="classObj">
<p>class属性:obj</p>
</div>
</div>
<h2>使用点击事件动态修改样式</h2>
<div>
<p>
<button @click="handleStyle">添加样式</button>
</p>
</div>
</div>
</body>
<script>
var vm = new Vue({
el: '#app',
data: {
// 字符串形式
styleStr: 'width: 300px;height: 300px;background-color: #c5e8ef',
// 数组形式 : [{},{},{}]
styleList: [{width: '300px'}, {height: '300px'}, {backgroundColor: '#c5e8ef'}],
// 对象形式 : {k:v,k:v} // 对于style,对象是最适合的
styleObj: {width: '300px', height: '300px', backgroundColor: '#c5e8ef'},
// 字符串形式
classStr: 'div1 div2 div3',
// 数组形式 ['','',''] // 对于class,数组是最适合的
classList: ['div1', 'div2', 'div3'],
// 对象形式 {k:true/false,k:true/false}
classObj: {div1: true, div2: true, div3: true},
},
methods: {
handleStyle() {
// 字符串添加 样式 或 类
// 对于样式,需要在前面添加【;】做分割
this.styleStr += ';border-radius: 50%;'
// 对于类 需要在前面添加空格【 】
this.classStr += ' div_add'
// 数组添加 // 数组添加可以使用push 或 +=
this.styleList.push({borderRadius: '50%'})
this.classList.push('div_add')
// 对象添加
this.styleObj['borderRadius'] = '50%'
this.classObj['div_add'] = true
}
},
computed: {}
})
</script>
</html>
【3.4】注意:修改样式未生效的情况
- Vue 的响应式系统无法自动检测到对数组元素或对象属性的直接赋值(例如
arr[0] = newValue
或obj.key = newValue
)。 - Vue 的响应式系统是基于 JavaScript 属性的 getter 和 setter 实现的,而直接的索引赋值或添加新属性不会触发 setter。
- Vue 文档中有提到一些方法,如
Vue.set
或使用Array.prototype.splice
,来处理这些限制,确保响应式系统能够检测到所有的更新。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>vue set 修改样式</title>
<script src="../js/vue/vue.js"></script>
</head>
<style>
.div1 {
height: 300px;
width: 300px;
background-color: #0a53be;
}
.div2 {
height: 300px;
width: 300px;
background-color: chartreuse;
}
</style>
<body>
<div id="app">
<div style="display: flex;justify-content: space-around">
<div>
<h1>样式不生效的情况</h1>
<div :class="classList"></div>
<p>
<button @click="handleClass">修改样式</button>
</p>
</div>
<div>
<h1>使用Vue.set使样式生效</h1>
<h2>共有很多种方法可以使虚拟dom触发更新</h2>
<p>【1】数组中:Vue.set(数组,索引,修改的值)</p>
<p>【1.1】对象中:Vue.set(对象,属性名,修改的值)</p>
<p>【2】vm.$set:与Vue.set用法一致</p>
<p>【3】调用变更方法,会触发更新</p>
<div :class="classList2"></div>
<p>
<button @click="handleClass2">使用【Vue.set】修改样式</button>
</p>
</div>
</div>
</div>
</body>
<script>
var vm = new Vue({
el: '#app',
data: {
classList: ['div1'],
classList2: ['div1']
},
methods: {
handleClass() {
// 修改class值
this.classList[0] = 'div2'
// 值已经改变了,但没能即时生效
console.log('classList',this.classList)
},
handleClass2() {
// 会触发响应式更新的修改操作
// 使用Vue.set
Vue.set(this.classList2, 0, 'div2')
// 使用vm.$set
vm.$set(this.classList2, 0, 'div1')
// 调用数组的变更方法
this.classList2.splice(0, 1, 'div2')
console.log('classList2', this.classList2)
}
},
computed: {}
})
</script>
</html>
- 需要注意,当我们点击前面一个样式不生效的情况时,在dom上,它的值已经被改变了,只是没能更新
当我们触发了vue的响应式更新时,将会查看页面上修改了的dom属性,并更新
【三】流程控制
【1】条件渲染v-if
v-else-if
v-else
指令 | 释义 |
---|---|
v-if | 相当于: if |
v-else | 相当于:else |
v-else-if | 相当于:else if |
【1.2】案例:根据分数判断评价
- 将
v-if
v-else-if
v-else
包裹的标签视作一个标签即可,因为只有一个条件会符合条件 - 【注】单独的
v-if
是允许出现的,因为就是判断布尔值决定标签是否渲染v-else-if
v-else
是不允许单独出现的
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>流程控制</title>
<script src="../js/vue/vue.js"></script>
</head>
<body>
<div id="app">
<p>姓名:{{name}}</p>
<p>分数:{{score}}</p>
<p>评价:【
<span v-if="score === 100">满分</span>
<span v-else-if="score > 90">优秀</span>
<span v-else-if="score > 80">良好</span>
<span v-else-if="score > 60">合格</span>
<span v-else>不合格</span>
】</p>
</div>
</body>
<script>
var vm = new Vue({
el: '#app',
data: {
name: 'user',
// 随机生成数字
score: Math.floor(Math.random() * 100),
},
methods: {
// 创建函数 方便演示时在前端生成分数
handleScore(){
this.score = Math.floor(Math.random() * 100)
}
},
computed: {}
})
</script>
</html>
【2】遍历渲染v-for
【2.1】遍历数组 遍历对象 遍历数字
<body>
<div id="app">
<h1>v-for:数组</h1>
<!-- 遍历数组产生两个值,对象+索引-->
<!-- 如果只需要使用对象可以不加括号-->
<!-- v-for="item in dataList"-->
<ul v-for="(item,index) in dataList">
<li>item:{{item}}|index:{{index}}</li>
</ul>
<h1>v-for:对象</h1>
<!-- 遍历数组可以产生三个值,对象的值+对象的键+索引-->
<ul v-for="(value,key,index) in dataObj">
<li>对象的值:{{value}} |对象的键:{{key}} | 对象的索引:{{index}}</li>
</ul>
<h2>v-for:对象,单个值【遍历出每一个item的值】</h2>
<ul v-for="value in dataObj">
<li>对象的值:{{value}}</li>
</ul>
<h1>v-for:数字</h1>
<!-- 遍历数字与python中的for i in range(num)差不多,不过首位是1-->
<ul v-for="item in num">
<li>{{item}}</li>
</ul>
</div>
</body>
<script>
var vm = new Vue({
el: '#app',
data: {
// 数组
dataList: [1, 2, 3],
// 对象
dataObj: {num1: 6, num2: 4, num3: 13},
// 数字
num: 5
},
methods: {},
computed: {}
})
</script>
【4】案例
【4.1】v-if
+v-for
+v-else
控制购物车商品的显示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>v-if + v-for + v-else控制购物车商品的显示</title>
<script src="../js/vue/vue.js"></script>
<link rel="stylesheet" href="../css/bootstrap/bootstrap.css">
<script src="../js/bootstrap/bootstrap.js"></script>
</head>
<body>
<div id="box">
<h2 class="text-center">我的购物车</h2>
<!-- 点击按钮后,将购物车信息赋值给shopping-car-->
<button @click="show">展示购物车</button>
<br>
<!-- 如果有商品渲染商品-->
<table v-if="!shopping_car.length==0" class="table table-hover">
<tr>
<td>商品名称</td>
<td>价格</td>
</tr>
<tr v-for="item in shopping_car">
<td>{{item.name}}</td>
<td>{{item.price}}</td>
</tr>
</table>
<!-- 没有商品显示没有商品信息-->
<table v-else class="table table-hover">
<tr>
<td>商品名称</td>
<td>价格</td>
</tr>
<tr>
<td>暂无信息</td>
<td>暂无信息</td>
</tr>
</table>
</div>
</body>
<script>
let vm = new Vue({
el: '#box',
data: {
isActive: false,
shopping_car: []
},
methods: {
show() {
if (this.shopping_car.length) {
this.shopping_car = []
} else {
this.shopping_car = [
{name: '华为-遥遥领先', price: '2999元'},
{name: '苹果', price: '9元'},
{name: '小米', price: '999元'},
]
}
}
}
})
</script>
</html>
【5】其他知识(了解)
【5.1】更新策略
- Vue.js 在使用
v-for
渲染元素列表时的更新策略。 - 在默认情况下,Vue 使用 "就地更新" 策略。这意味着当数据项的顺序改变时,Vue 不会移动 DOM 元素以匹配数据项的新顺序,而是会就地更新每个元素,确保它们在 DOM 中的位置与数据项的索引位置相对应。换句话说,Vue 会尽可能地复用已经存在的 DOM 元素,而不是重新创建或移动它们。
- 这种更新策略的好处是,在处理大型列表时能够更高效地进行 DOM 操作,因为不会频繁地创建、销毁或移动元素,而只是更新已存在的元素。这也可以提高性能并减少浏览器重新渲染的工作量,从而提升用户体验。
- 类似于 Vue 1.x 中的
track-by="$index"
,Vue.js 在更新列表时会跟踪每个元素的索引位置,以便正确地应用 "就地更新" 策略。这意味着你不需要手动指定索引,Vue 会自动处理好这些细节。
【5.2】优化数据效率参数key
-
vue中使用的是虚拟DOM,会和原生的DOM进行比较,然后进行数据的更新,提高数据的刷新速度(虚拟DOM用了diff算法)
-
在
v-for
循环数组、对象
时,建议在控件/组件/标签
写1个key属性
,属性值唯一 -
页面更新之后,会加速DOM的替换(渲染)
-
:key="变量"
-
【四】数组更新
【1】变更方法
- 变更方法,顾名思义,会变更调用了这些方法的原始数组
- Vue.js 在响应式地处理数组时,对数组的一些常用变更方法进行了包装,以便能够自动检测到数组的变化,并触发相应的视图更新。这些被包裹过的方法包括:
- push(): 将一个或多个元素添加到数组的末尾,并返回新的长度。
- pop(): 移除数组的最后一个元素,并返回该元素的值。
- shift(): 移除数组的第一个元素,并返回该元素的值,同时将数组长度减一。
- unshift(): 在数组的开头添加一个或多个元素,并返回新的长度。
- splice(): 在指定位置插入或删除元素,并返回被删除的元素组成的数组。
- sort(): 对数组元素进行排序,如果没有传递比较函数,则默认按照 Unicode 码点进行排序。
- reverse(): 将数组中的元素顺序颠倒,第一个元素变为最后一个,最后一个元素变为第一个。
- 这些方法被 Vue.js 包装后,当你使用它们修改数组时,Vue.js 将能够侦测到数组的变化,并在必要时更新视图,以确保视图与数据的同步。这是 Vue.js 实现响应式的重要特性之一,使得开发者可以更轻松地处理数据的变化并实时更新用户界面。
【2】非变更方法
- 非变更方法,它们不会变更原始数组,而总是返回一个新数组。
- 当使用非变更方法时,可以用新数组替换旧数组
Vue 使用一些智能的启发式方法(如虚拟 DOM 的 diff 算法)来尽可能重用现有的 DOM 元素,从而提高性能和效率。这意味着,即使整个数组被替换,如果新数组中包含与旧数组相同的元素,Vue 将尽量保持这些元素的 DOM 表示不变。
- 常见的非变更方法及其功能:
- filter():
- 功能:创建一个新数组,其中包含通过某个函数测试的所有元素。
- concat():
- 功能:用于合并两个或多个数组。不会改变现有数组,而是返回一个新数组。
- slice():
- 功能:从现有数组中返回选定的元素。不会改变现有数组。
【3】变更方法与非变更方法实例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>数组更新</title>
<script src="../js/vue/vue.js"></script>
</head>
<body>
<div id="app">
<h1>数组更新</h1>
<ul v-for="item in dataList">
<li>{{item}}</li>
</ul>
</div>
</body>
<script>
var vm = new Vue({
el: '#app',
data: {
dataList: [2, 1, 9],
},
methods: {
// 变更方法
handlePush() {
this.dataList.push(22)
},
handlePop() {
this.dataList.pop()
},
handleSort() {
this.dataList.sort()
},
// 非变更方法
handleFilter() {
// filter 方法返回布尔值 根据布尔值判断是否显示
// 不改变原数组 // 需要声明一个新的变量或重新赋值
return this.dataList.filter(
item => item < 5
)
}
},
computed: {}
})
</script>
</html>
【五】表单控制
【1】checkbox和radio
- 当数据绑定的值为字符串时,接收一个值
- 当数据绑定的值为数组时,接收多个值
<body>
<div id="app">
<form>
<p> 用户名: <input type="text" v-model="username"></p>
<p>
爱好:【checkbox:数组】
<input type="checkbox" v-model="hobby" value="0">爱好1
<input type="checkbox" v-model="hobby" value="1">爱好2
<input type="checkbox" v-model="hobby" value="2">爱好3
</p>
<p>
性别: 【radio:字符串】
<input type="radio" v-model="gender" value="0">女
<input type="radio" v-model="gender" value="1">男
</p>
<p>
是否记住:【checkbox:字符串/布尔值】
<input type="checkbox" v-model="is_remember">
</p>
</form>
<hr>
<div>
<p>
信息如下:
username : {{username}} <br>
hobby : {{hobby}} <br>
gender : {{gender}} <br>
is_remember : {{is_remember}} <br>
</p>
</div>
</div>
</body>
<script>
var vm = new Vue({
el: '#app',
data: {
username: '',
hobby: [],
gender: '',
is_remember: true
},
methods: {},
computed: {}
})
</script>
【2】购物车案例
【2.1】前端
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="./js/vue/vue.js"></script>
<script src="./js/bootstrap/bootstrap.js"></script>
<link rel="stylesheet" href="./css/bootstrap/bootstrap.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css">
</head>
<body>
<div id="app">
<div class="container text-center">
<h1>{{username}}购物车</h1>
<div class="row justify-content-md-center">
<div class="col-6">
<table class="table table-hover">
<thead>
<tr>
<th scope="col">商品id</th>
<th scope="col">商品名称</th>
<th scope="col">商品价格</th>
<th scope="col">商品数量</th>
<th scope="col">全选/全不选
<span><input type="checkbox" @change="checkAll" v-model="isAll"></span>
</th>
</tr>
</thead>
<tbody>
<tr v-for="item in goodsList" v-if="item.count !== 0">
<td>{{item.id}}</td>
<td>{{item.name}}</td>
<td>{{item.price}}</td>
<td>
<!-- <button class="bi bi-dash" @click="dwindleCount(item)"></button>-->
<button class="btn" @click="item.count>1?item.count--:item.count=1">-</button>
{{item.count}}
<button class="btn" @click="item.count++">+</button>
</td>
<td>
<input type="checkbox" @click="checkOne" v-model="goodsCheck"
:value="item" @change="checkOne">
</td>
</tr>
</tbody>
</table>
<div>
<p>gross:{{goodTotal}}</p>
<button class="btn btn-success" @click="goodsSubmit">提交</button>
</div>
</div>
</div>
</div>
</div>
</body>
<script>
var vm = new Vue({
el: '#app',
data: {
username:'',
isAll: false,
goodsList:[],
goodsCheck: []
},
methods: {
// 提交数据
goodsSubmit() {
console.log(this.goodsCheck)
alert('提交了数据')
},
// 全选或全不选
checkAll() {
if (this.isAll) {
this.goodsCheck = this.goodsList
} else {
this.goodsCheck = []
}
},
// 选中单个
checkOne() {
// 如果选中的商品长度与所有商品长度一致代表选中了所有商品
this.isAll = this.goodsCheck.length === this.goodsList.length;
},
// 减少数量
dwindleCount(item) {
if (item > 1) {
item.count--
} else {
item.count = 1;
alert('最低数量为1')
}
}
},
computed: {
// 计算属性
goodTotal() {
let total = 0
for (let item of this.goodsCheck) {
total += item.price * item.count
}
return total
}
},
created() {
fetch('http://127.0.0.1:5000/cart/1/').then(response => response.json()).then(
res => {
console.log(res)
this.username=res.username
this.goodsList = res.result
}
)
}
})
</script>
</html>
【2.2】后端(flask)
import json
from flask import Flask, jsonify
app = Flask(__name__)
@app.route('/')
def index():
res = jsonify({
'code': 100,
'msg': 'success',
'result': {
'name': 'lea4ning',
'age': 20
}
})
res.headers['Access-Control-Allow-Origin'] = '*'
return res
@app.route('/cart/1/')
def get_cart():
with open('../goods.json', 'r', encoding='utf-8') as f:
data = json.load(f)
res = jsonify({
'code': 100,
'msg': 'success',
'username': 'lea4ning',
'result': data
})
res.headers['Access-Control-Allow-Origin'] = '*'
return res
if __name__ == '__main__':
app.run()
- ../goods.json
[
{
"id": 101,
"name": "HuaWei",
"price": 7999,
"count": 3
},
{
"id": 102,
"name": "apple",
"price": 7998,
"count": 1
},
{
"id": 103,
"name": "Xiaomi",
"price": 3999,
"count": 3
},
{
"id": 104,
"name": "Oppo",
"price": 1230,
"count": 6
}
]