社区/学习指南/小程序云开发学习指南

页面渲染

在数据绑定章节,我们已经掌握如何把 data 里面的数据渲染到页面,这一部分我们会介绍如何通过点击组件绑定的事件处理函数来修改 data 里面的数据,如何把事件处理函数获取到的数据打印到页面。

将变量值渲染到页面

还记得我们之前在控制台打印的 Date 对象、Math 对象、字符串 String 对象以及常量么?在第一节里我们把这些对象赋值给了一个变量,然后通过控制台可以把这些值给 console.log()打印出来,那这些值可不可以渲染到小程序的页面上呢?答案是肯定的。

将变量值渲染到页面

使用开发者工具新建一个页面比如 data,然后在 data.js 的Page({})函数的前面,也就是不写在 Page 函数里面,写在 data.js 的第 1 行输入以下代码:


let lesson = "云开发技术训练营";

let enname = "CloudBase Camp";

let x = 3, y = 4, z = 5.001, a = -3, b = -4, c = -5;

let now = new Date();

注意上面这些是 JavaScript 函数的语句,所以用的是分号;分隔,这个不要和之前的逗号分隔给弄混了哦。如果语句是换行的,后面的分号;也可以不必写。

然后在 data 里面添加如下数据(注意没有双引号,单双引号里的是字符串)


data: {

    charat: lesson.charAt(4),

    concat: enname.concat(lesson),

    uppercase:enname.toUpperCase(),

    abs:Math.abs(b),

    pow: Math.pow(x, y),

    sign:Math.sign(a),

    now:now,

    fullyear:now.getFullYear(),

    date:now.getDate(),

    day: now.getDay(),

    hours: now.getHours(),

    minutes: now.getMinutes(),

    seconds: now.getSeconds(),

    time: now.getTime()

},

在 data.wxml 里输入以下代码:


<view>"云开发技术训练营"第5个字符 {{charat}}</view>

<view>两个字符串连接后的结果:{{concat}}</view>

<view>CloudBase Camp字母大写:{{uppercase}}</view>

<view>b的绝对值:{{abs}}</view>

<view>x的y次幂:{{pow}}</view>

<view>返回a是正还是负:{{sign}}</view>

<view>now对象:{{now}}</view>

<view>{{fullyear}}年</view>

<view>{{date}}日</view>

<view>星期{{day}}</view>

<view>{{hours}}时</view>

<view>{{minutes}}分</view>

<view>{{seconds}}秒</view>

<view>1970年1月1日至今的毫秒数:{{time}}</view>

因为 data 是一个对象 Object,我们可以通过冒号:的方式将变量值赋值给 data 里的各个属性,而在数据绑定章节,这些数据是可以直接渲染到小程序的页面的。

toString()方法

我们发现{{now}}渲染的结果是一个对象[object Object],而并没有显示出字符串文本,这个时候就需要用到对象的 toString()方法,得到对象的字符串。将 data 里 now 的赋值改为如下:


now:now.toString(),

技术文档:toString()方法

响应的数据绑定

逻辑层 js 文件里的 data 数据,无论是基础的字符串、数组、对象等,还是通过变量给赋的值,都可以渲染到页面。不仅如此,只要对逻辑层 data 里的数据进行修改,视图层也会做相应的更新,我们称之为响应的数据绑定,而这是通过 Page 的 setData()方法来实现的。

使用开发者工具在 data.wxml 里输入:


<view style="background-color:{{bgcolor}};width:400rpx;height:300rpx;"></view>

<button bindtap="redTap">让背景变红</button>

<button bindtap="yellowTap">让背景变黄</button>

然后在 data.js 里添加一个数据


bgcolor:"#000000",

然后在 js 里添加两个 button 绑定的事件处理函数 redTap 和 yellowTap:


redTap:function(){

    this.setData({

        bgcolor: "#cd584a"

    })

},

yellowTap:function(){

    this.setData({

        bgcolor: "#f8ce5f"

    })

},

