为了账号安全,请及时绑定邮箱和手机立即绑定
慕课专栏

目录

索引目录

mpvue原理深入解析36讲

限时优惠 ¥ 38.00

原价 ¥ 49.00

09月13日后恢复原价

限时优惠
立即订阅
04 第二式:计算属性和监听器
作者:Sam 更新时间:2019-08-14 14:08:38
人的一生可能燃烧也可能腐朽,我不能腐朽,我愿意燃烧起来!

——奥斯特洛夫斯基

本小节将围绕计算属性和监听器两块内容进行展开,分为三方面分别进行讲解:

  1. Vue 框架的计算属性和监听器
  2. 微信小程序的计算属性和监听器
  3. mpvue 框架的计算属性和监听器

Vue 框架的计算属性和监听器

1 计算属性

计算属性和监听器是 Vue 框架的重要概念。计算属性的目标是简化模板中的运算逻辑,下面是一个 Vue 框架的案例,我们需要手动创建一个 index.html 文件,并填入下面的代码:

<!DOCTYPE>
<html>
  <head>
    <title>Vue Computed</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  </head>
  <body>
    <div id="app">{{computedMessage}}</div>
    <script>
      new Vue({
        el: '#app',
        computed: {
          computedMessage() {
            return 'This is ' + this.message.toLowerCase() + '.'
          }
        },
        data() {
          return { 
            message: 'A COMPUTED MESSAGE' 
          }
        }
      })
    </script>
  </body>
</html>

可以看到计算属性 computedMessage 可以直接填入模板语法中,如果我们修改 message,那么计算属性会根据 message 的新值重新运算后通知视图更新。计算属性使用时需要注意三点:

  1. 计算属性不支持传入参数,如果需要传入参数,请使用 methodscomputed 的最大优势在于运算后的数据会进行缓存,而 methods 每次状态更新时都要进行重新调用,而如果 computed 依赖的状态不更新,就不会重新计算。值得注意的是,Vue 框架会将 Vue 实例注入计算属性作为参数;
  2. 计算属性如果定义为 function 将不支持修改,如果需要修改,请添加 set 方法。如果未提供 set 方法直接修改会触发以下错误:
vue.js:634 [Vue warn]: Computed property "computedMessage" was assigned to but it has no setter.

getset 定义方法如下:

computed: {
  computedMessage: {
    set(value) {
      this.message = value
    },
      get() {
        return this.message.toLowerCase()
      }
  }
}
  1. 计算属性不能与 data 中的状态重名,如果发生重名会收到一个报错:
vue.js:634 [Vue warn]: The computed property "message" is already defined in data.

因为 coumputed 最终会解析为一个状态,并挂载到 Vue 实例的根节点,所以如果与 data 中的状态重名,挂载时就会出现覆盖的情况,为了避免这种情况,Vue 框架禁止 datacomputedmethods 重名。

提示:computed 与普通状态的区别是具备缓存值,但他们都具备响应式的特点,所以可以将 computed 理解为其他状态的一个包裹,不得不说计算属性这个翻译非常贴切。

2 监听器

监听器的主要应用场景是监听状态变化,并主动响应变化,我们修改 index.html 代码:

<!DOCTYPE>
<html>
  <head>
    <title>Vue Watch</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  </head>
  <body>
    <div id="app">
      <input type="text" v-model="name">
      <div>{{message}}</div>
    </div>
    <script>
      new Vue({
        el: '#app',
        watch: {
          name(newName, oldName) {
            this.message = 'name changed! new name: ' + newName + ',old name: ' + oldName
          }
        },
        data() {
          return { 
            message: '',
            name: ''
          }
        }
      })
    </script>
  </body>
</html>

上面代码只做了一件事:监听状态 name 的变化,一旦 name 发生变化,watch 就会监听到,并修改 message 的值,显示变化的过程:

图片描述
由于 computed 通常可以获得更好的性能,所以在可以使用的 computed 的场景不推荐使用 watch

微信小程序实现计算属性和监听器

