设计模式在vue中的应用(四)

栏目: 编程语言 · 发布时间: 5年前

内容简介:目录整理:

目录整理:

设计模式在vue中的应用(一)

设计模式在vue中的应用(二)

设计模式在vue中的应用(三)

设计模式在vue中的应用(四)

为什么要写这些文章呢。正如 设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结 (来自百度百科)一样,也是想通过分享一些工作中的积累与大家探讨 设计模式 的魅力所在。

在这个系列文章中为了辅助说明引入的应用场景都是工作中真实的应用场景,当然无法覆盖全面,但以此类推也覆盖到了常见的业务场景

今天的主角应该是我们在使用框架(如:vue、react)开发中使用最多的设计模式——模板方法模式

定义(来自网络):

模板方法模式在一个方法中定义一个算法的骨架,而将一些步骤的实现延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中某些步骤的具体实现

一、OOP实现

1、算法骨架

一个动物身体结构算法有:头部、身体、脚

// template class
// 注意:JavaScript里面没有接口的概念,与传统的OOP实现有一定的缺陷
class AnimalTemplate {
  constructor() {}
  head () {}
  body () {}
  foot () {}
  render () {
    // 算法过程 ———— 身体部位排列顺序头、身体、脚
    // render方法不能被子类重写,无法通过JavaScript本身实现需人为遵守
    this.head()
    this.body()
    this.foot()
  }
}
复制代码

2、子类算法实现

// 有一头猪
class Pig extends AnimalTemplate {
  head () {
    console.log('head from pig')
  }
  body () {
   console.log('body from pig')
  }
  foot () {
    console.log('foot from pig')
  }
}

const pig1 = new Pig()
pig1.render() // 执行算法

// 有一只鸡
class Chicken extends AnimalTemplate {
  head () {
    console.log('head from chicken')
  }
  body () {
   console.log('body from chicken')
  }
  foot () {
    console.log('foot from chicken')
  }
}
const chicken1 = new Chicken()
chicken1.render() // 执行算法
复制代码

二、react实现

react中有class组件采用上面OOP的实现完全没问题,但是继承的方式好像在react中不怎么受欢迎,更流行是函数式编程(props传递)

1、来一个很常见的场景

class Parent {
  constructor() {}
  render () {
    <div>
      <div name="tom"></div>
      <!-- 算法过程:children要渲染在name为joe的div中 -->
      <div name="joe">{this.props.children}</div>
    </div> 
  }
}
class Stage {
  constructor() {}
  render () {
    // 在parent中已经设定了children的渲染位置算法
    <Parent>
      // children的具体实现
      <div>child</div>
    </Parent> 
  }  
}
复制代码

所以我们在写jax时就已经是在使用模板方法模式

2、再次实现OOP中完成的例子

// 算法模板
class AnimalTemplate {
  constructor() {
    ...
  }
  render () {
    // 算法过程————头、身体、脚的顺序
    return (
      <div>
        {this.props.renderHead()}
        {this.props.renderBody()}
        {this.props.renderFoot()}
      </div>
    )
  } 
}
// 具体需求
class Stage {
  constructor() {}
  pigRenderHead () {
    return <div>pig head</div>
  }
  pigRenderBody () {
    return <div>pig body</div>
  }
  pigRenderFoot () {
    return <div>pig foot</div>
  }
  chickenRenderHead () {
    ...
  }
  chickenRenderBody () {
    ...
  }
  chickenRenderFoot () {
    ...
  }
  render () {
    <div>
      <AnimalTemplate
        renderHead={this.pigRenderHead}
        renderBody={this.pigRenderBody}
        renderFoot={this.pigRenderFoot}
      />
      <AnimalTemplate
        renderHead={this.chickenRenderHead}
        renderBody={this.chickenRenderBody}
        renderFoot={this.chickenRenderFoot}
      />
    </div>
    
  }  
}
复制代码

总结

通过这节相信大家对react的render props有了更清晰的认识

三、vue实现

有了上面两步的推导要理解模板方法模式在vue中的应用就比较简单了。

1,children在name为joe的div中

// parent.vue
<template>
  <div>
    <div name="tom"></div>
    <div name="joe">
      <!--vue中的插槽渲染children-->
      <slot />
    </div>
  </div>
</template>
复制代码
// stage.vue
<template>
  <div>
    <parent>
      <!-- children的具体实现 -->
      <div>child</div>
    </parent>
  </div>
</template>
复制代码

2、再次实现OOP中完成的例子

// AnimalTemplate.vue
<template>
  <div>
    <slot name="head"></slot>
    <slot name="body"></slot>
    <slot name="foot"></slot>
  </div>
</template>
复制代码
// stage.vue
<template>
  <div>
    <animal-template>
      <div slot="head">pig head</div>
      <div slot="body">pig body</div>
      <div slot="foot">pig foot</div>
    </animal-template>
    <animal-template>
      <div slot="head">chicken head</div>
      <div slot="body">chicken body</div>
      <div slot="foot">chicken foot</div>
    </animal-template>
  </div>
</template>
复制代码

总结

从OOP实现到react实现再推导出vue实现,现在大家应该能很轻松的理解在vue中模板方法模式的应用是怎样的

四、搞点事情

通过上面的介绍我们应该是掌握了模板方法模式的理论知识,有了新技能就应该应用下。

场景:

列表渲染应该是常见操作,不管是什么列表都会有一下几个特点:请求数据时显示loading状态、没有数据时给出提示、有数据就渲染列表

1,算法封装

根据模板方法模式的理论我们首先需要封装列表渲染的算法:

  • 请求数据 ——> loading
  • 数据为空 --> 空数据提示
  • 获取到数据 ——> 渲染列表
