Vue练习:简单学生信息管理
1. 第一版
1.1展示效果
1.2 代码
App.Vue
<template>
<div id="app">
<div>
<span>姓名:</span>
<input type="text" v-model.trim="user.name"/>
</div>
<div>
<span>年龄:</span>
<input type="number" v-model="user.age"/>
</div>
<div>
<span>性别:</span>
<select v-model="user.sex">
<option value="男">男</option>
<option value="女">女</option>
</select>
<button @click="addOrEditFn">添加/修改</button>
</div>
<div v-show="arr.length > 0">
<table
border="1"
cellpadding="10"
cellspacing="0"
>
<tr>
<th>序号</th>
<th>姓名</th>
<th>年龄</th>
<th>性别</th>
<th>操作</th>
</tr>
<tr v-for="(obj, index) in arr" :key="index">
<td>{{index + 1}}</td>
<td>{{obj.name}}</td>
<td>{{obj.age}}</td>
<td>{{obj.sex}}</td>
<td>
<button @click="delFn(index)">删除</button>
<button @click="editFn(obj, index)">编辑</button>
</td>
</tr>
</table>
</div>
</div>
</template>
<script>
export default {
name: 'App',
data(){
return {
//用来判断按钮执行的功能是添加(editIndex=-1)还是修改(editIndex!=-1)
editIndex: -1,
//表单绑定对象
user: {name:'', age: 0, sex: ''},
//数据源
arr: [
{name: 'Tom', age: 19, sex: '男'},
{name: 'Jerry', age: 18, sex: '女'}
]
}
},
methods: {
addOrEditFn(){ //添加或修改方法
if(this.editIndex === -1){
//这里不能直接添加this.user,例如:this.arr.push(this.user),会报错,不信你试试
this.arr.push({...this.user});
}else{ //编辑
this.$set(this.arr, this.editIndex, {...this.user})
this.editIndex = -1;
}
this.user = {name: '', age: 0, sex: ''}
},
editFn(obj, index){
//这里也不能写this.user = obj
this.user = {...obj};
this.editIndex = index; //正在编辑的索引
},
delFn(index){
this.arr.splice(index, 1);
}
}
}
</script>
2. 第二版
第二版使用了props
属性,进行了组件间的通信;以及sessionStorage
用来存储数据,防止刷新网页数据消失。
2.1 展示效果
2.2代码
Top.Vue
<template>
<div>
<div>
<span>姓名:</span>
<input type="text" v-model.trim="name"/>
</div>
<div>
<span>年龄:</span>
<input type="number" v-model.number="age"/>
</div>
<div>
<span>性别:</span>
<select v-model="sex">
<option value="男">男</option>
<option value="女">女</option>
</select>
<button @click="add">添加</button>
</div>
</div>
</template>
<script>
import {nanoid} from 'nanoid'
export default {
name: 'Top',
props: ['addStu'],
data(){
return {
name: '',
age: 0,
sex: ''
}
},
methods: {
add(){
const stuObj = {id: nanoid(), name: this.name, age: this.age, sex: this.sex, isEdit: false};
this.addStu(stuObj);
//没有操作DOM元素,直接操作的数据
this.name = '';
this.age = 0;
this.sex = '';
}
}
};
</script>
<style>
div{
margin: 10px 20px;
}
button{
margin-left: 20px;
}
</style>
Bottom.Vue
<template>
<div>
<table border="1" cellpadding="10" cellspacing="0">
<tr>
<th>序号</th>
<th>姓名</th>
<th>年龄</th>
<th>性别</th>
<th>操作</th>
</tr>
<tr v-for="stu in stuList" :key="stu.id">
<td>
<span>{{stu.id}}</span>
</td>
<td>
<input type="text" v-model="stu.name" v-show="stu.isEdit">
<span v-show="!stu.isEdit">{{stu.name}}</span>
</td>
<td>
<input type="number" v-model.number="stu.age" v-show="stu.isEdit">
<span v-show="!stu.isEdit">{{stu.age}}</span>
</td>
<td>
<select v-model="stu.sex" v-show="stu.isEdit">
<option value="男">男</option>
<option value="女">女</option>
</select>
<span v-show="!stu.isEdit">{{stu.sex}}</span>
</td>
<td>
<button @click="del(stu.id)">删除</button>
<button @click="edit(stu)" ref="btnEdit">编辑</button>
</td>
</tr>
</table>
</div>
</template>
<script>
export default {
name: 'Bottom',
props: ['stuList', 'delStu', 'editStuInfo'],
methods: {
del(id){
this.delStu(id);
},
edit(stu){
event.target.innerHTML = stu.isEdit ? '编辑' : '保存';
this.editStuInfo(stu.id);
}
}
};
</script>
<style scoped>
button{
margin: 5px 5px;
}
</style>
App.Vue
<template>
<div id="app">
<h1>学生信息管理系统</h1>
<Top :addStu="addStu"/>
<Bottom :stuList="stuList" :delStu="delStu" :editStuInfo="editStuInfo"/>
</div>
</template>
<script>
import Top from './components/Top'
import Bottom from './components/Bottom'
export default {
name: 'App',
components: {Top, Bottom},
data(){
return {
stuList: JSON.parse(sessionStorage.getItem('stuList')) || []
}
},
watch: {
stuList: {
deep: true, //开启深度监视,否则无法修改sessionStorage中的数据
handler(value){
sessionStorage.setItem('stuList', JSON.stringify(value));
}
}
},
methods: {
//传递给top组件,用来添加学生信息
addStu(stuObj){
this.stuList.unshift(stuObj);
},
delStu(stuId){
this.stuList = this.stuList.filter(stu => {
return stu.id != stuId;
})
},
editStuInfo(stuId){
this.stuList.forEach((stu) => {
if(stu.id === stuId){
stu.isEdit = !stu.isEdit;
}
})
}
}
}
</script>
2.3 知识点记录
2.3.1 props
属性
-
功能:让组件接收外部传过来的数据,也可以接收外部组件传递过来的函数
-
传递数据和接收数据:
传递数据:
<Demo name='xxx'/>
<Demo :obj='obj'/>
接收数据:
第一种方式(只接收):props:['name']
第二种方式(限制类型):
props:{name:String}
第三种方式(限制类型、限制必要性、指定默认值):
props:{
name:{
type:String, //类型
required:true, //必要性
default:'老王' //默认值
}
}
注意:props是只读的,Vue底层会监测你对props的修改,如果进行了修改,就会发出警告,若业务需求确实需要修改,那么请复制props的内容到data中一份,然后去修改data中的数据。
3. props
适用于
(1)父组件 => 子组件 通信
(2)子组件 => 父组件 通信(要求父组件给子组件传递一个函数)
2.3.2 sessionStorage
sessionStorage
存储的内容会随着浏览器窗口关闭而消失。- 相关API:
sessionStorage.setItem('key', 'value');
该方法接受一个键和值作为参数,会把键值对添加到存储中,如果键名存在,则更新其对应的值。sessionStorage.getItem('person');
该方法接受一个键名作为参数,返回键名对应的值。sessionStorage.removeItem('key');
该方法接受一个键名作为参数,并把该键名从存储中删除。sessionStorage.clear();
该方法会清空存储中的所有数据。
3. 第三版
第三版使用了组件自定义事件功能进行了组件间的通信
3.1 代码
App.vue
<template>
<div id="app">
<h1>学生信息管理系统</h1>
<Top v-on:addStu="addStu"/>
<!-- 自定义事件 -->
<Bottom :stuList="stuList" v-on:delStu="delStu" v-on:editStuInfo="editStuInfo"/>
</div>
</template>
<script>
import Top from './components/Top'
import Bottom from './components/Bottom'
export default {
name: 'App',
components: {Top, Bottom},
data(){
return {
stuList: JSON.parse(sessionStorage.getItem('stuList')) || []
}
},
watch: {
stuList: {
deep: true, //开启深度监视,否则无法修改sessionStorage中的数据
handler(value){
sessionStorage.setItem('stuList', JSON.stringify(value));
}
}
},
methods: {
//传递给top组件,用来添加学生信息
addStu(stuObj){
console.log('自定义事件addStu被调用了');
this.stuList.unshift(stuObj);
},
delStu(stuId){
console.log('自定义事件delStu被触发了');
this.stuList = this.stuList.filter(stu => {
return stu.id != stuId;
})
},
editStuInfo(stuId){
console.log('自定义事件editStuInfo被触发了');
this.stuList.forEach((stu) => {
if(stu.id === stuId){
stu.isEdit = !stu.isEdit;
}
})
}
}
}
</script>
Top.vue
<template>
<div>
<div>
<span>姓名:</span>
<input type="text" v-model.trim="name"/>
</div>
<div>
<span>年龄:</span>
<input type="number" v-model.number="age"/>
</div>
<div>
<span>性别:</span>
<select v-model="sex">
<option value="男">男</option>
<option value="女">女</option>
</select>
<button @click="add">添加</button>
</div>
</div>
</template>
<script>
import {nanoid} from 'nanoid'
export default {
name: 'Top',
data(){
return {
name: '',
age: 0,
sex: ''
}
},
methods: {
add(){
const stuObj = {id: nanoid(), name: this.name, age: this.age, sex: this.sex, isEdit: false};
this.$emit('addStu', stuObj);
//没有操作DOM元素,直接操作的数据
this.name = '';
this.age = 0;
this.sex = '';
}
}
};
</script>
<style>
div{
margin: 10px 20px;
}
button{
margin-left: 20px;
}
</style>
Bottom.vue
<template>
<div>
<table border="1" cellpadding="10" cellspacing="0">
<tr>
<th>序号</th>
<th>姓名</th>
<th>年龄</th>
<th>性别</th>
<th>操作</th>
</tr>
<tr v-for="stu in stuList" :key="stu.id">
<td>
<span>{{stu.id}}</span>
</td>
<td>
<input type="text" v-model="stu.name" v-show="stu.isEdit">
<span v-show="!stu.isEdit">{{stu.name}}</span>
</td>
<td>
<input type="number" v-model.number="stu.age" v-show="stu.isEdit">
<span v-show="!stu.isEdit">{{stu.age}}</span>
</td>
<td>
<select v-model="stu.sex" v-show="stu.isEdit">
<option value="男">男</option>
<option value="女">女</option>
</select>
<span v-show="!stu.isEdit">{{stu.sex}}</span>
</td>
<td>
<button @click="del(stu.id)">删除</button>
<button @click="edit(stu)" ref="btnEdit">编辑</button>
</td>
</tr>
</table>
</div>
</template>
<script>
export default {
name: 'Bottom',
props: ['stuList'],
methods: {
del(id){
this.$emit('delStu', id)
},
edit(stu){
event.target.innerHTML = stu.isEdit ? '编辑' : '保存';
this.$emit('editStuInfo', stu.id);
// this.editStuInfo(stu.id);
}
}
};
</script>
<style scoped>
button{
margin: 5px 5px;
}
</style>