怎么设置可以让每个Word打开时是单独窗口?(在word环境中可以同时打开若干个窗口但是)
768
2022-05-30
上一章节我们讲解了组件的基础知识,本章我们将深入讲解组件的传值以及使用综合案例进行实践操作。
5
6
7
8
9
6.1 兄弟组件传值
在前面的内容中我们已经学习了父与子之间的传值,接下来我们来看如果组件之间的关系是平级的也就是兄弟组件之间该如何传值呢?兄弟传值有两种方式,一种是使用EventBus,另一种是借助父子传值实现兄弟传值,下面详细解释。
6.1.1 第一种方式Vue实例
我们先写两个兄弟组件,大家看案例代码:
例6-1 Demo0601.html
1
2
3
4
5
6
7
8
9
10
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41 // 确定名字组件
42 let x1 = Vue.extend({
43 template: "#x1",
44 data() {
45 return {
46 username: ""
47 }
48 },
49
50 });
51 //确定名字后的表白组件
52 let x2 = Vue.extend({
53 template: "#x2"
54 });
55 var vm = new Vue({
56 el: '#app',
57 components: {
58 'likename': x1,
59 'likewords': x2
60 }
61
62
63 })
64
65
66
程序的运行结果如下:
图 6- 1 案例效果
我们现在要做的是在组件1中输入喜欢人的名字,点击确定按钮,把名字传给兄弟组件2中显示。
第一步:建立一个空的Vue实例,用来兄弟组件之间的数据传递:
let bus = new Vue();
第二步:在组件1中触发组件的事件:使用 $emit 触发,点击按钮的时候把名字传过去
// 确定名字组件
let x1 = Vue.extend({
template: "#x1",
data() {
return {
username: ""
}
},
methods: {
getName() {
bus.$emit("editName", this.username);//点击确定按钮把名字传过去
}
}
});
第三步:在组件2中接受,接受组件的事件: 使用 $on 接受,必须写在钩子函数中
//确定名字后的表白组件
let x2 = Vue.extend({
template: "#x2",
data() {
return {
name: "小丽",
}
},
methods: {
myfn() {
bus.$on("editName", (name) => {
this.name = name;
});
}
},
created() {
this.myfn();
}
});
也可以这样写,直接在钩子函数中去接受传过来的数据。
let x2 = Vue.extend({
template: "#x2",
data() {
return {
name: "小丽",
}
},
methods: {
},
created() {
bus.$on("editName", (name) => {
this.name = name;
});
}
});
完整代码如下:
1
2
3
4
5
6
7
8
9
10
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42 let bus = new Vue();
43 // 确定名字组件
44 let x1 = Vue.extend({
45 template: "#x1",
46 data() {
47 return {
48 username: ""
49 }
50 },
51 methods: {
52 getName() {
53 bus.$emit("editName", this.username)
54 }
55 }
56
57 });
58 //确定名字后的表白组件
59 let x2 = Vue.extend({
60 template: "#x2",
61 data() {
62 return {
63 name: "小丽",
64 }
65 },
66 methods: {
67 myfn() {
68 //editName是一个方法的名字,但是这个方法并不存在,on和emit两个方法名字一致即可
69 bus.$on("editName", (name) => {
70 this.name = name;
71
72 });
73 }
74 },
75 created() {
76 this.myfn();
77 }
78 });
79 let vm = new Vue({
80 el: '#app',
81 components: {
82 'likename': x1,
83 'likewords': x2
84 }
85
86
87 })
88
89
90
通过例6-1中,我们通过一个空的Vue实例,来做中间容器,组件1输入名字,点击按钮触发Vue实例中的$on监听的方法 ,注意,$on和$emit后面的方法名字要一致,有同学会问,但是这个方法并不存在,这个方法的作用是用来保证on和emit监听和发送双方的一致,所以该方法可以不存在但是必须保持一致。
6.1.2 第二种方式props和event
兄弟传值也可以借助于同一个父组件,把两个自组建的内容都传给父组件,通过父组件来实现数据交流。
接下来我们把上面的例子进行改造,实现使用props和event方法兄弟传值。
例6-2 Demo0602.html
1
2
3
4
5
6
7
8
9
10
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43 // 确定名字组件
44 let x1 = Vue.extend({
45 template: "#x1",
46 data() {
47 return {
48 username: ""
49 }
50 },
51 methods: {
52 getName() {
53 this.$emit("getx1", this.username)
54 }
55 }
56
57 });
58 //确定名字后的表白组件
59 let x2 = Vue.extend({
60 props: ['myname'],
61 template: "#x2",
62 methods: {
63 },
64
65 });
66 let vm = new Vue({
67 el: '#app',
68 data: {
69 myname: ""//用来接受组件1传过来的值,然后再传给组件2
70 },
71 components: {
72 'likename': x1,
73 'likewords': x2
74 },
75 methods: {
76 //把这个方法传给组件1,在组件1中就可以触发这个方法
77 getx1(name) {
78 this.myname = name;
79 }
80 }
81
82
83 })
84
85
86
程序的运行结果如下:
图 6- 2 使用父组件作为容器进行兄弟传值
通过例6-2中,我们先通过自定义事件,把组件1的值传给父组件,然后父组件使用props把获取的值传给组件2,这样也能够实现兄弟传值。
6.1.3 第三种方式使用parent、children和refs
除了使用Vue空实例,以及父子传值我们还可以使用Vue实例的三个属性,分别是parent,children和refs,接下来我们来看这三种属性如何使用:
This.$parent //获取父组件
This.$children //获取子组件
This.$refs.子组件ref的名字 //获取子组件
1、ref为子组件指定一个索引名称,通过索引来操作子组件;
2、this.$parent 可以直接访问该组件的父实例或组件;
3、父组件也可以通过this.$children 访问它所有的子组件; 需要注意 $children 并不保证顺序,也不是响应式的。
接下来我们来看案例中具体使用:
例6-3 Demo0603.html
1
2
3
4
5
6
7
8
9
10
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43 // 确定名字组件
44 let x1 = Vue.extend({
45 template: "#x1",
46 data() {
47 return {
48 username: ""
49 }
50 },
51 methods: {
52 getName() {
53 this.$parent.getx1(this.username);
54 }
55 }
56
57 });
58 //确定名字后的表白组件
59 let x2 = Vue.extend({
60 template: "#x2",
61 data() {
62 return {
63 name: '夏利'
64 }
65 },
66 methods: {
67 sonName(val) {
68 this.name = val;
69 },
70 },
71
72 });
73 let vm = new Vue({
74 el: '#app',
75 components: {
76 'likename': x1,
77 'likewords': x2
78 },
79 data: {
80
81 },
82 methods: {
83 //该方法调用组件2的方法给name赋值
84 //但是该方法会在组件1中调用,这样就把组件1中username->sanme->组件2
85 getx1(sname) {
86 this.$refs.szj.sonName(sname);
87 },
88
89 }
90
91 })
92
93
94
程序的运行结果与上面两个案例效果相同。
下面我们来看代码解析:
组件2使用ref加入索引:
父组件中提供宫组件1调用的方法:
methods: {
//该方法调用组件2的方法给name赋值
//但是该方法会在组件1中调用,这样就把组件1中username->sanme->组件2
getx1(sname) {
this.$refs.szj.sonName(sname);
},
}
组件1中点击确定按钮,则把组件1中的名字传值给父组件中的方法:
methods: {
getName() {
this.$parent.getx1(this.username);
}
}
例6-3中,我们也可以使用$children替换$refs,但是父组件有多个子组件,使用的时候要使用下标说明调用的是哪个子组件。
methods: {
//该方法调用组件2的方法给name赋值
//但是该方法会在组件1中调用,这样就把组件1中username->sanme->组件2
getx1(sname) {
console.log(this);
this.$children[1].sonName(sname);
},
}
6.2 跨级传值
在Vue中,有时需要实现通信的两个组件不是直接的父子组件,而是祖父和孙子,或者是跨越了更多层级的父子组件,这种时候就不可能由子组件一级一级的向上传递参数,特别是在组件层级比较深,嵌套比较多的情况下,需要传递的事件和属性较多,会导致代码很混乱。这时就需要用到 vue 提供的更高阶的方法:provide/inject。
这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效。
provide/inject:简单来说就是在父组件中通过provider来提供变量,然后在子组件中通过inject来注入变量,不管组件层级有多深,在父组件生效的生命周期内,这个变量就一直有效。
先看使用步骤:
provide() {
// 它的作用就是将 **name** 这个变量提供给它的所有子组件。
name: 'Jack'
},
methods: {
changeName() {
this.name = 'Lily'
}
}
子组件:
inject: ['name'], // 注入了从父组件中提供的name变量
mounted () {
console.log(this.name); // Jack
}
接下来演示完整案例:
例6-4 Demo0604.html
1
2
3
4
5
6
7
8
9
10
16
17
18
19
20
21
22
23
24
25
26
27
28 儿子接受的值====>{{username}}
29
30
31
32
33
34 孙子接受的值===>{{username}}
35
36
37
38
39
40
41
42
43 //孙子组件
44 let sz = Vue.extend({
45 template: "#sz",
46 inject: ['username']
47
48 });
49 // 儿子组件
50 let ez = Vue.extend({
51 template: "#ez",
52 inject: ['username'],
53 components: { sz }
54
55 });
56 let vm = new Vue({
57 el: '#app',
58 components: {
59 ez
60 },
61 data: {
62 username: "你好世界"
63
64 },
65 provide() {
66 return {
67 username: "你好世界"
68 }
69 },
70
71 })
72
73
74
程序的运行结果如下:
图 6- 3 把父组件的值传给儿子和孙子
例6-4中,该案例中的值不是相应式的,也就是说如果父组件中的文本框内的数据发生变化,儿子和孙子接受的值不是不会跟着变化的,如果想要响应式变化我们可以使用如下代码:
父组件容器:
// 父组件
......
data() {
return {
name: "Jack"
};
},
provide() {
return {
parentObj: this //提供祖先组件的实例
};
},
methods: {
changeName() {
this.name = 'Lily'
}
}
孙子容器:
姓名:{{parentObj.name}}
export default {
inject:['parentObj']
例6-5 Demo0605.html
1
2 p
3
4
5
6
7
8
9
10
11
17
18
19
20
21
22
23
24
25
26
27
28
29 儿子接受的值====>{{parentObj.username}}
30
31
32
33
34
35 孙子接受的值===>{{parentObj.username}}
36
37
38
39
40
41
42
43
44 //孙子组件
45 let sz = Vue.extend({
46 template: "#sz",
47 inject: ['parentObj']
48
49 });
50 // 儿子组件
51 let ez = Vue.extend({
52 template: "#ez",
53 inject: ['parentObj'],
54 components: { sz }
55
56 });
57 let vm = new Vue({
58 el: '#app',
59 components: {
60 ez
61 },
62 data: {
63 username: "你好世界"
64
65 },
66 provide() {
67 return {
68 parentObj: this
69 }
70 },
71
72 })
73
74
75
程序的运行结果如下:
图 6- 4 子孙组件的值会跟着父组件的变化而变化
以上是使用provide把父组件实例共享给子孙,子孙通过inject注入,就可以使用父组件的值。
6.3 综合案例
有关组件的知识,通过第五章和第六章我们已经学习掌握,本节同通过实际操作来掌握有关父子传值的知识。
6.3.1 效果和需求
效果
图 6- 5 综合案例效果图
该案例实现了评论的增删改查,以及模糊查询和分页查询;
需求
• 实现所有评论的分页查询
• 实现模糊查询
• 实现添加功能
• 实现修改功能
• 实现删除功能
该案例综合使用动态组件、axios、以及组件传值,希望大家通过练习该案例能够掌握vue组件的基础知识。
6.3.2 实际步骤
第一步:建立数据源
建立data.json,因为我们的数据最初是从json文件里面拿出来的,拿出来后存储到本地中
1 {
2 "comments": [
3 {
4 "commentId": 1,
5 "content": "平凡的世界",
6 "comDate": "1999-09-09"
7 },
8 {
9 "commentId": 2,
10 "content": "白天与黑夜",
11 "comDate": "1999-09-09"
12 },
13 {
14 "commentId": 3,
15 "content": "这个很不错额",
16 "comDate": "1999-09-09"
17 },
18 {
19 "commentId": 4,
20 "content": "平凡的世界",
21 "comDate": "1999-09-09"
22 },
23 {
24 "commentId": 5,
25 "content": "平凡的世界",
26 "comDate": "1999-09-09"
27 }
28 ]
29 }
第二步:查询建立页面
在页面上引入vue.js,bootstrap.csc、axios.js以及moment.js
其中moment.js 是用来时间格式化的。
1
2
3
4
5
6
7
8
9
10
18
19
20
21
22
23
24
25
33
编号 | 内容 | 日期 | 操作 |
---|---|---|---|
42 {{item.commentId}} 43 | 45 {{item.content}} 46 | 48 {{item.comDate}} 49 | 51 52 53 |
57
58
59
60
61
62
63
64 let vm = new Vue({
65 el: '#app',
66 data: {
67 coms: [],
68
69 },
70 methods: {
71 //获取所有的评论
72 //先从本地获取存储中获取评论,如果没有则去data.json中获取
73 allComs() {
74 let comments = JSON.parse(localStorage.getItem("comments") || "[]");
75 this.coms = comments;
76 if (comments.length === 0) {
77 axios.get("./data.json").then(resp => {
78 console.log(resp.data);
79 this.coms = resp.data.comments;
80 localStorage.setItem("comments", JSON.stringify(this.coms));
81 }, resp => {
82 console.log("error");
83 });
84 }
85
86
87 },
88 },
89 created() {
90 this.allComs();
91 },
92
93 })
94
95
96
97
程序运行结果如下:
图 6- 6 查询所有评论
第四步:实现添加
添加的时候实现评论id自增,通过计算属性查询出数组的最大值,在最大值的基础上加1,在添加模板中,点击添加按钮,把最新添加的评论内容添加到数组中和本地中。点击添加按钮的时候使用$parent调用父组件的方法。
写添加模板:
1
2
3
4
13
14
15
添加的样式:
1
2 .add {
3 width: 700px;
4 height: auto;
5 margin: 10px auto;
6 }
7
8
添加的时候,我们的编号是通过查找最大的编号,然后在最大的编号的基础上加1:
1 computed: {
2 num() {
3 let index = 1;
4 this.coms.forEach(item => {
5 let id = parseInt(item.commentId);
6 if (id > index) {
7 index = id;
8 }
9
10 });
11 return index;
12 }
13 }
14
添加模板中的方法:
1 let addCom = Vue.extend({
2 template: '#add',
3 data() {
4 return {
5 content: ""
6 }
7 },
8 methods: {
9 addItem() {
10 let obj = { content: this.content }
11 this.$parent.addCom(obj);
12 }
13 }
14
15 });
父组件中的添加方法:
1 //添加方法
2 addCom(item) {
3 item.commentId = this.num + 1;
4 let date = new Date();
5 let commentDate = moment(date).format('YYYY-MM-DD')
6 item.comDate = commentDate;
7 this.coms.push(item);
8 localStorage.setItem("comments", JSON.stringify(this.coms));
9
10 }
程序运行如下:
图 6- 7 实现添加评论
来看本地存储中也添加了最新的数据:
图 6- 8 本地存储添加最新数据
第五步:实现修改业务;
点击修改按钮的时候,我们希望在添加的位置,显示修改的模板,这个时候我们可以使用动态组件component的is属性,默认显示add组件。
1
2 .
3 .
4 .
5 data: {
6 coms: [],
7 addOrupdate: "add"
8
9 },
设置修改的模板,设置完毕模板后要在父组件中注册:
1
2
3
4
17
18
点击每一行的修改按钮的时候要做以下事情:
• 表格上方改为修改模板
• 根据要修改的id找到这个数据
• 把该对象原来的数据传到修改组件中
1 //点击修改按钮去修改
2 //1、在添加的位置显示修改模板
3 //2、要修改的信息进行回显
4 toUpdate(id) {
5 this.addOrupdate = "update";
6 //根据id找到信息进行回显
7 let obj = {};
8 this.coms.some(c => {
9 if (c.commentId === id) {
10 obj = c;
11 return true;
12 }
13 });
14 this.upobj = obj;
15
16
17 },
现在把upobj传给修改组件
1
2
3
4 //修改模板去接受
5 let updateCom = Vue.extend({
6 template: "#update",
7 props: ['upobj'],
8 });
由于使用props是单向向下的,只能父组件传给子组件,但是子组件不能修改,所以我们要把props中的数据给data中的id和content,同时要监视props数据的变化,一旦变化随时传值给data:
1 let updateCom = Vue.extend({
2 template: "#update",
3 props: ['upobj'],
4 data() {
5 return {
6 id: this.upobj.commentId,
7 content: this.upobj.content
8 }
9 },
10 watch: {
11 //监听父组件传过来的值,只要传过来的值发生变化,子组件的data中的数据也会跟着变化
12 upobj(val) {
13 this.id = val.commentId;
14 this.content = val.content;
15 }
16 }
17
18
19 });
20
程序运行如下:
图 6- 9 点击修改按钮数据回显成功
点击提交实现修改:
点击提交,根据最新的数据生成一个对象,然后在子组件中调用父组件的修改方法,实现修改业务:
1 //父组件中的修改的方法
2 update(obj) {
3 console.log(obj);
4 obj.comDate = moment(new Date()).format("YYYY-MM-DD");
5 this.coms.some(c => {
6 if (c.commentId === obj.commentId) {
7 c.content = obj.content;
8 c.comDate = obj.comDate;
9 return true;
10 }
11 });
12 //本地存储做出修改
13 localStorage.setItem("comments", JSON.stringify(this.coms));
14 //修改页面恢复为添加
15 this.addOrupdate = "add";
16
17 }
18 //修改子组件的方法
19 methods: {
20 //修改的方法
21 //把修改的数据覆盖掉之前的数据
22 //在子组件中调用父组件的修改方法
23 upfn() {
24 let obj = {
25 commentId: this.id,
26 content: this.content
27 }
28 this.$parent.update(obj);
29
30 }
31
32 },
33
第六步:实现删除
点击删除按钮的时候,实现从data中的coms中删除,同时跟localStorage保持一致:
1 //执行删除功能
2 //根据id查找,找到后删除
3 del(id) {
4 this.coms.some((c, index) => {
5 if (c.commentId === id) {
6 this.coms.splice(index, 1);
7 return true;
8 }
9 });
10 localStorage.setItem("comments", JSON.stringify(this.coms));
11 }
12
第七步:实现搜索
定义搜索的模板,然后在父组件中注册:
1
2
3
4
5
6
7
8
9
10
点击查找按钮,进行调用父组件中的查找方法:
1 //搜索
2 let searchCom = Vue.extend({
3 template: "#search",
4 data() {
5 return {
6 keywords: ""
7 }
8 },
9 methods: {
10 searfn() {
11 this.$parent.search(this.keywords);
12
13 }
14 }
15 });
16
17 //父组件的搜索功能,scoms是在父组件中定义的专门用来存储搜索后结果的数组,同时table遍历改成使用scoms
18 search(kw) {
19 this.scoms = this.coms.filter(item => {
20 return item.content.includes(kw);
21 });
22 }
23 //最开是的查询所有变成如下代码
24 allComs() {
25 let comments = JSON.parse(localStorage.getItem("comments") || "[]");
26 this.coms = comments;
27 if (comments.length === 0) {
28 axios.get("./data.json").then(resp => {
29 console.log(resp.data);
30 this.coms = resp.data.comments;
31 localStorage.setItem("comments", JSON.stringify(this.coms));
32 }, resp => {
33 console.log("error");
34 });
35 }
36 this.scoms = this.coms;//把原来的数组给搜索的结果
37
38 },
程序运行结果如下:
图 6- 10 模糊查询的功能
第八步:实现分页
定义分页模板:
11
12
13
思考:分页组件中的总页数是从父组件中传过来的;
父组件定义计算属性:
1 //计算总页数
2 pagenum() {
3 return Math.ceil(this.scoms.length / this.pageSize);
4 }
把这个属性传值给分页组件:
1
2
3
4 let page = Vue.extend({
5 template: "#page",
6 props: ['pagenum'],
7 data() {
8 return {
9 num: this.pagenum
10 }
11 },
12 watch: {
13 pagenum(val) {
14 this.num = val;
15
16 }
17 }
18 });
19
模板中循环页码:
1
2
3
4
11
接下来实现默认显示第一页的内容:
在这我们使用的是数组的slice方法可以截取某一个段,所以我们需要计算开始和结束位置:
12
1
2 //使用计算属性计算截取的开始位置
3 start() {
4 return this.pageIndex * this.pageSize - this.pageSize;
5
6 },
7
8 //截取的结束位置
9 end() {
10 return this.pageIndex * this.pageSize;
11
12 }
模板变化:
1
2
3
10
实现点击页码显示相应的内容:
11 methods: {
1 //分页组件的点击页码事件
2 goto(n) {
3 this.$parent.changePageIndex(n);
4
5 }
6 }
7
8 //父组件的方法
9 //执行显示相应的页码的内容,本质就是改变页码
10 changePageIndex(val) {
11 this.pageIndex = val;
12
13 }
14
实现上一页下一页的功能:
1 methods: {
1 //分页组件的点击页码事件
2 goto(n) {
3 this.$parent.changePageIndex(n);
4
5 },
6 //子组件的上一页
7 prev() {
8 this.$parent.goUp();
9 },
10 //自组建的下一页
11 next() {
12 this.$parent.goDown();
13 }
14 }
15
16 //父组件的上一页下一页
17 //上一页
18 goUp() {
19 if (this.pageIndex === 1) {
20 alert("已经是第一页了");
21 } else {
22 this.pageIndex = this.pageIndex - 1;
23 }
24
25 },
26 //下一页
27 goDown() {
28 if (this.pageIndex === this.pagenum) {
29 alert("已经是最后一页了");
30 } else {
31 this.pageIndex = this.pageIndex + 1;
32 }
33 }
6.3.3 完整案例
Data.json
1
2 {
3 "comments": [
4 {
5 "commentId": 1,
6 "content": "平凡的世界",
7 "comDate": "1999-09-09"
8 },
9 {
10 "commentId": 2,
11 "content": "白天与黑夜",
12 "comDate": "1999-09-09"
13 },
14 {
15 "commentId": 3,
16 "content": "这个很不错额",
17 "comDate": "1999-09-09"
18 },
19 {
20 "commentId": 4,
21 "content": "平凡的世界",
22 "comDate": "1999-09-09"
23 },
24 {
25 "commentId": 5,
26 "content": "人间失格",
27 "comDate": "1999-09-09"
28 },
29 {
30 "commentId": 6,
31 "content": "yyh",
32 "comDate": "1999-09-09"
33 },
34 {
35 "commentId": 7,
36 "content": "yyh当当",
37 "comDate": "1999-09-09"
38 }
39 ]
40 }
综合案例.html
1
2
3
4
5
6
7
8
9
10
40
41
42
43
44
45
编号 | 内容 | 日期 | 操作 |
---|---|---|---|
54 {{item.commentId}} 55 | 57 {{item.content}} 58 | 60 {{item.comDate}} 61 | 63 64 65 |
69
70
71
72
73
74
75
76
77
78
87
88
89
90
91
92
93
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
127
128
129
130
131 //添加
132 let addCom = Vue.extend({
133 template: '#add',
134
135 data() {
136 return {
137 content: ""
138 }
139 },
140 methods: {
141 addItem() {
142 let obj = { content: this.content }
143 this.$parent.addCom(obj);
144 }
145 },
146
147
148
149 });
150 //修改
151 let updateCom = Vue.extend({
152 template: "#update",
153 props: ['upobj'],
154 data() {
155 return {
156 id: this.upobj.commentId,
157 content: this.upobj.content
158 }
159 },
160 methods: {
161 //修改的方法
162 //把修改的数据覆盖掉之前的数据
163 //在子组件中调用父组件的修改方法
164 upfn() {
165 let obj = {
166 commentId: this.id,
167 content: this.content
168 }
169 this.$parent.update(obj);
170
171 }
172
173 },
174 watch: {
175 //监听父组件传过来的值,只要传过来的值发生变化,子组件的data中的数据也会跟着变化
176 upobj(val) {
177 this.id = val.commentId;
178 this.content = val.content;
179 }
180 }
181
182
183 });
184 //搜索
185 let searchCom = Vue.extend({
186 template: "#search",
187 data() {
188 return {
189 keywords: ""
190 }
191 },
192 methods: {
193 searfn() {
194 this.$parent.search(this.keywords);
195
196 }
197 }
198 });
199 //分页
200 let page = Vue.extend({
201 template: "#page",
202 props: ['pagenum'],
203 data() {
204 return {
205 num: this.pagenum
206 }
207 },
208 watch: {
209 pagenum(val) {
210 this.num = val;
211
212 }
213 },
214 methods: {
215 //分页组件的点击页码事件
216 goto(n) {
217 this.$parent.changePageIndex(n);
218
219 },
220 //子组件的上一页
221 prev() {
222 this.$parent.goUp();
223 },
224 //自组建的下一页
225 next() {
226 this.$parent.goDown();
227 }
228 }
229 });
230 let vm = new Vue({
231 el: '#app',
232 data: {
233 coms: [],
234 addOrupdate: "add",
235 upobj: {},//保存被修改的对象
236 scoms: [],
237 pageSize: 3,//每页显示的条数
238 pageIndex: 1,//当前页码
239
240 },
241 components: {
242 "add": addCom,
243 "update": updateCom,
244 "search": searchCom,
245 page
246 },
247 methods: {
248 //获取所有的评论
249 //先从本地获取存储中获取评论,如果没有则去data.json中获取
250 allComs() {
251 let comments = JSON.parse(localStorage.getItem("comments") || "[]");
252 this.coms = comments;
253 if (comments.length === 0) {
254 axios.get("./data.json").then(resp => {
255 console.log(resp.data);
256 this.coms = resp.data.comments;
257 localStorage.setItem("comments", JSON.stringify(this.coms));
258 }, resp => {
259 console.log("error");
260 });
261 }
262 this.scoms = this.coms;
263
264 },
265
266 //添加方法
267 addCom(item) {
268 item.commentId = this.num + 1;
269 let date = new Date();
270 let commentDate = moment(date).format('YYYY-MM-DD')
271 item.comDate = commentDate;
272 this.coms.push(item);
273 this.scoms = this.coms;
274 localStorage.setItem("comments", JSON.stringify(this.coms));
275
276 },
277 //点击修改按钮去修改
278 //1、在添加的位置显示修改模板
279 //2、要修改的信息进行回显
280 toUpdate(id) {
281 this.addOrupdate = "update";
282 //根据id找到信息进行回显
283 let obj = {};
284 this.coms.some(c => {
285 if (c.commentId === id) {
286 obj = c;
287 return true;
288 }
289 });
290 this.upobj = obj;
291
292
293 },
294 //父组件中的修改的方法
295 update(obj) {
296 console.log(obj);
297 obj.comDate = moment(new Date()).format("YYYY-MM-DD");
298 this.coms.some(c => {
299 if (c.commentId === obj.commentId) {
300 c.content = obj.content;
301 c.comDate = obj.comDate;
302 return true;
303 }
304 });
305 this.scoms = this.coms;
306 //本地存储做出修改
307 localStorage.setItem("comments", JSON.stringify(this.coms));
308 //修改页面恢复为添加
309 this.addOrupdate = "add";
310
311 },
312 //执行删除功能
313 //根据id查找,找到后删除
314 del(id) {
315 this.coms.some((c, index) => {
316 if (c.commentId === id) {
317 this.coms.splice(index, 1);
318 return true;
319 }
320 });
321 this.scoms = this.coms;
322 localStorage.setItem("comments", JSON.stringify(this.coms));
323 },
324 //父组件的搜索功能
325 search(kw) {
326
327 this.scoms = this.coms.filter(item => {
328 return item.content.includes(kw);
329 });
330 },
331 //执行显示相应的页码的内容,本质就是改变页码
332 changePageIndex(val) {
333 this.pageIndex = val;
334
335 },
336 //上一页
337 goUp() {
338 if (this.pageIndex === 1) {
339 alert("已经是第一页了");
340 } else {
341 this.pageIndex = this.pageIndex - 1;
342 }
343
344 },
345 //下一页
346 goDown() {
347 if (this.pageIndex === this.pagenum) {
348 alert("已经是最后一页了");
349 } else {
350 this.pageIndex = this.pageIndex + 1;
351 }
352 }
353
354 },
355 created() {
356 this.allComs();
357 },
358 computed: {
359 num() {
360 let index = 1;
361 this.coms.forEach(item => {
362 let id = parseInt(item.commentId);
363 if (id > index) {
364 index = id;
365 }
366
367 });
368 return index;
369 },
370 //计算总页数
371 pagenum() {
372 return Math.ceil(this.scoms.length / this.pageSize);
373 },
374 //截取的开始位置
375 start() {
376 return this.pageIndex * this.pageSize - this.pageSize;
377
378 },
379
380 //截取的结束位置
381 end() {
382 return this.pageIndex * this.pageSize;
383
384 }
385 }
386
387 })
388
389
390
391
6.4 本章小结
• 兄弟组件传值有三种方式:空的Vue实例、props和event结合以及parent/children/refs;
• 跨级组件传值使用provider在父组件中申明,使用inject在孙子组件中注入;
• 综合案例掌握不同组件之间的数据通讯,以及axios的初步使用以及动态组件的使用。
6.5 理论试题与实践练习
1.思考题
1.1 请简述如何使用空的Vue实例传值;
1.2 请简述如何使用props和event实现兄弟组件传值;
1.3 请简述parent/children/refs的使用;
1.4 请简述跨级provicer/inject的使用步骤;
1.5 请简述keep-alive的使用和以及钩子函数;
1.6 请简述动态组件如何传值;
2.编程题
实现图书管理的增删改查以及分页和模糊查询
Vue
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。