zoukankan      html  css  js  c++  java
  • 【技术博客】Vue组件开发总结

    Vue是一套工程化、便于多人合作开发的基于视图层的前端开发框架。我们最初选用Vue,因为其简便且易于学习上手,组件化的开发思路适合多人合作开发,而且也支持多种现代化的工具链,比如UI库ivew、JavaScript实用库lodash、和后端数据交互的axios等。
    下文会略微提及Vue入门基础知识,然后主要阐述Vue组件开发的实践经历。

    Vue特性

    在一门Vue入门的慕课中,提及了Vue的三大特性:

    • 前端工程化
    • 双向绑定 MVVM
    • 组件化开发

    下面简要说明一下我对这三个概念的理解

    前端工程化

    总所周知,之前的前端开发,是依靠HTML+CSS+JavaScript。这种开发模式,在某些情况下是极其繁琐的。比如事件绑定的情况:

    document.getElementById('dom').addEventListener('click', function(e) {
      ...
    });
    

    上述代码的绑定方式,对于多个对象的多事件绑定,会极其繁琐,而且要写大量的重复代码。而Vue采用的方法是组件内的事件触发和方法绑定,简易了很多。

    <div @click="clickMethod">
    </div>
    
    methods: {
      clickMethod() {
        ...
      }
    }
    

    相似的例子还有很多。而且Vue也提供了很多辅助工程化开发的工具,比如基本脚手架(vue-cli)、包管理工具(yarn)、代码规范(eslint)等,都有助于前端工程化开发。

    双向数据绑定

    双向数据绑定,或者说MVVM,说的是程序的数据(model)和视图(view)之间的架构模式。前端使用的架构模式还有MVC、MVP等等,双向数据绑定的识别模式也可以参考这篇博客。相关理论很多,但是在实际编程中,理解视图的值发生更改后,数据的值也会更改,数据的值发生更改,触发视图内容更改即可。

    <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数据的例子。

    组件化开发

    组件化、模块化,相信各位一定都听说过类似的术语。说白了,也就是把上万行的程序分成几个几千或者几百行的文件,再把这些文件拆分成几十行的函数或者方法。拆分不是个难事,但是怎么拆分能让多人合作的时候分工明确,怎么拆分能让数据接口尽可能简洁,怎么拆分能避免程序单模块和组织上的bug。这都是拆分时需要考虑的事项。

    所以我们组件化开发,一是做了前端视图上的拆分。举个例子:
    页面视图组件化

    这是我们文献管理的界面,其中以视图为单位的组件有页面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等组件。下面会对这些组件进行简要的介绍。

    与后端的接口apis

    与后端的接口采用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

    viewsDir

    其中RoadmapLayout.vue设定了整体页面视图架构(参考iview),在Layout的基础上,加入ArticleTableViewRoadmapEditorViewWelcomeCardView等组件,形成几个主要页面的组织。比如下方,header、footer是layout中的元素,加入WelcomeCard组件后形成主页显示界面。

    layout2view

    在主页面的基础上,添加各个页面的模块组件,比如边栏、表单、图表、画布、编辑器、按钮等组件,完成整体页面的制作。

    component2view

    组件的代码结构

    通过上面的几张图,想必大家已经了解了组件开发的大概思路,感受到了Vue通过组件化开发,能够达到的效果。但是在代码层面,怎么把组件连接起来,还是不够清楚。

    所以下面会从代码层面介绍,通过一些什么样的方法,能够实现上述效果。

    1. 父子组件概念

    在上一节的例子,layout是WelcomeCard的父组件,而RoadmapView又是RoadmapEditor的component的父组件。下图也可清晰的看到RoadmapEditor页面中到侧边栏Item的父子组件调用树状关系。

    父子组件树状关系
    1. 父子组件构建

    下面写一下父子组件构建的代码

    <!-- 父组件中 -->
    <div>
      <child></child>
    </div>
    
    <script>
    import child from './child';
    
    export default {
      components: {child}
    }
    </script>
    
    <!-- 子组件中 -->
    <script>
    export default {
      name: 'child',
    }
    </script>
    
    1. 父子组件互相传值

    页面中,除了父子组件的概念及其代码架构,父子组件之间的交互和传值对于页面的响应和触发也极为重要。因此下面介绍父组件向子组件传值的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的内容,以获取更深入的认识。

  • 相关阅读:
    JavaScript原型、闭包、继承和原型链等等总结
    JS创建对象的几种方式整理
    js中 给json对象添加属性和json数组添加元素
    JSON 数组
    httpclient封装
    java 数字和日期处理
    jmeter所有版本下载路径
    idea的使用
    Java环境的搭建
    Axure8.0可用的授权码
  • 原文地址:https://www.cnblogs.com/yzy11235/p/12968328.html
Copyright © 2011-2022 走看看