前言

上一篇文章中,我们已经介绍了如何在Laravel中搭建Vue.js所需要的环境,以及简单的编码示例,接下来我们将会稍微深入一点,完成一个多标签切换显示的小功能。

本文需要对LaravelVue.js有基本的了解;

另外,本文使用到了sassjade,如果不了解或不想使用,可以考虑其他预处理器,甚至可以粗暴地使用原生htmlcss来写

Demo功能说明

在开发前,让我们看下我们将要实现的UI:

image

上面有2级tab供切换显示,下面的图片内容根据tab的切换来显示不同内容。

这里主要涉及到数据的处理及展示,是很适合使用Vue.js的。

假如下面的图片不仅仅只有一张图片显示,可能还会加个hover等其他东西,这时候可以考虑将之封装成一个组件(Component),这是非常有用的一个做法。
(这里为了节省时间,我们在这个Component里就不加hover等其他东西了,只显示一张图片)。

组件(Component)是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素,封装可重用的代码。在较高层面上,组件是自定义元素,Vue.js 的编译器为它添加特殊功能。在有些情况下,组件也可以是原生 HTML 元素的形式,以 is 特性扩展。

建议先阅读一遍官方的Component文档

预处理

Vue.js支持各种预处理工具,如sassstylusjade等。

假设要使用stylusjade,只要仿照以下命令安装一下:

1
cnpm install stylus jade --save-dev

然后在之后的vue文件里,指定类型即可,如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<template lang='jade'>
.hello
h1 Hello Vue
</template>

<style lang="stylus" scoped>
.hello
width: 100vw;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
</style>

<script>