微信小程序默认不支持计算属性和监听器,但官方提供了 computed 库,有了 computed 库,我们就通过 Component + behavior 的方式实现计算属性和监听器了,这里涉及的新知识点较多,本节我们重点讲解微信小程序使用 npm 流程及计算属性和监听器的实际案例,关于 Componentbehaviorobservers 等小程序组件相关的概念我们将在第七式组件化中为大家进行讲解,并且会带大家一起深入分析 computed 库源码。

1 微信小程序使用 npm 流程

下面我们将对 my-wx-project 进行增强,让它能够支持引入第三方的 npm 库。微信小程序中使用 npm 库主要需要三步:npm 项目的初始化、npm 包的下载和通过微信开发者工具完成 npm 构建。

npm 初始化

在终端中进入 my-wx-project 项目目录,输入以下指令快速完成 npm 项目初始化:

npm init -y

此步完成后,会在项目目录下创建package.json文件。

npm 包下载

我们需要借助 computed 库实现计算属性和监听器,所以要通过 npm 安装这个包:

$ npm install --save miniprogram-computed

npm WARN my-wx-project@1.0.0 No description
npm WARN my-wx-project@1.0.0 No repository field.

+ miniprogram-computed@2.0.1
updated 1 package and audited 1 package in 2.062s
found 0 vulnerabilities

安装成功后,会在项目目录下创建 node_modules 目录,目录下包含了 miniprogram-computed 库。

npm 构建

npm 包下载完成后,我们需要在微信开发者工具中,打开详情,勾选使用 npm 模块,在项目中启用 npm 模块:

图片描述
然后在微信开发者工具中选择工具=>构建 npm,构建成功后会在项目目录下创建 miniprogram_npm 目录,该目录下包含了我们 node_modules 中的 computed 库:

图片描述
经过上述改造后,此时项目目录如下:

├── app.json # 小程序主配置文件
├── index.js # 小程序逻辑文件
├── index.wxml # 小程序样式文件
├── index.wxs # 自定义过滤器
├── miniprogram_npm # 小程序npm库文件目录
├── node_modules # npm库文件目录
├── package-lock.json # npm自动生成文件,管理npm库版本
├── package.json # npm主配置文件
├── project.config.json # 微信小程序开发者工具配置文件
└── sitemap.json # 用于配置小程序及其页面是否允许被微信索引

2 计算属性应用案例

在微信小程序中我们无法直接在 Page 使用计算属性,需要借助 Component 来实现,Component 是小程序的标准组件,功能非常强大。要使用 Component 来实现计算属性,需要三步:创建、开发和集成,下面详细说明:

Component 创建

我们先在项目根路径下创建 components 目录,然后在 components 目录中创建三个文件:computed.jscomputed.jsoncomputed.wxml,创建后目录结构如下:

├── components
│   ├── computed.js
│   ├── computed.json
│   └── computed.wxml

Component 开发

  • computed.json:配置启用组件,这个配置是必须的,否则 Component 将无法生效:
{
  "component": true
}
  • computed.js
const computedBehavior = require('miniprogram-computed') // 引用miniprogram-computed库

Component({
  behaviors: [computedBehavior], // 将miniprogram-computed库混入Component
  data: {
    message: 'A COMPUTED MESSAGE' // 定义组件的状态
  },
  computed: {
    computedMessage(data) { // 定义组件的计算属性
			return 'This is ' + data.message.toLowerCase() + '.'
		}
  }
})

上述代码我们将 Vue 框架的计算属性案例移植到小程序中,可以看到微信小程序的 computed 与 Vue 框架的最大差异是不支持使用 this,只能使用入参 data 获得组件的状态和父组件传入的状态(类似 Vue 框架中的 props)。实现 computed 有一个关键步骤:

behaviors: [computedBehavior]

behaviorsComponent 的扩展属性,它实现了代码混入,目的是为了方便代码复用,它与 Vue 框架的 mixins 概念如出一辙。上述代码实现了将 miniprogram-computed 库混入到 Component 中,这一点,我们会在第七式组件化源码分析中详细为大家讲解。这里先通过一个简单的例子为大家演示 Vue 框架的 mixins 特性:

<!DOCTYPE>
<html>
  <head>
    <title>Vue Watch</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  </head>
  <body>
    <div id="app">
      <div>{{message}}</div>
    </div>
    <script>
      const dataMixin = {
        data() {
          return {
            firstName: 'Xiao' // 混入代码定义了firstName
          }
        }
      } // 定义代码混入的对象,它和Vue的options参数格式一致
      new Vue({
        el: '#app',
        mixins: [dataMixin], // 将自定义对象混入,Vue会自动将这个对象与options对象合并
        computed: {
          message() {
            return this.firstName + ' ' + this.lastName // Computed可以直接获取混入代码定义的状态
          }
        },
        data() {
          return { 
            lastName: 'Mu' // data中只定义lastName状态
          }
        }
      })
    </script>
  </body>
</html>

上述代码运行后结果如下:

Xiao Mu

Vue 框架的 mixins 设计初衷是为了方便多组件之间通用代码的复用,mixins 代码是一个对象,它的结构与 Vue 框架构造函数的入参 options 结构一致,Vue 框架实例化过程中会将 optionsmixins 代码进行融合。微信小程序的 behaviormixins 的概念是一致的,默认情况下 Component 是不支持 computed 属性的,但是通过混入 miniprogram-computed 即可支持。

  • computed.wxml:组件的布局文件与 Page 没有差别
<view>{{computedMessage}}</view>

至此,computed 就开发完了,接下来我们需要将这个组件集成到 Page 中。

Component 集成

与 Vue 框架不同,小程序无法直接使用组件,而必须在配置文件中进行注册,我们创建 index.json,并填写配置信息:

{
  "usingComponents": {
    "computed": "./components/computed"
  }
}

修改 index.wxml

<computed />

此时模拟器上会出现:

This is a computed message.

说明计算属性应用成功,如果我们修改组件中的 message 的值,computedMessage 的值会随之改变。此时项目的目录结构如下:

├── app.json
├── components # 新增组件
│   ├── computed.js # 组件的逻辑文件
│   ├── computed.json # 组件的配置文件
│   └── computed.wxml # 组件的布局文件
├── index.js
├── index.json # 新增index页面的配置文件
├── index.wxml
├── index.wxs
├── miniprogram_npm
│   └── miniprogram-computed
├── node_modules
│   └── miniprogram-computed
├── package-lock.json
├── package.json
├── project.config.json
└── sitemap.json

3 监听器应用案例

有了上述计算属性组件后,我们可以非常快速地添加监听器,我们修改 computed.js 添加监听器:

const computedBehavior = require('miniprogram-computed')

Component({
  behaviors: [computedBehavior],
  data: {
    a: 1,
    b: 2,
    c: {
      d: 3
    }
  },
  computed: {
    sum(data) {
      return data.a * data.b
    }
  },
  watch: {
    'a': function(a) { // 监听单个状态
      console.log(a)
    },
    'a, b, sum': function(a, b, sum) { // 同时监听状态a、b和sum的变化
      console.log(a, b, sum)
    },
    'c.d': function(d) { // 监听对象c的d属性变化
      console.log(d)
    }
  },
  methods: {
    add() {
      this.setData({
        a: this.data.a + 1,
        b: this.data.b + 1,
        c: {
          d: this.data.c.d + 1
        }
      })
    }
  }
})

微信小程序 computed 库的监听器功能比较强大,它包含三个重要特性:

  1. 支持监听多个状态,只要一个状态发生变化,该状态相关的所有监听器都会被触发。这个特性得益于微信小程序组件的 observers 特性,这个特性也是监听器的实现原理;
  2. 支持监听计算属性(因为计算属性会注入 data 中作为一个响应式状态,所以可以被监听);
  3. 支持监听对象的某一个特定属性,这个特性也与小程序组件的 observers 有关。

我们继续修改 computed.wxml 查看效果:

<view>{{a}},{{b}},{{sum}}</view>
<view>{{c.d}}</view>
<button bindtap="add">add</button>

