循环出来的数据不能判断?SJS语法让你开发钉钉原生小程序如虎添翼!

1,247 阅读6分钟

本文正在参加「金石计划」

前言

听说你在原生的钉钉小程序对无法使用像VueReact那样通过includes()判断元素存在与否感到烦恼?别担心,我这里有一个好消息——SJS语法!它不仅能让你使用像includes()那样的语法,还能让你后续在原生开发小程序的路上更加轻松愉快。Now,让我们来一起探索这个神奇的语法吧!

背景

最近在搞一个钉钉小程序,由于项目时间周期有点紧张,所以就没有考虑使用框架进行搭建,而是选择手撸原生。期间就遇见一个问题:那就是在页面上想要根据includes()来判断日历上的日期在不在打卡的日期数组中,如果在就表示已打卡并着绿色,否则就是未打卡着红色。 如下图所示:

微信截图_20230404090608.png

这个问题若是在框架面前那是信手拈来,可是现在是完全原生的钉钉小程序,原生不支持includes()直接在页面使用,那怎么办呢?后来翻阅了文档,发现钉钉小程序也有和微信小程序WXS一样的语法——那就是SJS语法。

经过仔细阅读SJS语法,最后上述需求场景得以完全实现。那下面就跟着我一起来看看我是如何使用SJS语法实现了在原生钉钉小程序的页面中像includes()那样去判断元素存在与否的?

SJS语法

想要实现功能需求还得先来看看SJS常见语法,下面就一起来看看→

概述

SJS(safe/subset javascript)是钉钉小程序一套自定义脚本语言,可以在AXML中使用其构建页面结构。SJSJavaScript语言的子集,与JavaScript是不同的语言,其语法并不与JavaScript一致,请勿将其等同于JavaScript

其实,根据使用来看,SJS语法和JavaScript语法没什么区别,就是一些ES6以上的语法在里面不能使用,还有就是时间的获取有所不同而已,所以不要有任何负担,简单得很。

下面就来简单介绍几种语法,更多的还请前往钉钉开发文档-SJS语法参考

使用方式

index.sjs文件中定义SJS

// pages/index/index.sjs
const message = 'hello dingtalk';
const getMsg = x => x;
export default {
  message,
  getMsg,
};

index.axml示例代码:

<!-- pages/index/index.axml -->
<import-sjs name="m1" from="./index.sjs"/>
<view>{{m1.message}}</view>
<view>{{m1.getMsg(msg)}}</view>

注意:

  • sjs中只支持使用import、export管理模块依赖
  • sjs只能定义在.sjs文件中,然后在axml中使用<import-sjs>标签引入。
  • sjs可以调用其他sjs文件中定义的函数。
  • sjs的运行环境和其他JavaScript代码是隔离的,sjs中不能调用其他JavaScript文件中定义的函数,也不能调用小程序提供的API。
  • sjs函数不能作为组件事件回调。
  • sjs不依赖于基础库版本,可以在所有版本小程序中运行。

在实际使用中,就是不能在sjs文件中引用非sjs文件中的模块或插件,这就是后续为什么没有用moment.jsday.js来操作时间的原因。

变量

SJS中的变量均为值的引用。

  • varJavaScript中表现一致,会有变量提升。
  • 支持constlet,与JavaScript表现一致。
  • 没有声明的变量直接赋值使用,会被定义为全局变量。
  • 只声明变量而不赋值,默认值为undefined

示例代码:

var num = 1;
var str = "hello dingtalk";
var undef; // undef === undefined
const n = 2;
let s = 'string';
globalVar = 3;

这里相较于微信小程序来说,微信小程序现在还没有支持constlet,不知道后续会不会改动。

数据类型

SJS目前支持如下数据类型:

image.png

SJS提供了constructortypeof两种方式判断数据类型,更多也请前往文档进行查看。

下面就看看Arraydete分别拥有的方法:

其实数组的方法几乎和javascript中的一致,只是少了一些方法,例如:includes()

image.png

image.png

以上就是SJS中支持的所有数组方法。

至于date对象只有在获取时间方式不同,其余的几乎也是一样的。在SJS中,获取时间不再是使用new Date(),而是使用getDate()返回一个当前时间的对象,然后其余的操作都能使用JS中的相关方法进行获取。

image.png

好了,上面就简单介绍了SJS语法中的ArrayDate对象的方法,这也是在我们需求中会用到的两个相关语法,至于其他的语法这里就不过多展开了。

开发

下面就来进行实际应用,像上述需要判断日历的日期是否打卡,首先得在页面文件中创建一个index.sjs文件。如下:

image.png

然后就可以在index.sjs中写如下代码:

const isContain = function (arr, item) {
  return arr.indexOf(item) !== -1;
}

export default {
  isContain
};

isContain()方法接受两个参数,一个是已打卡的时间数组,一个是日历上循环出来的日期,最后将该方法导出,就可在页面进行引用。

image.png

首先在页面中使用import-sjs标签,添加name为当前<import-sjs>标签指定模块名;然后在view标签中使用a:if语法调用isContain()方法进行判断,从而实现了在原生钉钉小程序中为循环出来的数据进行includes()判断。

上述需求还需要进行判断,大于当前时间的日期不显示表示是否打卡的圆点,所以还需要在index.sjs文件中增加如下代码:

const isContain = function (arr, item) {
  return arr.indexOf(item) !== -1;
}

const isAfter = function(date, curDay) {
  const date1 = getDate(date);
  const date2 = getDate(curDay);
  const time1 = date1.getTime()
  const time2 = date2.getTime()
  return Number(time1) - Number(time2) >= 0
}

export default {
  isContain,
  isAfter
};

这里就用到了SJS语法中的date对象的相关方法了,然后使用getTime()来将传入的时间转成时间戳进行比较,从而实现判断时间是否是在当前时间之后。再次说明,sjs文件中是不能使用new Date()来获取时间的!!!

image.png

最终实现效果如下:

image.png

至此,在原生钉钉小程序中使用SJS语法解决数据循环出来不能使用includes()等方法判断逻辑的问题就完美解决了。index.sjs文件中的代码可以直接复制到微信小程序中的WXS文件中进行使用,只是在页面中的引用方式不同而已,所以学会了在原生钉钉小程序中解决此类逻辑,也就能在所有原生小程序中使用相关的语法解决原生小程序中诸如此类的所有问题啦。

最后,希望看完本文的你也能解锁该技能,在日后的工作中更加轻松愉快!^_^

后语

小伙伴们,如果觉得本文对你有些许帮助,点个👍或者➕个关注再走哦^_^ 。另外如果本文章有问题或有不理解的部分,欢迎大家在评论区评论指出,我们一起讨论共勉。