10. 로직 & 스크립팅
기본 구조 이해
- 스크립트는 순수 JavaScript(ES6+)입니다 → 표준 언어 기능이 모두 그대로 동작합니다:
- 조건문(if/else, switch)
- 반복문(for, while)
- 삼항 연산자
- 배열과 객체
- JSON.parse, JSON.stringify
- 표준 문자열·수학 연산
- 페이지의 라이프사이클은 라이프사이클 이벤트로 관리합니다. 전역 객체로는 데이터, 화면 이동, 애니메이션을 다룹니다. 위젯 객체로는 위젯의 속성을 조작해 겉모습을 세밀하게 제어하고, 다른 위젯에서 일어난 사용자 조작에 따라 그 모습이나 동작을 바꿉니다. 이 셋을 함께 사용해 페이지에 생명을 불어넣습니다.
라이프사이클 이벤트
- 화면이 생성되고, 사용되고, 닫히는 흐름에 맞춰 Lucy가 자동으로 호출하는 콜백이 있습니다.
| 함수 | 호출 시점과 역할 |
|---|---|
| onStart(arg) | 화면이 시작될 때 가장 먼저 호출됩니다. 여기서 데이터를 초기화하고 이벤트 바인딩을 설정합니다. |
| onClose() | 화면이 닫힐 때 호출됩니다. 자원을 해제하고 정리 작업을 수행합니다. |
| onReceiveDone() | 데이터 수신이 성공적으로 끝나면 호출됩니다. 받은 데이터로 UI를 갱신합니다. |
| onReceiveError() | 데이터 수신이 실패하면 호출됩니다. 네트워크 오류 같은 예외를 처리합니다. |
전체 라이프사이클 이벤트 목록과 각 이벤트의 상세 설명은 11. 스크립트 API 문서의 LifeCycle Events 섹션을 참고하세요.
전역 객체
- 전역 객체는 Lucy Studio가 미리 만들어 제공하는 객체입니다. import나 별도 설정이 필요 없고, 앱 전체에서 공유되며 언제든 바로 사용할 수 있습니다.
| 전역 객체 | 제어 대상 |
|---|---|
| $app | 앱 전체 동작: 화면 이동, 다이얼로그, 저장된 데이터, 테마, 기기 정보 |
| $form | 현재 화면과 폼: 변수, 메시지 전달, 화면 이동 |
| $vm | 데이터: 데이터 소스 읽기·쓰기, 데이터 요청과 구독 |
| $http | 외부 API로 보내는 네트워크 요청(get, post, put 등) |
| $log | 디버깅용 로그 메시지 출력(d, i, w, e) |
| $mqtt | 실시간 메시지 통신(connect, subscribe, publish) |
| $act | 'animation mode' 탭에 등록한 액션이나 상태 전환 실행 |
$log.d("Button was tapped!"); // 디버그 로그 출력
$app.openPage("dashboard"); // dashboard 페이지로 이동
$http.get("https://api.example.com/user", function(res) {
$log.i(res); // 응답을 사용해 처리
});
각 전역 객체($app, $form, $vm, $act, $log, $http, $mqtt)의 전체 메서드와 속성은 11. 스크립트 API 문서의 Global Objects 섹션에서 확인하세요.
위젯 객체 제어
- 캔버스 영역에 배치한 특정 위젯을 가리킵니다 — Button, Text, Checkbox 등입니다. 이 객체는 자신이 속한 화면에만 존재하며, ID로만 접근할 수 있습니다. 모든 위젯 객체는 속성, 메서드, 이벤트라는 세 종류의 멤버로 기능을 제공합니다. 이 셋을 이해하면 어떤 위젯이든 스크립트로 다룰 수 있습니다 — 패턴을 한 번 익히면 모든 위젯이 같은 방식으로 동작합니다.
위젯별 전체 속성·메서드·이벤트 목록은 11. 스크립트 API 문서의 Widget 섹션(Widget and Component Reference)에서 확인하세요.