当我们点击按钮时,触发 add 方法,修改了属性 abc.d 的值,这时三个监听器都会被触发,与 computed 不同,监听器中可以获得 this,从而实现更多复杂的功能。

mpvue 实现计算属性和监听器

mpvue 框架实现计算属性与 Vue 框架的体验几乎一致,这也是 mpvue 框架令人兴奋之处,因为它原汁原味地保留了 Vue 框架的很多优秀特性。但是 mpvue 对计算属性和监听器的实现原理与微信小程序完全不同,mpvue 依赖 Vue 实现这两个特性,而微信小程序依赖 Component 特性实现。mpvue 的方案通用性更好,因为其他小程序平台很可能不支持 Component 特性,或者实现方式有差异,如果 mpvue 依赖 Component 实现计算属性,那么不同平台适配成本很高。下面我们基于 mpvue 来实现计算属性和监听器,一起打开 wx-mpvue-project 项目进行修改。

1 mpvue 实现计算属性

修改 src/pages/index/index.vue

<template>
  <div>
    <div>{{computedMessage}}</div>
  </div>
</template>

<script>
  export default {
    computed: {
      computedMessage() {
        return 'This is ' + this.message.toLowerCase() + '.'
      }
    },
    data() {
      return {
        message: 'A COMPUTED MESSAGE'
      }
    }
  }
</script>

使用微信开发者工具查看编译后的结果:

This is a computed message.

不得不说 mpvue 框架实现计算属性的体验很棒。

2 mpvue 实现监听器

再次修改 src/pages/index/index.vue

<template>
  <div>
    <input v-model="name" />
    <div>{{message}}</div>
  </div>
</template>

<script>
  export default {
    watch: {
      name(newName, oldName) {
        this.message = 'name changed! new name: ' + newName + ',old name: ' + oldName
      }
    },
    data() {
      return {
        message: '',
        name: ''
      }
    }
  }
</script>

在界面中的输入框内输入 aaa,可以看到 message 显示为:

name changed! new name: aaa,old name: aa

Tip:小程序的 input 组件默认是没有边框的,所以很容易形成没有显示成功的错觉,大家只需要直接点击界面,就可以获得焦点了!

总结

本节我们讲解了 Vue、mpvue 和微信小程序如何实现计算属性和监听器,下面我们做个整体回顾:

1. 计算属性 computed

  • 实现方式对比:
    • Vue 和 mpvue 的实现一致,都是通过 Vue 实例化时传入 computed 参数实现;
    • 微信小程序默认不支持 computed 特性,需要使用官方的 computed 库来实现,实现原理是通过 behavior 混入 computed 库源码,动态添加 computed 特性。
  • 使用方法差异:
    • Vuempvuecomputed入参是vm,即Vue实例,方法中可直接使用this获得Vue实例,默认不支持setter方法,需要手动添加set属性解决;
    • 微信小程序的computed不能获得this,仅支持通过入参data获得组件的data和父组件传入的properties(类似Vueprops

2. 监听器 watch

  • 实现方法对比:
    • Vue 和 mpvue 的实现一致,都是通过 Vue 实例化时传入 watch 参数实现;
    • 微信小程序是在 computed 库基础上,通过混入 watch 对象实现,watch 对象中的所有属性会自动注册到小程序组件 Componentobservers 中,由 observers 完成监听工作,所以小程序的 watch 可以理解为语法糖,为了兼容大家的开发习惯。
  • 使用方法差异:
    • Vue 和 mpvue 的 watch 只支持监听单个状态,入参是 newValueoldValue
    • 微信小程序的 watch 非常强大,支持监听多个状态、对象的指定属性等功能,可扩展性强于 Vue 和 mpvue。
}
限时优惠 ¥ 38.00 ¥ 49.00

你正在阅读课程试读内容,订阅后解锁课程全部内容

千学不如一看,千看不如一练

手机
阅读

扫一扫 手机阅读

mpvue原理深入解析36讲
限时优惠 ¥ 38.00 ¥ 49.00

举报

0/150
提交
取消
意见反馈 邀请有奖 帮助中心 APP下载
官方微信