export default {
el() {
return '#app'
}
</script>

本文示例代码是采用jadesass的方式来写的,sass是用Laravel本身封装的elixir api来转换的,所以这里只需要安装jade

1
cnpm install jade --save-dev

编码

接下来让我们进入实际的编码阶段,前期准备还是跟上一篇文章所说的一样。

1、在./gulpfile.js里增加一句代码(这里我们将之命名为tab.js):

1
mix.browserify('entries/tab.js', 'public/js/tab.js');

2、添加一些测试数据,并修改./app/Http/routes.php,增加一条路由。

首先创建./config/tab_sample_data.php文件,添加等下需要的测试数据,具体数据结构及内容有点长,就不直接贴在这了,需要的话请去本文最后面的附录查看。

接着让我们配置好路由并传递数据过去:

1
2
3
4
Route::get('tab', function () {
$tabSampleData = \Config::get('tab_sample_data');
return view('tab', ['allData' => $tabSampleData]);
});

3、创建文件./resources/views/tab.blade.php,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Vue-Tab-Demo</title>
<link rel="stylesheet" href="/css/app.css" media="screen" title="no title" charset="utf-8">
</head>
<body>
{{-- Vue入口 --}}
<div id='app'></div>
<script type="text/javascript">
// 转换 php 传来的数据,给 Tab.vue 文件使用
@if(isset($allData))
var allData = {!! json_encode($allData) !!};
@endif
</script>
{{-- CDN --}}
<script src="//cdn.bootcss.com/vue/1.0.26/vue.min.js"></script>
{{-- 引进编译后的js文件 --}}
<script src="{{ asset('/js/tab.js')}}" charset="utf-8"></script>
</body>
</html>

4、创建./resources/assets/js/entries/tab.js文件,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import Vue from 'vue';
import Tab from '../views/Tab.vue';

Vue.config.debug = true;

Promise.all([
new Promise((resolve) => {
if (window.addEventListener) {
window.addEventListener('DOMContentLoaded', resolve);
} else {
window.attachEvent('onload', resolve);
}
}),
]).then((event) => {
new Vue(Tab);
});

5、创建./resources/assets/js/components/TabItem.vue文件(文件夹不存的话,请自行创建),这里主要就是用来封装我们上面提到的组件(component),为了节省时间,我们就只显示一张图片,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<template lang="jade">
.tab-list-item
img(:src='info.pic_url')
</template>

<script>
export default {
props: ['info'],
data() {
return {
}
},
computed:{

},
ready() {
},
methods: {

},
events: {
},
components: {
}
}
</script>

6、创建./resources/assets/js/views/Tab.vue文件,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
<template lang="jade">
.tab-container
.tab-nav
ul.tab-main-nav
li.tab-main-nav-item(@click='setCategoryNav(0)', :class='{active: categoryNav === 0}') 产品设计
li.tab-main-nav-item(@click='setCategoryNav(1)',:class='{active: categoryNav === 1}') 交互设计
li.tab-main-nav-item(@click='setCategoryNav(2)',:class='{active: categoryNav === 2}') 视觉设计
ul.tab-sub-nav
li.tab-sub-nav-item(v-for='item in subNavList', :class='{active: subNav === item}' @click='setSubNav(item)') {{item}}
.tab-list
tab-item(v-for='item in subList', :info='item')
</template>

<script>
import TabItem from '../components/TabItem.vue'

export default {
el() {
return '#app'
},
data() {
return {
categoryNav: 0,
totalData: allData,
subNav: '全部'
}
},
computed:{
subNavList() {
let self = this;
let subList = self.totalData[self.categoryNav];

let navList = ['全部'];
for (var i = 0; i < subList.length; i++) {
navList.push(subList[i].name);
}
return navList;
},
subList() {
let self = this;
let subList = self.totalData[self.categoryNav];

let list = [];
for (var i = 0; i < subList.length; i++) {
let wList = subList[i].list;
for (var j = 0; j < wList.length; j++) {
if (self.subNav == '全部') {
list.push(wList[j]);
} else if (self.subNav == subList[i].name) {
list.push(wList[j]);
}
}
}
return list;
}
},
ready() {
},
methods: {
setCategoryNav(nav) {
this.categoryNav = nav;
this.subNav = '全部';
},
setSubNav(nav) {
this.subNav = nav;
}
},
events: {
},
components: {
TabItem
}
}
</script>

7、接下来进入sass部分,先在./resources/assets/sass/app.scss里增加一句代码:

1
@import 'tab';

然后创建./resources/assets/sass/_tab.scss文件,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
45
46
47
48
49
50
51
52
53
54
55
56
57
.tab {
$mainColor: #c45441;
$activeColor: #515151;

&-container {
height: 100%;
width: 60%;
margin: 0 auto;
}

&-nav {
color: #b0b0b0;
margin: 80px auto 0px;
max-width: 400px;
}
&-main-nav {
margin: 0;
padding: 0;
height: 30px;
border-bottom: 1px solid $mainColor;
display: flex;
justify-content: space-between;
&-item {
display: inline;
cursor: pointer;
height: 31px;
&.active {
color: $activeColor;
border-bottom: 1px solid $mainColor;
}
}
}
&-sub-nav {
padding: 0;
font-size: 13px;
&-item {
display: inline;
padding: 5px;
cursor: pointer;
&.active {
color: $activeColor;
border-bottom: 1px solid $mainColor;
}
}
}

&-list {
margin: 60px 0 0 0;
padding: 0;
display: flex;
justify-content: flex-start;
flex-wrap: wrap;
&-item {
margin-left: 10px;
}
}
}

8、运行gulp watch命令,去浏览器访问http://localhost:3000/tab查看效果 (具体域名请根据自身修改,这里是我本地的)

注意:请在Chrome等现代化浏览器下访问

总结

以上就是多标签切换显示的小功能Demo,从中我们可以稍微了解到Vue.js组件(components)功能。我现在学到的只是皮毛,以后有机会再来深入地学习及应用。

Vue.js 是一个构建数据驱动的 web 界面的库。Vue.js 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件。
Vue.js 自身不是一个全能框架——它只聚焦于视图层。因此它非常容易学习,非常容易与其它库或已有项目整合。另一方面,在与相关工具和支持库一起使用时,Vue.js 也能完美地驱动复杂的单页应用。

—— 官方描述

最后附上这两篇在Laravel中使用Vue.js文章里的示例工程代码:github地址

以上代码是在我最敬爱和佩服的大楷哥的悉心指点下完成,在此衷心献上我一双二十几年份的膝盖,希望他以后在我宿舍睡觉时,能不要再放了几个屁还死不承认。


2016-06-30 20:01
Aevit
华师一课南座



摄影:Aevit 2015年10月 布达拉宫

附录

测试数据

./config/tab_sample_data.php文件内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
<?php
return array(
// 产品
array(
array(
'name' => '厨房',
'list' => array(
array(
'pic_url' => 'http://file.arvit.xyz/454c855115f16ad5e75869fc7e2bdb1f1460975212.png',
),
array(
'pic_url' => 'http://file.arvit.xyz/454c855115f16ad5e75869fc7e2bdb1f1460975212.png',
),
array(
'pic_url' => 'http://file.arvit.xyz/a797f2435852b8471bf5a79342e4aee61460975212.png',
),
)
),
array(
'name' => '卫浴',
'list' => array(
array(
'pic_url' => 'http://file.arvit.xyz/454c855115f16ad5e75869fc7e2bdb1f1460975212.png',
),
array(
'pic_url' => 'http://file.arvit.xyz/5850d66f802feda8cb9b0963bfdd66f11460975212.png',
),
)
)
),

// 交互
array(
array(
'name' => '数码',
'list' => array(
array(
'pic_url' => 'http://file.arvit.xyz/454c855115f16ad5e75869fc7e2bdb1f1460975212.png',
),
)
),
array(
'name' => '厨房',
'list' => array(
array(
'pic_url' => 'http://file.arvit.xyz/454c855115f16ad5e75869fc7e2bdb1f1460975212.png',
),
)
)
),

// 视觉
array(
array(
'name' => '卫浴',
'list' => array(
array(
'pic_url' => 'http://file.arvit.xyz/454c855115f16ad5e75869fc7e2bdb1f1460975212.png',
),
)
),
),
);