Vue图书管理案例
1.图书列表
- 实现静态列表效果
- 基于数据实现模板效果
- 处理每行的操作按钮
编号 | 名称 | 时间 | 操作 |
---|---|---|---|
1 | 三国演义 | 2020-11-02 | 修改 | 删除 |
2 | 水浒传 | 2020-11-02 | 修改 | 删除 |
3 | 红楼梦 | 2020-11-02 | 修改 | 删除 |
4 | 西游记 | 2020-11-02 | 修改 | 删除 |
代码实现
@click.prevent - 禁止 a 标签的默认事件
<tbody>
<tr :key='item.id' v-for='item in books'>
<td>{{item.id}}</td>
<td>{{item.name}}</td>
<td>{{item.date}}</td>
<td>
<a href="" @click.prevent>修改</a>
<span>|</span>
<a href="" @click.prevent>删除</a>
</td>
</tr>
</tbody>
const vm = new Vue({
el: "#app",
data: {
books: [
{
id: 1,
name: "三国演义",
date: ""
},
{
id: 2,
name: "水浒传",
date: ""
},
{
id: 3,
name: "红楼梦",
date: ""
},
{
id: 4,
name: "西游记",
date: ""
}
]
}
})
2.添加图书
- 实现表单的静态效果
- 添加图书表单域数据绑定
- 添加按钮事件绑定
- 实现添加业务逻辑
代码实现
v-model 双向绑定 输入框对应的 value 值
定义一个 handle 点击事件(点击提交,把填写的编号和名称添加到列表中)
在 Vue 实例对象的data中定义 id 和 name 属性
在 methods 中实现 handle 事件
<div>
<label for="id">
编号:
</label>
<input type="text" id="id" v-model="id">
<label for="name">
名称:
</label>
<input type="text" id="name" v-model="name">
<button @click="handle">提交</button>
</div>
const vm = new Vue({
el: "#app",
data: {
id: "",
name: "",
books: [
{
id: 1,
name: "三国演义",
date: ""
},
{
id: 2,
name: "水浒传",
date: ""
},
{
id: 3,
name: "红楼梦",
date: ""
},
{
id: 4,
name: "西游记",
date: ""
}
]
},
methods: {
handle: function(){
var book = {}
book.id = this.id
book.name = this.name
book.date = ""
this.books.push(book)
this.id = ""
this.name = ""
}
}
})
3.修改图书
- 修改信息填充到表单
- 修改后重新提交表单
- 重用添加和修改的方法
代码实现
为修改按钮添加 toEdit 事件,把 tr 的 id 传入
<a href="" @click.prevent="toEdit(item.id)">修改</a>
toEdit: function(id){
console.log(id);
// 先通过 id 找到对应的这一行数据
var book = this.books.filter(function(item){
return item.id === id
})
// console.log(book);
this.id = book[0].id
this.name = book[0].name
}
在修改的时候我们不希望能够修改 书籍的编号 ,所以就需要在修改时添加
disabled
属性,如下写法
<input type="text" id="id" v-model="id" :disabled="flag">
可以看到,这是一个 vue 属性,flag是一个变量,Ta 需要在 Vue 实例对象 data中定义,默认为
flag: false
在修改是禁止修改编号,使
flag: true
即可,如下
toEdit: function(id){
// 禁止修改编号
this.flag = true
// console.log(id);
// 先通过 id 找到对应的这一行数据
var book = this.books.filter(function(item){
return item.id === id
})
// console.log(book);
this.id = book[0].id
this.name = book[0].name
}
另外,提交(handle)事件现在有两件事要做,一是编辑图书,二是添加图书,当 flag 为 true 时去编辑图书,当 flag 为 false 时去添加图书,如下
使用 filter 得到 books 中的所有元素,如果输入框中的 id 等于 要编辑的图书的id,则把输入框中的 name 重新赋值给 书籍的 name
handle: function(){
if(this.flag){
// 编辑
this.books.filter((item)=>{
// console.log(item);
if(this.id == item.id){
item.name = this.name
return true
}
})
this.flag = false
}else{
// 添加
var book = {}
book.id = this.id
book.name = this.name
book.date = ""
this.books.push(book)
}
this.id = ""
this.name = ""
}
效果如下
4.删除图书
- 删除按钮绑定事件处理方法
- 实现删除业务逻辑
代码实现
三种方法
<a href="" @click.prevent="deleteBook(item.id)">删除</a>
deleteBook: function(id){
// -----------------方法一(filter)---------------------
var book = this.books.filter(function(item){
return item.id === id
})
// console.log(book);
var index = this.books.indexOf(book[0])
// console.log(index);
this.books.splice(index, 1)
// -----------------方法二(findIndex)---------------------
var index = this.books.findIndex(function(item){
return item.id === id
})
// console.log(index);
this.books.splice(index, 1)
// -----------------方法三(filter的重新赋值)---------------
this.books = this.books.filter(function(item){
return item.id != id
})
}
5.常用特性应用场景
- 过滤器(格式化日期)
- 自定义指令(获取表单焦点)
- 计算属性(统计图书数量)
- 侦听器(验证图书存在性)
- 生命周期(图书数据处理)
代码实现
首先 Ctrl+C、Ctrl+V 祖传过滤器
Vue.filter('format', function(value, arg) {
function dateFormat(date, format) {
if (typeof date === "string") {
var mts = date.match(/(\/Date\((\d+)\)\/)/);
if (mts && mts.length >= 3) {
date = parseInt(mts[2]);
}
}
date = new Date(date);
if (!date || date.toUTCString() == "Invalid Date") {
return "";
}
var map = {
"M": date.getMonth() + 1, //月份
"d": date.getDate(), //日
"h": date.getHours(), //小时
"m": date.getMinutes(), //分
"s": date.getSeconds(), //秒
"q": Math.floor((date.getMonth() + 3) / 3), //季度
"S": date.getMilliseconds() //毫秒
};
format = format.replace(/([yMdhmsqS])+/g, function(all, t) {
var v = map[t];
if (v !== undefined) {
if (all.length > 1) {
v = '0' + v;
v = v.substr(v.length - 2);
}
return v;
} else if (t === 'y') {
return (date.getFullYear() + '').substr(4 - all.length);
}
return all;
});
return format;
}
return dateFormat(value, arg);
})
然后在需要显示时间的那一格进行使用
<td>{{item.date | format('yyyy-MM-dd hh:mm:ss')}}</td>
注意:books内不能直接用 this 获取Dao Vue的实例对象,而是获取的 Window 全局对象
直接在添加书籍时添加时间即可,如下
// 添加
var book = {}
book.id = this.id
book.name = this.name
book.date = new Date() // 时间
this.books.push(book)
刷新页面获取焦点也是直接写一个全局 directive ,自定义指令即可,我命名为
focus
,名字可以随便写,el 为需要获取焦点的元素
Vue.directive('focus', {
inserted: function (el) {
el.focus();
}
});
实现效果如下
当图书名已经存在则禁用提交按钮
通过 watch 实时验证图书名称是否已经存在
代码实现
在提交按钮定义一个 flag,同样是设置一个变量,默认值设置为 false
<button @click="handle" :disabled="submitFlag">提交</button>
使用 some 来检测 books 数组中是否有 输入的书籍的 name,如果有则禁止提交,如果没有则可以提交
some() 方法会依次执行数组的每个元素:
- 如果有一个元素满足条件,则表达式返回true , 剩余的元素不会再执行检测。
- 如果没有满足条件的元素,则返回false。
watch: {
name: function(val){
var flag = this.books.some(function(item){
return item.name == val
})
console.log(flag);
if(flag){
this.submitFlag = true
}else{
this.submitFlag = false
}
}
}
最后我们需要在 Vue 实例的生命周期的 mounted 阶段(渲染之后,可以获取数据生成的DOM对象)来获取图书数据
mounted: function(){
// 该生命周期钩子函数被触发的时候,模板已经可以使用
// 一般此时用于获取后台数据,然后把数据填充到模板
var data = [
{
id: 1,
name: '三国演义',
date: 2525609975000
},{
id: 2,
name: '水浒传',
date: 2525609975000
},{
id: 3,
name: '红楼梦',
date: 2525609975000
},{
id: 4,
name: '西游记',
date: 2525609975000
}
]
this.books = data
}
最后的实现效果是一样的