-
속성: 위젯의 상태를 읽고 바꿉니다 — 사용자 이벤트에 따라 속성을 설정하거나 가져올 수 있습니다(예: Button을 클릭해 지정한 Text의 색상을 바꿉니다).
-
속성은 여러 메서드로 설정하고 가져올 수 있습니다. 단축 메서드가 없는 속성은 .setProperty와 .getProperty를 사용합니다. 설정하거나 가져올 속성을 매개변수로 넘깁니다.
// 속성 이름을 매개변수로 넘겨 특정 속성을 설정합니다// 속성 이름을 매개변수로 넘겨 특정 속성을 가져옵니다textWidgetId.setProperty(propertyName, value);textWidgetId.getProperty(propertyName);textWidgetId.setProperty("text", "Hello World");var textProp = textWidgetId.getProperty("text");// 자주 쓰는 일부 속성에는 단축 메서드도 있습니다(아래 Methods 참고).// 예를 들어 .setText("Hello World")는// .setProperty("text", "Hello World")의 단축형입니다. 모든 속성에// 단축 메서드가 있는 것은 아니므로, 없을 때는 .setProperty / .getProperty를 사용합니다. -
스크립트로 스타일 속성도 설정하고 가져올 수 있습니다 — SizedBox, Padding, DecoratedBox 같은 속성입니다. 스크립트에서 다루려면 해당 스타일 속성이 위젯에 이미 적용되어 있어야 하며, 그렇지 않으면 스크립트가 아무 효과를 내지 않습니다.
// 스타일 속성을 설정하려면 그 스타일이 이미 적용되어 있어야 합니다widgetId.setStyleProperty(styleName, styleProperty, value);widgetId.getStyleProperty(styleName, styleProperty);// 색상을 설정할 때는 hex 값을 쓰거나// color theme에 등록한 색상 이름을 쓸 수 있습니다widgetId.setStyleProperty("DecoratedBox", "decoration.color", "#FFFFFF");widgetId.getStyleProperty("DecoratedBox", "decoration.color");
-
-
메서드: 위젯에 내장된 동작으로, 주로 괄호를 붙여 호출합니다 — 위젯에 무엇을 할지 지시합니다. 인자를 넘길 수 있고, 일부 메서드는 결과를 반환해 저장할 수 있습니다.
위젯 메서드 Timer widgetId.start(); Calendar widgetId.goToToday(); ListView widgetId.insert(index); Text(속성 단축 메서드) widgetId.setText(”Hello World”); - 참고: 각 위젯에서 사용할 수 있는 속성·메서드·이벤트의 전체 목록은 Properties, Methods & Events 레퍼런스 전체를 참고하세요: 11. 스크립트 API 문서
-
이벤트: 함수를 할당하는 대상입니다
- 사용자가 위젯을 조작하면 이벤트가 발생합니다. 이에 반응하려면 이벤트에 함수를 할당합니다. 그러면 이벤트가 발생할 때마다 Lucy가 그 함수를 실행합니다. 일부 함수는 매개변수를 받으므로, 이를 추가 처리에 활용할 수 있습니다.
- 페이지가 사용자에게 반응하는 주된 방식입니다. 전체 이벤트 목록과 전달되는 인자, 실제 바인딩 예시는 다음 절 이벤트 처리에서 확인하세요.
이벤트 처리: 탭, 입력 변경 등
바인딩 동작 방식
- 사용자가 위젯을 조작하면 이벤트가 발생합니다. 이에 반응하려면 이벤트에 함수를 할당합니다. 그러면 이벤트가 발생할 때마다 Lucy가 그 함수를 실행합니다.
- 바인딩은 항상
onStart함수 안에서 설정합니다. 그러면 페이지가 초기화될 때 함수가 바로 이벤트에 연결됩니다. onChanged,onSelected,onSubmitted같은 이벤트는 핸들러에 인자를 넘길 수 있다는 점에 유의합니다(예:value,index,date).
자주 쓰는 위젯 이벤트
- 위젯에 이미 지정된 이벤트가 있으면, 그 위젯을 클릭할 때 Properties 패널에 표시됩니다. 이런 이벤트는 보통 'on'으로 시작합니다. 아무 이벤트도 보이지 않으면 그 위젯에는 지정된 이벤트가 없다는 뜻이며, 이때는
onTap이벤트를 사용할 수 있습니다.
| 위젯 | 이벤트 | 전달되는 인자 |
|---|---|---|
| Button | onClick | |
| Checkbox, TextField | onChanged | value |
| TextField | onSubmitted | value |
| ListView | onSelected | index |
| Text, Icon, Row, Column 등 | onTap |
위젯 타입별 상세 목록
| 그룹 | 이벤트 |
|---|---|
| Button·선택 계열 | onClick, onSelected |
| 텍스트 입력(TextField) | onChanged, onSubmitted, onEditingComplete, onTap, onFocusOut |
| 토글·피커 | onChanged (Checkbox, Switch, DropDown, Slider, Radio) |
| 슬라이더 | onChangeStart, onChangeEnd |
| 리스트·스크롤 | onScrollEnd, onReorder, onOverflowChanged |
| 화면 이동·시간 | onPageChanged, onDateSelected, onExpired (Timer) |
핸들러 바인딩
- 이벤트에 함수를 연결하는 방법은 두 가지입니다. 인라인으로 정의하거나, 따로 선언한 뒤 이름으로 참조합니다 — 두 방식은 동일하게 동작합니다.
// 1) 인라인: onStart() 안에서 핸들러를 직접 정의합니다
function onStart() {
widgetId.onClick = function() {
$log.d("submit tapped");
};
widgetId.onChanged = function(value) {
$log.d("field is now: " + value);
}
}
// ================================================================
// 2) 분리: 함수를 선언하고 이름으로 참조합니다
function onStart() {
widgetId.onClick = button_onClick;
widgetId.onChanged = checkbox_onChanged;
}
function button_onClick() {
$log.d("button clicked!");
}
function checkbox_onChanged(value) {
$log.d("field is now " + value);
}
조건 분기, 반복, 유틸 함수 사용
자주 쓰는 패턴 (스크립트에서 쓰는 JavaScript 기초)
JavaScript가 처음이라면, 아래 예시로 표준 언어 기능을 핸들러 안에서 어떻게 쓰는지 확인하세요. 이미 익숙하다면 넘어가도 됩니다 — 순수 JavaScript이므로 따로 익혀야 할 전용 문법은 없습니다.
조건문 — 조건이 충족될 때만 무언가를 실행합니다(예: Checkbox 값을 읽어 다른 위젯을 보이거나 숨깁니다).
function checkbox_onChanged(value) {
if(value === true) {
detailsBox.setProperty("visible", true);
detailsBox.visible = true; // visible 속성은 이렇게 설정해도 됩니다
} else {
detailsBox.setProperty("visible", false);
detailsBox.visible = false; // visible 속성은 이렇게 설정해도 됩니다
}
}
삼항 연산자 — 두 값 중 하나를 반환하는 짧은 if/else입니다.
function checkbox_onChanged(value) {
// 체크되어 있으면 "On", 그렇지 않으면 "Off"를 표시합니다
statusLabel.setText(value === true ? "On" : "Off");
}
반복문 — 동작을 반복합니다. 예를 들어 리스트에 여러 행을 추가합니다.
function onStart() {
var fruits = ["Apple", "Banana", "Cherry"];
for (var i = 0; i < fruits.length; i++) {
$log.d("Item " + i + ": " + fruits[i]);
}
}
객체와 JSON 다루기 — 응답을 파싱한 뒤 필드를 읽습니다.
function onStart() {
var jsonText = '{ "name": "Jane", "age": 30 }';
var user = JSON.parse(jsonText); // 텍스트 -> 객체
nameLabel.setText(user.name); // "Jane"
var backToText = JSON.stringify(user); // 객체 -> 텍스트
$log.d(backToText);
}
공유한 스크립트 사용
공유 모듈 만들기
프로젝트가 커지면 여러 화면에서 같은 스크립트 블록(로그인, 헬퍼 함수 등)이 필요해집니다. 같은 코드를 페이지마다 스크립트 창에 복사해 붙이는 대신, 공유할 수 있는 스크립트 파일에 넣어 둡니다. 그 파일의 코드를 가져오면 거기 선언한 함수를 여러 화면에서 사용할 수 있습니다.
- Script 탭에서 새
.js파일을 만듭니다(예:common.js). - 이 파일은 다른 스크립트와 함께 프로젝트의 script 에셋 폴더에 저장됩니다.
- 가져오는 쪽 파일에서는
require('jsFileName')을 맨 위에 두고, 파일 이름을 매개변수로 넘깁니다. - 가져올 수 있는 파일 수에는 제한이 없습니다.
- 함수는 다음과 같이 선언합니다:
const Util = {
getToday : function() {
let today = new Date();
return today;
},
getTime : function() {
let today = new Date();
let hour = ("0" + today.getHours()).slice(-2); // 시
let min = ("0" + today.getMinutes()).slice(-2); // 분
let sec = ("0" + today.getSeconds()).slice(-2); // 초
return hour+ "" +min+ "" +sec;
}
}
가져오기 — 스크립트 맨 위, 다른 코드보다 앞에 두고 필요한 곳에서 호출합니다:
require('common.js');
function onStart() {
button.onClick = setCurrentTime;
}
function setCurrentTime() {
let time = Util.getTime(); // Util은 common.js에서 가져온 것입니다
time_txt.setProperty("text", time);
}
스크립트 디버깅
자주 쓰는 디버깅 패턴
함수가 호출되는지 확인하기
가장 간단한 확인 방법입니다 — 실행되지 않는 것 같은 함수 맨 위에 로그를 추가합니다:
function myButton_onClick() {
$log.d("myButton_onClick fired");
// 나머지 로직
}
데이터 흐름 추적하기
주요 동작 전후에 로그를 남겨 데이터가 어디서 바뀌거나 멈추는지 찾습니다:
$log.d("before sort: " + $vm.getDSValue("myDS.body.items[0].title"));
$vm.sortString("myDS", "body.items.title", "ascending");
$log.d("after sort: " + $vm.getDSValue("myDS.body.items[0].title"));