- 参考视频:https://www.bilibili.com/video/av89760569
- 源码和markdown下载:https://github.com/tanglei302wqy/notes/tree/master/vue
- 欢迎star、fork、follow素质三连
前端开发过程中,需要监听各种事件:点击、拖拽、键盘事件等,在Vue中使用v-on进行事件监听,v-on可以使用**@**语法糖进行简化:
<body>
<div id="div1">
{{counter}}
<button @click="increment">+button>
<button @click="decrement">-button>
div>
body>
<script>
const app = new Vue({
el: "#div1",
data: {
counter: 0
},
methods: {
increment() {
this.counter++;
},
decrement() {
this.counter--;
}
}
});
script>
当函数没有参数时,()可以加也可以不加
当函数有一个参数,但是调用时并没有传递参数,默认会将屏幕原生事件event传递过去
当需要同时传递屏幕原生事件和自定义参数时,使用**$event**表示屏幕原生自定义事件
<body>
<div id="div1">
<button @click="func1()">btn1button>
<button @click="func1">btn2button>
<button @click="func2">btn3button>
<button @click="func3(1, $event)">btn4button>
div>
body>
<script>
const app = new Vue({
el: "#div1",
data: {},
methods: {
func1() {
console.log("func1");
},
func2(event) {
console.log("++++++++", event);
},
func3(args, event) {
console.log("++++++++", args, event);
}
}
});
script>
Vue提供了一些修饰符可以方便的处理事件调用:
注意:
<body>
<div id="div1" @click="divClick">
msg <button @click.stop="btnClick">stopbutton>
<form action="foo url">
<input type="submit" value="提交" @click.prevent.stop="formClick" />
form>
<input type="text" @keyup.enter="textKeyUp" />
<button @click.once.stop="btnOnceClick">oncebutton>
div>
body>
<script>
const app = new Vue({
el: "#div1",
data: {},
methods: {
divClick() {
console.log("div click");
},
btnClick() {
console.log("stop");
},
formClick() {
// 手动提交,并且会阻止submit默认的提交行为,可以在这里自定义数据处理逻辑
console.log("prevent");
},
textKeyUp() {
console.log("enter");
},
btnOnceClick() {
console.log("once");
}
}
});
script>
v-if和v-else相当于if-else条件判断:
<body>
<div id="div1">
<h2 v-if="flag">v-ifh2>
<h2 v-else>v-elseh2>
div>
body>
<script>
const app = new Vue({
el: "#div1",
data: {
flag: true
}
});
script>
v-else-if相当于if-else-if,但是实际中并不推荐这种形式,因为它会直接在标签中进行判断,应该优先考虑使用计算属性:
<body>
<div id="div1">
<h2 v-if="score >= 90">优秀h2>
<h2 v-else-if="score >= 80">良好h2>
<h2 v-else-if="score >= 60">及格h2>
<h2 v-else>不及格h2>
<h1>{{result}}h1>
div>
body>
<script>
const app = new Vue({
el: "#div1",
data: {
score: 99
},
computed: {
result() {
let result = "";
if (this.score >= 90) {
result = "优秀";
} else if (this.score >= 80) {
result = "良好";
} else if (this.score >= 60) {
result = "及格";
} else {
result = "不及格";
}
return result;
}
}
});
script>
用户可以使用:用户名和邮箱进行登录,现在实现一个功能,点击按钮后切换不同的登录功能:
<body>
<div id="div1">
<span v-if="isUserLogin">
<label for="username">用户登录label>
<input type="text" placeholder="用户名" id="username" key="username" />
span>
<span v-else>
<label for="email">邮箱登录label>
<input type="text" placeholder="邮箱" id="email" key="email" />
span>
<button @click="isUserLogin=!isUserLogin">切换登录类型button>
div>
body>
<script>
const app = new Vue({
el: "#div1",
data: {
isUserLogin: true
}
});
script>
在上面案例中:如果我们现在input中输入了内容,然后点击切换按钮切换到另一种登录方式时,此时input框中仍然保留着之前输入的内容。
v-show和v-if非常相似,用于决定一个元素是否显示,v-show和v-if主要区别:
使用场景:
<body>
<div id="div1">
<h2 v-if="isShow" id="vif">isShowh2>
<h2 v-show="isShow" id="vshow">isShowh2>
div>
body>
<script>
const app = new Vue({
el: "#div1",
data: {
isShow: true
}
});
script>
v-for用于遍历,可以直接遍历数组,也可以遍历对象:
<body>
<div id="div1">
<ul>
<li v-for="(name, idx) in names">{{idx+1}}: {{name}}li>
ul>
<ul>
<li v-for="(val, key, idx) in info">
{{idx+1}}: {{key}}-{{val}}
li>
ul>
div>
body>
<script>
const app = new Vue({
el: "#div1",
data: {
names: ["sherman", "wqy", "tl", "gantlei"],
info: {
name: "sherman",
age: 23,
height: 1.76
}
}
});
script>
官方推荐在使用v-for时,给对应的元素或者组件添加行:key属性。在需要向数组中插入一个新元素时,默认的Diff算法会依次更新待插入元素位置之后的所有元素,然后在末尾添加一个元素,并更新最后一个元素,达到插入的效果,这种Diff算法是非常低效的。
如果使用key来给每个节点做一个唯一标识,Diff算法就可以正确地识别该节点,找到正确的位置并插入。
因此:key属性的作用就是高效的更新VDOM。
推荐文章链接:
<div id="div1">
<ul>
<li v-for="(name, idx) in names" :key="name">{{idx+1}}: {{name}}li>
ul>
div>
Vue是响应式的,当数组数据发生变化时,Vue能够监听到变化,并且在页面上做出相应更新操作。对于绝大数数组操作都是响应式的:
数组非响应式写法:this.arr[0] = “change”,注意这种基于下标的方式更新,Vue并不会监听。替代方案:
- {{item}}
<html>
<title>购物车案例title>
<head>
<meta charset="utf-8" />
<link rel="stylesheet" href="style.css" />
head>
<body>
<div id="app">
<div v-if="books.length">
<table>
<thead>
<tr>
<th>th>
<th>书籍名称th>
<th>出版日期th>
<th>价格th>
<th>数量th>
<th>操作th>
tr>
thead>
<tbody>
<tr v-for="(book, idx) in books">
<td>{{book.id}}td>
<td>{{book.name}}td>
<td>{{book.date}}td>
<td>{{book.price | finalPrice}}td>
<td>
<button
@click="decrement(idx)" v-bind:disabled="book.count <= 1">-button>
{{book.count}}
<button @click="increment(idx)">+button>
td>
<td>
<button @click="removeHandle(idx)">移除button>
td>
tr>
tbody>
table>
<h2>总价格:{{totalPrice | finalPrice}}h2>
div>
<div v-else>
<h2>购物车为空!h2>
div>
div>
<script src="../../js/vue.js">script>
<script src="main.js">script>
body>
html>
table {
border: 1px solid #e9e9e9;
border-collapse: collapse;
border-spacing: 0;
}
th,
td {
padding: 8px 16px;
border: 1px solid #a39797;
text-align: left;
}
th {
background-color: #f7f7f7;
color: #5c6b77;
font-weight: 600;
}
const app = new Vue({
el: '#app',
data: {
books: [
{
id: 1,
name: "算法导论",
date: "2006-01",
price: 85.0,
count: 1
},
{
id: 2,
name: "算法",
date: "2008-01",
price: 75.0,
count: 1
},
{
id: 3,
name: "Unix编程艺术",
date: "2010-03",
price: 105.3,
count: 2
},
{
id: 4,
name: "Java编程思想",
date: "2003-01",
price: 100.5,
count: 1
}
]
},
filters: {
finalPrice(price) {
return "¥" + parseFloat(price).toFixed(2);
}
},
methods: {
decrement(idx) {
this.books[idx].count--;
},
increment(idx) {
this.books[idx].count++;
},
removeHandle(idx) {
this.books.splice(idx, 1);
}
},
computed: {
totalPrice() {
let res = 0.0;
for (let i = 0; i < this.books.length; ++i) {
res += this.books[i].count * this.books[i].price;
}
return res;
}
},
});
过滤器也是Options入参的可选项,本质上还是一个函数,用法:变量 | filter,变量会被当做过滤器的入参:
filters: {
finalPrice(price) {
return "¥" + parseFloat(price).toFixed(2);
}
}
// html
<td>{{book.price | finalPrice}}</td>
当商品的数量为1时,此时不能再进行减操作,可以禁用button:
<button @click="decrement(idx)" v-bind:disabled="book.count <= 1">-button>
当删除购物车中所有商品时,应该显示提示:购物车为空。可以将之前购物车的逻辑放入到一个div标签中,并通过v-if来判断books.length是否大于0,在通过v-else来显示提示内容:
<div id="app">
<div v-if="books.length">
...
div>
<div v-else>
购物车为空!
div>
div>
点击+按钮对应商品数量增加,点击-按钮对应商品数量减少,点击移除,对应商品行消失:
methods: {
decrement(idx) {
this.books[idx].count--;
},
increment(idx) {
this.books[idx].count++;
},
removeHandle(idx) {
this.books.splice(idx, 1);
}
}
购物车总价格可以通过计算属性来获取:
computed: {
totalPrice() {
let res = 0.0;
for (let i = 0; i < this.books.length; ++i) {
res += this.books[i].count * this.books[i].price;
}
return res;
}
},
for循环在es6中可以简写:
// 注意这种方式i let idx in ...,idx是索引
let res = 0.0;
for (let idx in this.books) {
res += this.books[idx].count * this.books[idx].price;
}
return res;
let res = 0.0;
for (let item of this.books) {
res += item.count * item.price;
}
return res;
高阶函数reduce:
// 标准写法
return this.books.reduce(function (pre, book) {
return pre + book.price * book.count;
}, 0);
// =>简写形式
return this.books.reduce((pre, book) => { return pre + book.price * book.count }, 0);
表单控件在实际开发中非常常见,特别是用户信息的提交,需要大量的表单。Vue使用v-model指令来实现表单元素和数据的双向绑定。
<body>
<div id="div1">
<input v-model="message">
{{message}}
input>
div>
body>
<script>
const app = new Vue({
el: '#div1',
data: {
message: 'sherman'
}
});
script>
对于上面的标签和message之间的双向绑定,其实相当于两个命令:
<body>
<div id="div1">
<input @input="message=$event.target.value" :value="message" />
{{message}}
div>
body>
v-model绑定绑定某个属性时(例如sex)正好能形成互斥效果,和radio功能类似:
<body>
<div id="div1">
<label for="male">
<input type="radio" id="male" name="sex" value="男" v-model="sex" />男
label>
<label for="female">
<input type="radio" id="female" name="sex" value="女" v-model="sex" />女
label>
<h2>您选择的性别是:{{sex}}h2>
div>
body>
<script>
const app = new Vue({
el: "#div1",
data: {
sex: "男"
}
});
script>
<body>
<div id="div1">
<label for="license">
<input type="checkbox" id="license" v-model="isAgree">同意协议label>
label>
<h2>是否同意协议:{{isAgree}}h2>
<button :disabled="!isAgree">下一步button>
div>
body>
<script>
const app = new Vue({
el: "#div1",
data: {
isAgree: false,
}
});
script>
<body>
<div id="div1">
<label for="play">
<input type="checkbox" id="play" value="play" v-model="hobbies">play
label>
<label for="music">
<input type="checkbox" id="music" value="music" v-model="hobbies">music
label>
<label for="eat">
<input type="checkbox" id="eat" value="eat" v-model="hobbies">eat
label>
<label for="sleep">
<input type="checkbox" id="sleep" value="sleep" v-model="hobbies">sleep
label>
<h2>您的爱好是:{{hobbies}}h2>
div>
body>
<script>
const app = new Vue({
el: "#div1",
data: {
hobbies: []
}
});
script>
<body>
<div id="div1">
<select id="fruit" name="fruit" v-model="fruit">
<option name="香蕉">香蕉option>
<option name="苹果">苹果option>
<option name="榴莲">榴莲option>
<option name="葡萄">葡萄option>
select>
<h2>您选择的水果是:{{fruit}}h2>
div>
body>
<script>
const app = new Vue({
el: "#div1",
data: {
fruit: "榴莲"
}
});
script>
<body>
<div id="div1">
<select id="fruits" name="fruits" v-model="fruits" multiple>
<option name="香蕉">香蕉option>
<option name="苹果">苹果option>
<option name="榴莲">榴莲option>
<option name="葡萄">葡萄option>
select>
<h2>您选择的水果是:{{fruits}}h2>
div>
body>
<script>
const app = new Vue({
el: "#div1",
data: {
fruits: []
}
});
script>
在前面的示例中,所有的value都是固定写死的,真实环境中,value应该是从服务器端获取的,然后动态赋值的。可以通过v-bind:value动态的value进行绑定值,这就是值绑定。
<body>
<div id="div1">
<label v-for="hobby in hobbiesFromDB" :for="hobby">
<input
type="checkbox"
:value="hobby"
:id="hobby"
v-model="hobbies"
/>{{hobby}}
label>
<h2>您选择的爱好是:{{hobbies}}h2>
div>
body>
<script>
const app = new Vue({
el: "#div1",
data: {
hobbies: [],
// 假设这些值是从服务器(或者DB)获取
hobbiesFromDB: ["吃", "喝", "睡", "玩", "code"]
}
});
script>
v-model的修饰符和class的修饰符类似,直接使用.符号即可。v-model主要有三个修饰符:
<body>
<div id="div1">
<input type="text" v-model.lazy="msg" />{{msg}}
<br />
<input type="text" v-model.number="foo" />{{foo}}-{{typeof foo}}
<br />
<input type="text" v-model.trim="bar" />#{{bar}}#
div>
body>
<script>
const app = new Vue({
el: "#div1",
data: {
msg: "msg",
foo: "foo",
bar: "bar"
}
});
script>