前端路上的新长征
- 前言
从历史的角度来说,尽管几十年过去了,前端(即运行在浏览器里的程序)的基本结构还是以HTML(CSS)+Javascript为主,变化不大,曾经有一些脚本语言比如微软的VBS试图挑战过这个架构,均以失败告终(甚至连昙花一现都谈不上)。后端(服务器)方面则是百花齐放,方案众多,像是Java、PHP、GO、Python以及Javascript本身的一个分支Node.JS等等。
由于WEB技术的发展速度非常快,因此HTML与Javascript也在高速迭代,于是产生了 “框架” 这个概念,所谓框架就是一堆前人已经编写好的成体系的代码,其主要目的是不重复造轮子,加速开发效率。
前端框架大致上分为两个大类,侧重于HTML的CSS框架与侧重于Javascript的JS框架。
主流的Javascript框架:React、Angular、Vue
主流的CSS框架:Bootstrap、Element、Vuetifylk
像React、Vue这一类框架关注点是Javascript本身,更多的是属于处理逻辑层面的事务。而Bootstrap和Vuetify这一类CSS框架则着重关注HTML界面,页面布局,排版等视觉方面的事情。
在没有框架之前,所有前端开发者都采用原生HTML和原生Javascript,工作量极大。当然,你如果问:我们一定需要框架吗?答案却是否定的,国外就确实有一股势力是反对采用框架编程的,自诩为 "JS反框架联盟",为了不引战,此话题咱们不做深入探讨,见仁见智吧。
- PS: 本文以Vue + Vuetify为基础。
Vuetify 篇:
- Vuetify 号称是 Vue.js 的头号组件库,笔者使用过Bootstrap,因为年代久远已经忘得差不多了,具体特点也不做评价。外卖双雄之一的饿了吗也搞了CSS库,名字叫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包管理这个工具,调试和链接各种组件的难度将陡增,在此我还是建议从脚手架开始吧,等以后有闲了可以再去深入。
-
输入以下命令:
npm install -g @vue/cli
-
vue-cli安装好之后,vue命令就能使用了,用它创建一个项目,名称随意(此处为mini):
vue create mini //创建mini项目 cd mini vue add vuetify //添加vuetify组件
- 项目将会自动创建完成,并且自动生成以下目录结构:
-
问题是,如何运行一个vue程序? 很简单,在cmd命令行输入以下命令:
npm run serve
- 然后打开浏览器,输入网址:http://localhost:8080 即可。
一个最基础的APP界面如下:
如图所示,这是一个最简单的APP框架,包括
- 两个状态栏:v-app-bar(顶部)、v-footer(底部)
- 侧边功能导航栏:v-navigation-drawer
- 主视图区:v-content
最基础的主页代码,UI由<template>部分组成,JS代码包裹在<script>里:
<template>
<v-app id="inspire">
<v-navigation-drawer
v-model="drawer"
app
clipped>
<!-- vmodel: 显示开关,设为null的时候屏蔽导航栏
app : 是app = 'true'的简化语法,表示这个导航栏属于app的一部分
clipped: 等于clipped = 'true',表示导航栏采用压缩布局
-->
<v-list dense>
<v-list-item link>
<v-list-item-action>
<v-icon>mdi-home</v-icon>
</v-list-item-action>
<v-list-item-content>
<v-list-item-title>选项1</v-list-item-title>
</v-list-item-content>
</v-list-item>
<v-list-item link>
<v-list-item-action>
<v-icon>mdi-email</v-icon>
</v-list-item-action>
<v-list-item-content>
<v-list-item-title>选项2</v-list-item-title>
</v-list-item-content>
</v-list-item>
</v-list>
</v-navigation-drawer>
<v-app-bar
app
clipped-left
color="cyan"
dense
>
<v-app-bar-nav-icon @click.stop="drawer = !drawer"></v-app-bar-nav-icon>
<v-toolbar-title>Application</v-toolbar-title>
</v-app-bar>
<v-main>
<v-container
class="fill-height"
fluid
>
<h1>Hello World!</h1>
</v-container>
</v-main>
<v-footer
color="cyan"
app
>
<v-spacer></v-spacer>
<span class="white--text">© {{ new Date().getFullYear() }}</span>
</v-footer>
</v-app>
</template>
<script>
export default {
name: 'SimpleDemo',
props: {
source: String,
},
data: () => ({
drawer: null,
}),
}
</script>
上面是最简单的基础用法,接下来我们稍微复杂一点:
- 用数组的方法为导航栏(v-navigation-drawer) 添加连接
- 结合vue-router动态渲染主视图区
-
首先回到cmd命令行状态,输入以下命令安装vue-router:
npm install vue-router
-
然后在main.js里添加:
import VueRouter from 'vue-router' Vue.use(VueRouter) //启用vue-router插件 import router from './router' //引入我们自己的路由定义表 new Vue({ vuetify:vuetify, router:router, //这行也可以简写为: router, render: function (h) { return h(App) } }).$mount('#app')
-
在与main.js平级的目录中创建一个router.js文件:
import VueRouter from "vue-router"; import hello from './components/hello' const originalPush = VueRouter.prototype.push; VueRouter.prototype.push = function push(location) { return originalPush.call(this, location).catch(err => err) } //以上三行是为了解决相同路由报错的问题,不用深究,照原样放在此就行了 export default new VueRouter({ mode: 'history', routes: [ {path: '/', component: hello}, {path: '/msg/:msg', name: 'sayhi', component: hello}, ] }) /*以上代码创建了两个路由,“/” 根路由和“/msg” 大白话解释根路由就是当我们在浏览器地址栏什么参数都不带,直接输入网址比如qq.com,页面应该跳到哪, 第二个路由/msg,就是说当我们在网址后面加一个/msg,比如qq.com/msg,页面应该跳到哪,所谓路由就是这个意思。*/
-
在 src/components 目录中创建一个hello.vue文件:
<template> <h1>Hello {{ $route.params.msg}}</h1> <!-- 此处的$route.params.msg表示从路由/msg传递过来的参数 --> </template> <script> export default { name: 'hello', data: () => ({ }), } /* 以上就是一个最简单的vue组件,它由template和script两部分组成,template部分表示HTML代码, 很简单,就是显示一个H1级别的文字:Hello + 路由传过来的参数, JS部分其实并没有任何实质性内容,是一个空框架。 */ </script>
-
修改app.vue文件,清空旧的内容,将以下内容全部复制粘贴进去:
<template> <v-app id="inspire"> <v-navigation-drawer v-model="drawer" app clipped> <v-list dense> <v-subheader class="mt-4 grey--text text--darken-1">操作选项</v-subheader> <!-- v-subheader 是组的标题 --> <v-list-item v-for="item in items" :key="item.text" @click="test(item.path)" link> <!-- v-for 是 vue的标准语法,item in items的 items 是一个数组,:key 表示唯一值 --> <v-list-item-action> <v-icon>{{ item.icon }}</v-icon> </v-list-item-action> <v-list-item-content> <v-list-item-title> {{ item.text }} </v-list-item-title> </v-list-item-content> <!-- v-list-item-action 是选项图标 v-list-item-content 是选项的内容区 v-list-item-title 是选项的文字 --> </v-list-item> <v-subheader class="mt-4 grey--text text--darken-1">用户选项</v-subheader> <v-list> <v-list-item v-for="item in items2" :key="item.text" @click="test(item.path)" link> <v-list-item-avatar> <!-- https://randomuser.me 是一个随机产生用户头像的趣味网站,此处从该网站获取头像图片 --> <img :src="`https://randomuser.me/api/portraits/men/${item.picture}.jpg`" alt=""> </v-list-item-avatar> <v-list-item-title v-text="item.text"></v-list-item-title> </v-list-item> </v-list> <!-- 以下两个选项并没有用到数组,一般用于一些非动态的固定栏目 --> <v-list-item class="mt-4" link> <v-list-item-action> <v-icon color="grey darken-1">mdi-plus-circle-outline</v-icon> </v-list-item-action> <v-list-item-title class="grey--text text--darken-1">附加选项1</v-list-item-title> </v-list-item> <v-list-item link> <v-list-item-action> <v-icon color="grey darken-1">mdi-cog</v-icon> </v-list-item-action> <v-list-item-title class="grey--text text--darken-1">附加选项2</v-list-item-title> </v-list-item> </v-list> </v-navigation-drawer> <!-- v-app-bar 是顶部栏,一般放一些操作类的按钮、搜索功能等 --> <v-app-bar app clipped-left color="cyan" dense> <v-app-bar-nav-icon @click.stop="drawer = !drawer"></v-app-bar-nav-icon> <!-- 此处通过修改drawer变量来决定导航栏是否隐藏,PS:当宽度被压缩的时候导航栏自动隐藏(比如手机) --> <v-toolbar-title>我的第一个APP</v-toolbar-title> </v-app-bar> <v-main> <!-- v-main是主试图,一般指与用户交互信息最频繁的区域,尺寸也最大 --> <v-container class="fill-height" fluid> <router-view></router-view> <!-- router-view 是路由视图,APP的所有点击变化都在此反映,一般来说路由视图约等于主视图--> </v-container> </v-main> <v-footer color="cyan" app> <!-- v-footer是最底部的页脚栏,一般用于放置版权信息之类杂项 --> <v-spacer></v-spacer> <span class="white--text">© {{ new Date().getFullYear() }}</span> </v-footer> </v-app> </template> <script> export default { name: 'sayhi', props: { source: String, }, data: () => ({ drawer: null, items: [ {icon: 'mdi-trending-up', text: '世界', path: 'Wolrd'}, {icon: 'mdi-youtube-subscription', text: '太阳', path: 'Sun'}, {icon: 'mdi-history', text: '月亮', path: 'Moon'}, {icon: 'mdi-playlist-play', text: '星星', path: 'Star'}, {icon: 'mdi-clock', text: '地球', path: 'Earth'}, ], items2: [ {picture: 28, text: 'Joseph',path:"约瑟夫"}, {picture: 38, text: 'Apple',path:"苹果"}, {picture: 48, text: 'Xbox',path:"叉博克斯"}, {picture: 58, text: 'Nokia',path:"诺基亚"}, {picture: 78, text: 'MKBHD',path:"爱慕凯碧爱趣帝"}, ], }), methods: { test: function (path) { this.$router.push({name: "sayhi", params: {msg: path}}) } } } </script>
在命令行输入: npm run serve
运行结果如下,点击导航栏不同的菜单选项,触发vue-router产生不同的参数,主视图也会跟着一起改变:
- 后记
本文纯粹属于抛砖引玉,对文中所涉及的概念并没有进行深入的探讨,不过万事开头难,希望我这个简单的框架能带你快速进入角色,开启你的前端探秘之旅。下面提供几个链接供大家做深入学习之用: -
https://vuetifyjs.com/zh-Hans/
(Vuetify官网,文档非常详尽,而且有简体中文版) -
https://www.jianshu.com/p/4c5c99abb864
(一篇很不错的vue-router教程) -
http://www.ruanyifeng.com/blog/2015/07/flex-grammar.html
(阮一峰老师的布局教程) - http://www.ruanyifeng.com/blog/2014/05/restful_api.html
-
http://www.ruanyifeng.com/blog/2011/09/restful.html
(阮一峰老师关于Restful风格编程的两篇指南,Restful是现在WEB编程的主选方案)