点击 button,原来 view 组件的背景颜色由黑色变成了其他颜色,这是因为点击组件触发事件处理函数,调用了 Page 的 setData()方法修改了 data 里与之相应的属性的值(重复赋值就是修改),bgcolor 由原来的”#000000″,变成了其他数据。

小任务:通过以往的学习我们了解到无论是组件的样式,图片、链接的路径,数组、对象里的数据,他们都是可以进行数据分离写到 data 里面的,这也就意味着,我们通过点击事件改变 data 里面的数据可以达到很多意想不到的效果,请发挥你的想象力做一些有意思的案例出来。

响应的布尔操作

在前面我们已经了解到,有些组件的私有属性的数据类型为 Boolean 布尔值,比如视频、Swiper 轮播组件是否自动播放、是否轮播,视频组件是否显示播放按钮等等,这些我们都可以使用 setData 将 true 改为 false,false 改为 true 来达到控制的目的。

在交互方面,响应的布尔操作可以用于单一属性 true 与 false 的切换,比如显示与隐藏、展开与折叠、聚焦与失焦、选中与不选中。

我们来看一个案例,使用开发者工具在 data.wxml 里输入以下代码:


<video id="daxueVideo" src="http://wxsnsdy.tc.qq.com/105/20210/snsdyvideodownload?filekey=30280201010421301f0201690402534804102ca905ce620b1241b726bc41dcff44e00204012882540400&bizid=1023&hy=SH&fileparam=302c020101042530230204136ffd93020457e3c4ff02024ef202031e8d7f02030f42400204045a320a0201000400" autoplay loop muted="{{muted}}" initial-time="100" controls event-model="bubble">

</video>

<button bindtap="changeMuted">静音和取消静音</button>

然后给在 data.js 的 data 里新增


muted: true,

然后添加 changeMuted 事件处理函数


changeMuted: function (e) {

  this.setData({

    muted: !this.data.muted

  })

},

在开发者工具的模拟器里点击按钮,我们发现静音和取消静音都是这个按钮。这里的感叹号 !是逻辑非的意思,可以理解为 not。

this.setData 和 this.data 都用到了一个关键字 this。 this 和中文里的“这个的”有类似的指代作用,在方法中, this 指代该方法所属的对象,比如这里的是 Page 对象, this.data 就是指 Page 函数对象里的 data 对象。

响应的数组操作

结合点击事件以及数组操作的知识,我们再来看下面这个案例,了解如何通过点击按钮新增数组里的数据和删除数组里的数据。

使用开发者工具在 data.wxml 里输入以下代码,注意这里视图层只有一个{{text}},也就是说我们之后会把所有的数据都赋值给 data 里的 text。


<view>{{text}}</view>

<button bindtap="addLine">新增一行</button>

<button bindtap="removeLine">删掉最后一行</button>

然后在 data.js 的 Page()之前声明变量,这里声明 extraLine 为一个空数组,我们之后会往这个数组里添加和删除数据。


let initData = '只有一行原始数据'

let extraLine = [];

然后再在 Page 的 data 里添加一条数据,


text: initData,

我们先来看没有事件处理函数时,数据渲染的逻辑,首先我们把 initData 变量值赋值给 text,这时渲染的结果只有 initData 里的数据,所以页面显示的是“只有一行原始数据”,而 extraLine 和 text 没有什么关系。

我们再来在 Page 里添加 addLine 和 removeLine 的事件处理函数:


addLine: function (e) {

  extraLine.push('新增的内容')

  this.setData({

    text: initData + '\n' + extraLine.join('\n')

  })

},

removeLine: function (e) {

  if (extraLine.length > 0) {

      extraLine.pop()

      this.setData({

        text: initData + '\n' + extraLine.join('\n')

      })

  }

},

首先回顾一下之前的数组操作知识,push 为往数组的末尾新增数据,而 pop 则删除数组末尾一行的数据,join 为数组数据之前的连接符。