// renderList.vue
<template>
  <div>
    <img v-if="isLoading" src="./loading.gif" />
    <div v-if="isEmpty">数据为空</div>
    <div v-else>
      <div v-for="(item, index) in data" :key="index">
        <!-- vue中的作用域插槽 -->
        <slot name="item" :data="item" />
      </div>
    </div>
  </div>
</template>
<script>
  export default {
    name: 'RenderList',
    props: {
      isLoading: Boolean,
      data: Array,
    },
    computed: {
      isEmpty () {
        return this.data.length < 1
      }
    }
  }
</script>
复制代码

2,定义某些步骤的实现(列表项)

// stage.vue
<template>
  <div>
   <render-list :isLoading="isStudentsLoding" :data="students">
     <!-- 学生信息的渲染 -->
     <div slot="item" slot-scope="{ data }">
       <div>名字:{{ data.name }}</div>
       <div>年龄:{{ data.age }}</div>
     </div>
   </render-list>
   <render-list :isLoading="isFamilyLoading" :data="family">
     <!-- 家庭成员的渲染 -->
     <div slot="item" slot-scope="{ data }">
       <!-- 不同的DOM结构 -->
       <div>
         <span>称呼:{{ data.role }}</span>
         名字:{{ data.name }}
       </div>
     </div>
   </render-list>
  </div>
</template>
<script>
  import RenderList form './renderList'
  export default {
    data () {
      return {
        isStudentsLoding: false,
        isFamilyLoading: false,
        students: [
          { name: 'aa', age: '18' },
          { name: 'bb', age: '19' },
          { name: 'cc', age: '120' }
        ],
        family: [
          { name: 'aaaa', role: '爸爸' },
          { name: 'bbbb', role: '妈妈' },
          { name: 'cccc', role: '本人' },
        ]
      }
    },
    components: {
      RenderList   
    }
  }
</script>
复制代码

3,更复杂点

在上面渲染学生列表时我想将学生每科的成绩也展示出来,数据结构如下:

export default {
  ...
  data () {
    return {
      students: [
	    { name: '小明',
	      age: 16, 
	      score: [
	        { course: '语文', value: 86 },
	        { course: '数学', value: 88 }
	      ]
	    },
	    { name: '小李',
	      age: 16, 
	      score: [
	        { course: '语文', value: 90 },
	        { course: '数学', value: 85 }
	      ]
	    }
      ]
    }
  }
  ...
}
复制代码

在children中手动实现?

<render-list :isLoading="isStudentsLoding" :data="students">
 <div slot="item" slot-scope="{ data }">
   <div>名字:{{ data.name }}</div>
   <div>年龄:{{ data.age }}</div>
   <!-- 我们能拿到每个学生的信息,手动渲染成绩列表 -->
   <div v-for="score in data.score" :key="score.course">
     <slot name="score" :data="score" />
   </div>
 </div>
</render-list>
复制代码

调整我们的列表算法

上面的方式或许可以达到我们目的,但是要渲染列表对使用者来说要关心的事太多了,需要调整我们的算法模板

// renderList.vue
<template>
  <div>
    <img v-if="isLoading" src="./loading.gif" />
    <div v-if="isEmpty">数据为空</div>
    <div v-else>
      <div v-for="(item, index) in source" :key="index">
        <!-- 学生信息 -->
        <slot name="item" :data="item"></slot>
        <!-- 学生分数 -->
        <div class="score">
          <div v-for="score in item.score" :key="score.course">
            <slot name="score" :data="score" />
          </div>
        </div>
      </div>
    </div>
  </div>
</template>
复制代码
// stage.vue
<template>
  <div>
   <render-list :isLoading="isStudentsLoding" :data="students">
     <!-- 学生信息渲染规则 -->
     <div slot="item" slot-scope="{ data }">
       <div>名字:{{ data.name }}</div>
       <div>年龄:{{ data.age }}</div>
     </div>
     <!-- 学生成绩渲染规则 -->
     <div slot="score" slot-scope="{ data }">
       <div>——课程:{{ data.course }}</div>
       <div>——成绩:{{ data.value }}</div>
     </div>
   </render-list>
  </div>
</template>
复制代码

总结

这一篇主要分享了vue中slot的设计模式理念,结合列表渲染的场景向大家展示了模板方法模式的应用。

为什么开头说模板方法模式是vue、react开发中使用最多的设计模式?

通过上面的介绍相信大家已经感受到模板方法模式的特点:
1,封装一个算法模板
2,用户负责某一步的具体实现

现在想想vue,react内部封装好了diff算法、状态改变触发更新的机制、生命周期,我们在使用框架时只
需要按照语法规则使用它们的API完成我们的业务逻辑,这也就是模板方法模式
复制代码

本文实现同样适用于react,为什么文章以vue做题?vue的template让我们在理解一些概念的时候可能会有点不适应,而react的jsx可以看做就是在写JavaScript对各种概念实现更灵活

友情提示:设计模式在vue中的应用应该会写一个系列,喜欢的同学记得关注下


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Ruby on Rails实践之路

Ruby on Rails实践之路

沃哈 / 科学 / 2010-5 / 48.00元

《Ruby on Rails实践之路:写给PHP和Java开发者的书》内容简介:Ruby on Rails是基于MVC模式的Web框架,用于开发基于数据库的Web应用。Ruby on Rails中内含了所需的Web服务器WEBrick。该框架配置的数据库除了缺省的MySQL外,还可以是Oracle、SQL Server等其他数据库。《Ruby on Rails实践之路:写给PHP和Java开发者的......一起来看看 《Ruby on Rails实践之路》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换