Vue是一套工程化、便于多人合做开发的基于视图层的前端开发框架。咱们最初选用Vue,由于其简便且易于学习上手,组件化的开发思路适合多人合做开发,并且也支持多种现代化的工具链,好比UI库ivew、JavaScript实用库lodash、和后端数据交互的axios等。
下文会略微说起Vue入门基础知识,而后主要阐述Vue组件开发的实践经历。html
在一门Vue入门的慕课中,说起了Vue的三大特性:前端
下面简要说明一下我对这三个概念的理解vue
总所周知,以前的前端开发,是依靠HTML+CSS+JavaScript。这种开发模式,在某些状况下是极其繁琐的。好比事件绑定的状况:webpack
document.getElementById('dom').addEventListener('click', function(e) { ... });
上述代码的绑定方式,对于多个对象的多事件绑定,会极其繁琐,并且要写大量的重复代码。而Vue采用的方法是组件内的事件触发和方法绑定,简易了不少。ios
<div @click="clickMethod"> </div> methods: { clickMethod() { ... } }
类似的例子还有不少。并且Vue也提供了不少辅助工程化开发的工具,好比基本脚手架(vue-cli)、包管理工具(yarn)、代码规范(eslint)等,都有助于前端工程化开发。git
双向数据绑定,或者说MVVM,说的是程序的数据(model)和视图(view)之间的架构模式。前端使用的架构模式还有MVC、MVP等等,双向数据绑定的识别模式也能够参考这篇博客。相关理论不少,可是在实际编程中,理解视图的值发生更改后,数据的值也会更改,数据的值发生更改,触发视图内容更改便可。web
<div v-if="viewStyle==='chart'"> <!-- show chart --> </div> <div v-else-if="table"> <!-- show table --> </div> data() { viewStyle: 'chart' }
上面的代码示例也是说明model到view的一个例子,数据中的viewStyle
从’chart‘改变为’table‘时,视图也随之改变。而从view到model的例子,好比Input文本框,就是一个典型的用户view中输入,改变model数据的例子。vuex
组件化、模块化,相信各位必定都据说过相似的术语。说白了,也就是把上万行的程序分红几个几千或者几百行的文件,再把这些文件拆分红几十行的函数或者方法。拆分不是个难事,可是怎么拆分能让多人合做的时候分工明确,怎么拆分能让数据接口尽量简洁,怎么拆分能避免程序单模块和组织上的bug。这都是拆分时须要考虑的事项。vue-cli
因此咱们组件化开发,一是作了前端视图上的拆分。举个例子:
编程
这是咱们文献管理的界面,其中以视图为单位的组件有页面layout组件,页面索引组件、文献建立表单组件、表格组件、表格扩展组件和问卷调查组件。从中咱们能够看出一个Vue的页面也就是多个组件的叠加。在组件划分时,能够从页面总体规划入手,或整为零的去划分。
除了视图上的划分,还有工程逻辑上的划分。好比和后端数据接口axios、前端的页面跳转router,各类页面的图标,也都是重要的前端开发组件因此在此基础上,也就引出了咱们项目的代码架构。
README.md config/ src ├── App.vue ├── apis │ ├── User.js │ └── util.js ├── assets │ ├── HomePageLogo.png │ └── logo.png ├── components │ └── ErrPush.js ├── main.js ├── router │ └── index.js ├── views │ ├── Layout.vue │ ├── UserLoginView.vue │ └── UserRegisterView.vue └── vuex └── index.js build/ index.html package.json yarn.lock .eslintrc.js .gitignore
上述代码结构中,有GitHub工程相关文件,有yarn包管理相关文件,有知道yarn编译的build文件夹和config配置文件夹。其中,src是源码组织和组件分文件撰写的目录,其中有上面提到的apis(axios)、assets、components、router、views等组件。下面会对这些组件进行简要的介绍。
与后端的接口采用Node.js的http库axois,代码中对axios进行实例的建立
// eslint-disable-next-line no-unused-vars const instanceAuth = axios.create({ headers: { 'Access-Control-Allow-Origin': '*', }, });
并对错误状态进行处理
instanceAuth.interceptors.response.use( response => response, (error) => { if (error.response) { // code: 错误状态码, response:错误响应信息,error:原始错误信息 switch (error.response.status) { case 400: return Promise.reject({ code: 4000, response: error.response, error }); // 客户端请求有语法错误 case 401: // 请求未经受权 { store.commit('pushAuthToken', ''); router.push({ name: 'Login' }); return Promise.reject({ code: 4010, response: error.response, error }); } case 404: return Promise.reject({ code: 4040, response: error.response, error }); // 页面未找到 case 403: return Promise.reject({ code: 4030, response: error.response, error }); // Bad Gateway case 500: return Promise.reject({ code: 5000, response: error.response, error }); // Server Error default: return Promise.reject({ code: -1, response: error.response, error }); // 不常见错误 } } else { return Promise.reject({ code: -1, response: {}, error }); } }, );
随后对数据获取请求进行了封装
export const reqSingle = (url, _method, params_or_data = {}) => { const method = _method.toUpperCase(); let options; if (method === 'POST' || method === 'PUT' || method === 'PATCH') { options = { method, url, data: params_or_data, }; } else { options = { method, url, params: params_or_data, }; } return instanceAuth(options); };
而在实际组件的使用中,也能够对数据的增删改查api进行更组件化的封装,来减小冗余代码,使代码更加清晰简明。
// eslint-disable-next-line import/prefer-default-export export const createArticleTabledata = (title, author, url, note, journal, ref) => req( '/api/articles/', 'POST', {}, { title, author, url, note, journal, article_references: ref }); export const deleteArticleTabledata = id => req( `api/articles/${id}/`, 'DELETE'); export const changeArticleTabledata = data => req( `api/articles/${data.id}/`, 'PATCH', {}, data);
前端页面显示,主要分布在src/views
。
其中RoadmapLayout.vue
设定了总体页面视图架构(参考iview),在Layout的基础上,加入ArticleTableView
、 RoadmapEditorView
、WelcomeCardView
等组件,造成几个主要页面的组织。好比下方,header、footer是layout中的元素,加入WelcomeCard组件后造成主页显示界面。
在主页面的基础上,添加各个页面的模块组件,好比边栏、表单、图表、画布、编辑器、按钮等组件,完成总体页面的制做。
经过上面的几张图,想必你们已经了解了组件开发的大概思路,感觉到了Vue经过组件化开发,可以达到的效果。可是在代码层面,怎么把组件链接起来,仍是不够清楚。
因此下面会从代码层面介绍,经过一些什么样的方法,可以实现上述效果。
在上一节的例子,layout是WelcomeCard的父组件,而RoadmapView又是RoadmapEditor的component的父组件。下图也可清晰的看到RoadmapEditor页面中到侧边栏Item的父子组件调用树状关系。
下面写一下父子组件构建的代码
<!-- 父组件中 --> <div> <child></child> </div> <script> import child from './child'; export default { components: {child} } </script> <!-- 子组件中 --> <script> export default { name: 'child', } </script>
页面中,除了父子组件的概念及其代码架构,父子组件之间的交互和传值对于页面的响应和触发也极为重要。所以下面介绍父组件向子组件传值的props代码架构(props也可参考官网说明)下面代码略去和上述代码的重复部分
<!-- 父组件中 --> <div> <child :sucData="fatherData"> </child> </div> <script> export default { data() { return { fatherData : [], }, }, }; </script> <!-- 子组件中 --> <script> export default { props: { sucData: { type: Array, required: true, }, }, }; </script>
除了子组件会接收父组件的数据以外,也会向父组件触发事件,并传递参数,这里须要用到emit方法,来完成触发。举例以下:
<!-- 父组件中 --> <div> <child @childEvent="childEvent"> </child> </div> <script> export default { method: { childEvent(par) { // do something }; }, }; </script> <!-- 子组件中 --> <Button @click="onClick"></Button> <script> export default { method: { onClick() { this.$emit('childEvent', par); } }, }; </script>
页面的跳转也是页面中极其重要的一个功能,这部分的内容由组内的另外一位同窗负责完成技术博客
经过此次软件工程编程,初步认识了Vue这一现代化的前端开发框架,并且本身也完成了几个主要页面的编写,收获颇丰。以后会继续深刻webpack的内容,以获取更深刻的认识。