点击按钮新增一行,触发绑定的事件处理函数 addLine,首先会执行 extraLine 数组新增一条数据“新增的内容”,但是这时 extraLine 和 text 还没有关系,这时在 setData()函数里将 initData 和 extraLine 进行拼接(注意 extraLine 本来是一个数组,但是调用 join 方法后返回的是数组的值拼接好的字符串)。点击按钮删除最后一行,会先删除 extraLine 数组里最后一行的数据。

小任务:新增内容过于单一,我们可以给它后面添加一个随机数,将 extraLine.push('新增的内容')改成 extraLine.push('新增的内容'+Math.random()),再来看看新增数据的效果,关于 Math.random()大家可以自行去 MDN 查阅。大家也可以把拼接的连接符由 \n换成其他字符。

函数与调用函数

函数的作用,可以写一次代码,然后反复地重用这个代码。JavaScript 的函数本身也是对象,因此可以把函数赋值给变量,或者作为参数传递给其他函数。

函数的定义和结构

我们可以使用 function 关键词来定义一个函数,括号()里为函数的参数,参数可以有很多个,使用逗号,隔开;函数要执行的代码(语句)使用大括号{}包住:


function 函数名(参数 1, 参数 2, 参数 3) {

    代码块内要执行的语句

}

不带参数的函数

比如,我们使用开发者工具在 data.js 的 Page()函数前,添加如下代码:


function greet() {

    console.log("你好,欢迎来到云开发训练营");

};

greet(); //调用greet()函数

保存之后,我们可以在控制台看到函数打印的字符串。定义一个函数并不会自动的执行它。定义了函数仅仅是赋予函数以名称并明确函数被调用时该做些什么。调用函数才会以给定的参数真正执行这些动作。greet()函数没有参数,调用函数时,直接写函数名+括号即可。

只有一个参数的函数

下面定义了一个简单的平方函数 square(),square 为函数名,number 为函数的参数(名称可以自定义),使用 return 语句确定函数的返回值。我们继续在 data.js 的 Page()函数前,输入以下代码:


function square(number) {

  return number * number;

};

square(5);

square(5),就是把 5 赋值给变量 number,然后执行 numbernumber,也就是 55,然后返回 return 这个值。

这里的 number 被称之为形参,而 5 被称之为实参。大家可以结合案例就能大致了解形参和实参的意思。

  • 形参是在定义函数时使用的参数,目的是用来接收调用该函数时传进来的实际参数。

  • 实参是在调用时传递给函数的参数

JavaScript 允许传入任意个参数而不影响调用,因此传入的参数可以比定义的参数多,但是不能少。也就是说实参的数量可以多于形参但是不能少于形参。

对象的方法

在小程序里我们会经常将一个匿名函数赋值给对象的一个属性,而这个属性我们可以称之为对象的方法。

匿名函数

函数声明 function 在语法上是一个语句,但函数也可以由函数表达式创建,这样的函数没有函数名称(匿名)。

使用开发者工具在 data.js 的 Page()函数前,输入以下代码:


let square = function(number) {

  return number * number

};

console.log(square(4))//使用console.log()输出变量square

执行后,可以在控制台看到输出的结果为 16。上面这个 function 函数没有函数名,相当于是把函数的返回值赋值给了变量 square。

箭头函数

为什么叫箭头函数(Arrow Function),因为它定义一个函数用的就是一个箭头=>,我们来看两个例子,在 data.js 的 Page()函数前输入以下代码:


const multiply = (x, y) => {

  return x * y;

}

const sum= (x, y) => x + y;//连{}和return语句都可以省掉

console.log(multiply(20, 4));

console.log(sum(20, 4));

在控制台我们可以看到箭头函数打印的结果。箭头函数相当于匿名函数,它没有函数名,而且也简化了函数定义。箭头函数可以只包含一个表达式,甚至连{ … }和 return 都可以省略掉。大家可以先只需要了解这个写法就可以了,以后碰到不至于比较迷惑,见多了也试着尝试多写一下。

