2020-08-30 前端路上的新长征(Vuetify入门)

![

image.png

前端路上的新长征

  • 前言

    在开始之前,如果你从未涉及过前端操作,那么有必要知道究竟什么是前端,什么是后端?

    本文摒弃一切专业术语,尽量采用大白话来叙述概念,所谓前端就是平时咱们打开浏览器看到的页面,也称为HTML页面,所谓前端就是指浏览器,后端就是指存放信息的服务器。在最早最早的时候,这二者没有交互性。注意,没有交互性指的是信息只能从服务器单向传递给用户,早期的所谓”网站“其实就是一本电子书。一段时间之后,出现了交互式网页,信息流不再是单向传递,比如说网上留言板的产生,用户在浏览器输入了一段文字之后,点提交按钮,这段文字将通过网络发送到服务器端,然后结果又通过网页的方式回传到浏览器,浏览器和服务器之间产生了双向数据流动。Javascript就是这样一种运行在浏览器里面的胶水语言,负责将用户数据和服务器数据进行耦合。

从功能性角度来说,前端主要就是负责页面排版、内容呈现,用户界面等等,前端程序跑在本机浏览器里。后端则主要负责逻辑处理,内容查询、组织等功能,后端程序运行在远程服务器里。

从历史的角度来说,尽管几十年过去了,前端的基本结构还是以浏览器+Javascript为主,基本没什么变化,曾经有一些脚本语言比如微软的VBS试图挑战过这个结构,均以失败告终,连昙花一现都谈不上。后端(服务器)方面则是百花齐放,太多的方案可以选择,像是Java、PHP、GO、Python甚至JS本身的一个分支Node.JS等等。

由于WEB的发展速度非常快,连带着Javascript也在高速迭代,于是产生了”框架“这个概念,所谓框架就是一堆前人已经编写好的成体系的代码,其主要目的是不重复造轮子,加速开发效率。在没有框架之前,所有前端开发者都采用原生Javascript,工作量极大,后来稍好一点有了JQuery减轻负担(JQuery不是框架,而是一个简化JS操作的选择器)。从目的性角度而言,为什么我们需要框架呢,不用不成吗?当然可以不用,国外就确实有一股势力是反对采用框架编程的,自诩为 ”JS反框架联盟“,此话题不多说,见仁见智吧。

记得前面咱们说过,前端是HTML页面和JS的混合体,在最早的时候HTML就是一种简单的排版语言,但随着时代的发展,这一块也在突飞猛进,从CSS的诞生,再到今天各种UI层面的需求、设计风格的变迁,以至于HTML也有了框架。从Twitter公司开发的Bootstrap,再到饿了吗公司开发的Element,再到今天我们讲的Vuetify,这些框架和前面所讲的JS框架定位并不相同,像React、Vue这一类JS框架关注点是JS本身,更多的是属于逻辑层面的事务。而Bootstrap和Vuetify这一类HTML框架则着重关注UI界面,页面布局,排版等视觉方面的事情。换句话说,JS框架是码农关注的焦点,HTML框架更多的是设计师和美工关注的焦点。

主流的JS三大框架:React、Angular、Vue

三大主流HTML UI框架:Bootstrap、Element、Vuetify

  • PS: 本文以Vue + Vuetify为基础。

Vuetify 篇:

  • Vuetify 号称是 Vue.js 的头号组件库,笔者使用过Bootstrap,因为年代久远已经忘得差不多了,具体特点也不做评价。饿了吗的Element,感觉上手最容易,但限制比较多,UI的炫酷程度也比较低。Vuetify 要比前两者诞生的时间晚,但是它的可定制性很强,速度快,而且预设UI非常新潮,漂亮,值得尝试!

  • 由于Vuetify是专门提供给Vue使用的(从其名称上也大概猜到了),所以在使用Vuetify之前我们还必须先安装Vue

  • 装Vue之前还得先装Node.JS

    • Node.JS本质上用于服务器后端,它将原本只能用在前端的Javascript变得可以运行在服务器后端,它对标的是Java、PHP这一类东西。但此处安装Node.js并不是要用到它的后端功能,主要是需要他的一个附属工具:“npm” 包管理工具。

    • 下载新版Node.js: https://nodejs.org/en/

    • 下载完毕之后,安装基本是无脑下一步即可。

  • 回到windows cmd命令行界面,开始准备安装vue-cli:

    • vue-cli是vue框架的“脚手架”,它的作用是快速为你搭建一个空的框架,然后立刻可以工作,省去了一大堆调试安装的事情。当然如果你不采用vue脚手架,用传统的方式引用一个vue.js也是可以的。这样更加简洁高效,但是对于稍大一点的应用,无穷无尽的调试和链接工作将会让你抓狂,在此我还是建议从脚手架开始吧,等以后有闲了可以再去深入。

    • 输入:

      npm install -g @vue/cli
    • vue-cli安装好之后,vue命令就能使用了,用它创建一个项目,名称随意(此处为mini):

      1. vue create mini //创建mini项目

      2. vue add vuetify //添加vuetify组件

      • 项目将会自动创建完成,并且自动生成以下目录结构:

image-20200830075007635.png

  1. - 然后打开浏览器,输入网址:http://localhost:8080 即可。


一个最基础的APP界面如下:

image-20200829024214407.png

如图所示,这是一个最简单的APP框架,包括

  • 两个状态栏:v-app-bar(顶部)、v-footer(底部)
  • 侧边功能导航栏:v-navigation-drawer
  • 主视图区:v-content

最基础的主页代码:

  1. v-model="drawer"

  2. <v-list-item link>

  3. <v-list-item-action>

  4. <v-icon>mdi-home</v-icon>

  5. </v-list-item-action>

  6. <v-list-item-content>

  7. <v-list-item-title>选项1</v-list-item-title>

  8. </v-list-item-content>

  9. <v-list-item link>

  10. <v-list-item-action>

  11. <v-icon>mdi-email</v-icon>

  12. </v-list-item-action>

  13. <v-list-item-content>

  14. <v-list-item-title>选项2</v-list-item-title>

  15. </v-list-item-content>

  16. </v-navigation-drawer>

  17. <v-app-bar-nav-icon @click.stop="drawer = !drawer"></v-app-bar-nav-icon>

  18. <v-toolbar-title>Application</v-toolbar-title>

  19. class="fill-height"

  20. <h1>Hello World!</h1>

  21. <v-spacer></v-spacer>

  22. <span class="white--text">&copy; {{ new Date().getFullYear() }}</span>

  • vmodel: 显示开关,设为null的时候屏蔽导航栏

  • clipped:将导航栏置于app-bar的下方 (此处的 clipped:clipped = “true” 的简化写法)

  • app:是否显示app信息,如app title之类

  • <v-list dense> : dense作用是减小列表块的最大宽度,观感上就是导航栏内文字变小,变得更密集了。


上面是最简单的基础用法,接下来我们稍微复杂一点:
  1. 用数组的方法为导航栏(v-navigation-drawer) 添加连接
  2. 结合vue-router动态渲染主视图区

  • 首先安装vue-router:

    npm install vue-router
  • 然后在main.js里添加:

    1. import VueRouter from 'vue-router'

    2. Vue.use(VueRouter) //启用vue-router插件

    3. import router from './router' //引入我们自己的路由定义表

    4. router:router, //这行也可以简写为: router,

    5. render: function (h) { return h(App) }

  • 在与main.js平级的目录中创建一个router.js文件:

    1. import VueRouter from "vue-router";

    2. import hello from './components/hello'

    3. const originalPush = VueRouter.prototype.push;

    4. VueRouter.prototype.push = function push(location) {

    5. return originalPush.call(this, location).catch(err => err)

    6. } //以上三行是为了解决相同路由报错的问题,不用深究,照原样放在此就行了

    7. export default new VueRouter({

    8. {path: '/', component: hello},

    9. {path: '/msg/:msg', name: 'sayhi', component: hello},

    10. /*以上代码创建了两个路由,“/” 根路由和“/msg”

    11. 大白话解释根路由就是当我们在浏览器地址栏什么参数都不带,直接输入网址比如qq.com,页面应该跳到哪,

    12. 第二个路由/msg,就是说当我们在网址后面加一个/msg,比如qq.com/msg,页面应该跳到哪,所谓路由就是这个意思。*/

  • 在 src/components 目录中创建一个hello.vue文件:

    1. <h1>Hello {{ $route.params.msg}}</h1>

    2. <!-- 此处的$route.params.msg表示从路由/msg传递过来的参数 -->

    3. /* 以上就是一个最简单的vue组件,它由template和script两部分组成,template部分表示HTML代码,

    4. 很简单,就是显示一个H1级别的文字:Hello + 路由传过来的参数,

    5. JS部分其实并没有任何实质性内容,是一个空框架。 */

  • 修改app.vue文件,清空旧的内容,将以下内容全部复制粘贴进去:

    1. <v-navigation-drawer

    2. v-model="drawer"

    3. <v-list dense>

    4. <v-subheader class="mt-4 grey--text text--darken-1">操作选项</v-subheader>

    5. <!-- v-subheader 是组的标题 -->

    6. <v-list-item

    7. v-for="item in items"

    8. :key="item.text"

    9. @click="test(item.path)"

    10. link>

    11. <!-- v-for 是 vue的标准语法,item in items的 items 是一个数组,:key 表示唯一值 -->

    12. <v-list-item-action>

    13. <v-icon>{{ item.icon }}</v-icon>

    14. </v-list-item-action>

    15. <v-list-item-content>

    16. <v-list-item-title>

    17. {{ item.text }}

    18. </v-list-item-title>

    19. </v-list-item-content>

    20. <!-- v-list-item-action 是选项图标

    21. v-list-item-content 是选项的内容区

    22. v-list-item-title 是选项的文字

    23. </v-list-item>

    24. <v-subheader class="mt-4 grey--text text--darken-1">用户选项</v-subheader>

    25. <v-list-item

    26. v-for="item in items2"

    27. :key="item.text"

    28. @click="test(item.path)"

    29. link>

    30. <v-list-item-avatar>

    31. <!-- https://randomuser.me 是一个随机产生用户头像的趣味网站,此处从该网站获取头像图片 -->

    32. <img

    33. :src="`https://randomuser.me/api/portraits/men/${item.picture}.jpg`"

    34. alt="">

    35. </v-list-item-avatar>

    36. <v-list-item-title v-text="item.text"></v-list-item-title>

    37. </v-list-item>

    38. </v-list>

    39. <!-- 以下两个选项并没有用到数组,一般用于一些非动态的固定栏目 -->

    40. <v-list-item class="mt-4" link>

    41. <v-list-item-action>

    42. <v-icon color="grey darken-1">mdi-plus-circle-outline</v-icon>

    43. </v-list-item-action>

    44. <v-list-item-title class="grey--text text--darken-1">附加选项1</v-list-item-title>

    45. </v-list-item>

    46. <v-list-item link>

    47. <v-list-item-action>

    48. <v-icon color="grey darken-1">mdi-cog</v-icon>

    49. </v-list-item-action>

    50. <v-list-item-title class="grey--text text--darken-1">附加选项2</v-list-item-title>

    51. </v-list-item>

    52. </v-navigation-drawer>

    53. <!-- v-app-bar 是顶部栏,一般放一些操作类的按钮、搜索功能等 -->

    54. clipped-left

    55. color="cyan"

    56. <v-app-bar-nav-icon @click.stop="drawer = !drawer"></v-app-bar-nav-icon>

    57. <!-- 此处通过修改drawer变量来决定导航栏是否隐藏,PS:当宽度被压缩的时候导航栏自动隐藏(比如手机) -->

    58. <v-toolbar-title>我的第一个APP</v-toolbar-title>

    59. <v-main> <!-- v-main是主试图,一般指与用户交互信息最频繁的区域,尺寸也最大 -->

    60. class="fill-height"

    61. fluid>

    62. <router-view></router-view>

    63. <!-- router-view 是路由视图,APP的所有点击变化都在此反映,一般来说路由视图约等于主视图-->

    64. </v-container>

    65. <v-footer color="cyan" app> <!-- v-footer是最底部的页脚栏,一般用于放置版权信息之类杂项 -->

    66. <v-spacer></v-spacer>

    67. <span class="white--text">&copy; {{ new Date().getFullYear() }}</span>

    68. source: String,

    69. drawer: null,

    70. {icon: 'mdi-trending-up', text: '世界', path: 'Wolrd'},

    71. {icon: 'mdi-youtube-subscription', text: '太阳', path: 'Sun'},

    72. {icon: 'mdi-history', text: '月亮', path: 'Moon'},

    73. {icon: 'mdi-playlist-play', text: '星星', path: 'Star'},

    74. {icon: 'mdi-clock', text: '地球', path: 'Earth'},

    75. {picture: 28, text: 'Joseph',path:"约瑟夫"},

    76. {picture: 38, text: 'Apple',path:"苹果"},

    77. {picture: 48, text: 'Xbox',path:"叉博克斯"},

    78. {picture: 58, text: 'Nokia',path:"诺基亚"},

    79. {picture: 78, text: 'MKBHD',path:"爱慕凯碧爱趣帝"},

    80. test: function (path) {

    81. this.$router.push({name: "sayhi", params: {msg: path}})

  • 在命令行输入: npm run serve


运行结果如下,点击导航栏不同的菜单选项,触发vue-router产生不同的参数,主视图也会跟着一起改变:

image-20200830054159768.png

  • 后记

    本文纯粹属于抛砖引玉,对文中所涉及的概念没有进行深入的探讨,实际上每一块摊开来说都可以引申出很多内容来,笔者是一个从上古蛮荒时期走过来的前端爱好者(以前没有前端后端这么仔细的人员划分,统称为 “做网页的” )。因为当今的网页复杂程度比之过去的“电子书”级要大得多得多,我曾经尝试什么都不用,纯原生Javascript上马,弄了一段时间放弃了,再然后混入JQuery+Bootstrap,方案可行,但是UI不够现代化,PC端浏览效果尚可,但用移动端来浏览简直惨不忍睹。最后迫于无奈上了“框架”的车。但即便如此,当我碰到vue-router这种东西的时候,还是百思不得其解何必多此一举,他和HTML原生的<A href=”xxx”>xxx</a> 有毛线个区别?实际上Vue程序最终编译成原生JS代码后还不是用<A>实现的跳转。通过一段时间的沉浸,我发现这是没办法的事情,如果没有一个统一的路由表,全部由孤立的A跳转实现,规模小尚且可行,页面稍微复杂一点就得乱套。况且,vue-router内部将router和view进行了整合,你只需要push一个路由,router-view即可实现刷新。如果采用传统的A方案,实现局部刷新怎么弄,嵌一个iframe可以实现,后台用ajax刷新一个div也可以实现,问题是这么一来,将管理更多的代码,而且无法实现统一管理,我举这个例子只是众多传统思维和现代化思想的一个小碰撞,类似的案例多不胜数。这充分说明,IT业是一个随时都在推陈出新,无法固步自封依靠吃老本的行业。

  • 总的来说,单说前端:JS框架、Vue和Vuetify这三个关键词必须深入了解。

  • 从前后端整合的角度来说,影响最大的是 “RESTful”,本文没有提及,感兴趣的可以自行搜索。建议所有从上古时期走过来的前端爱好者,都必须掌握(至少了解)RESTful,这是一道必须跨过去的坎儿。