调用对象的方法

可以使用点表示法来调用对象的方法,这个和访问对象的属性没有区别。而调用对象的方法和调用一个函数也是大同小异。

调用对象的方法我们在前面就已经接触过大量的案例了,在前面我们已经说过,wx 是小程序的全局对象,而在第一节我们打印的很多 API,就是调用了 wx 对象里的方法。

JavaScript 函数的写法

在点击事件章节里,我们创建的事件点击处理函数的写法如下:


scrollToPosition() {

    },

而在这一节我们创建的事件点击函数的写法为:


yellowTap:function(){

},

这两种写法都是可以执行的,大家可以把这两种写法互相修改一下试试看~

currentTarget 事件对象

在前面的列表渲染里,我们知道点击电影列表里的某一部电影,要进行页面跳转显示该电影的详情,我们需要给该电影创建一个页面,那如果要显示数千部的电影的详情,一一创建电影详情页显然不合适,毕竟所有电影的详情页都是同一一个结构,有没有办法所有电影详情都共用一个页面,但是根据点击的链接的不同,渲染相应的数据?答案是肯定的,要解决这个问题,首先我们要了解链接组件的点击信息。

当点击组件触发事件时,逻辑层绑定该事件的处理函数会收到一个事件对象,通过 event 对象可以获取事件触发时候的一些信息,比如时间戳、 detail 以及当前组件的一些属性值集合,尤其是事件源组件的 id。

currentTarget 是事件对象的一个属性,表示的是事件绑定的当前组件。使用开发者工具在 data.wxml 里输入以下代码


<view class="weui-navbar">

    <block wx:for="{{tabs}}" wx:key="index">

        <view id="{{index}}" class="weui-navbar__item {{activeIndex == index ? 'weui-bar__item_on' : ''}}" bindtap="tabClick">

            <view class="weui-navbar__title">{{item}}</view>

        </view>

    </block>

</view>

<view class="weui-tab__panel">

    <view hidden="{{activeIndex != 0}}">帝都</view>

    <view hidden="{{activeIndex != 1}}">魔都</view>

    <view hidden="{{activeIndex != 2}}">妖都</view>

    <view hidden="{{activeIndex != 3}}">渔村</view>

</view>

然后再往 data.js 的 data 里添加以下数据:


tabs: ["北京", "上海", "广州", "深圳"],

activeIndex:0,

然后再添加事件处理函数 tabClick。


tabClick: function (e) {

  console.log(e)

  this.setData({

    activeIndex: e.currentTarget.id

  });

},

编译之后在模拟器里预览。当我们点击上面的 tab 时,触发 tabClick 事件处理函数,这时候事件处理函数会收到一个事件对象 e,我们可以看一下控制台打印的 e 对象的内容,关于 e 对象具体属性的解释可以看技术文档。

技术文档:事件对象

currentTarget 就是事件对象的一个属性,我们可以使用点表示法获取到点击的组件的 Id,并将其赋值给 activeIndex,所谓 active 就是激活的意思,也就是我们点击哪个 tab,哪个 tab 就激活。

  • 当点击的 id 为 0,也就是第一个 tab 时,activeIndex 的值被事件处理函数修改为 0;

  • activeIndex == index 相同的 tab,也就是激活的 tab 就会有 weui-bar__item_on 的 class,也就显示为绿色

  • !=是不等于操作符,activeIndex != 0 显然不成立条件为 false,也就是组件 hidden 为 false,即为显示;而 activeIndex != 1,2,3 则都会 true,hidden 生效,组件不显示,于是 tab 的效果就有了。

当我们对字符串、Math 对象、Date 对象、数组对象、函数对象、事件对象所包含的信息不了解时,把他们打印出来即可。打印出来的结果基本都是字符串、列表、对象,而在前面我们已经掌握如何操作它们。通过实战,通过打印日志,既有利于我们调试代码,也加强我们对逻辑的理解。

本文出自 李东bbsky