🦉 Служебные функции (Utils) 🦉
Owl экспортирует несколько полезных служебных функций, чтобы помочь с
распространенными проблемами. Все эти функции доступны в пространстве
имен owl.utils
.
Содержимое
whenReady
: выполнение кода, когда DOM готовloadJS
: загрузка файлов скриптовloadFile
: загрузка файла (полезно для шаблонов)escape
: очистка строкdebounce
: ограничение частоты вызовов функцийshallowEqual
: сравнение неглубоких объектов
whenReady
Функция whenReady
возвращает Promise
, разрешенное, когда DOM будет
готов (если оно еще не готово, в противном случае разрешается напрямую).
Если вызывается с обратным вызовом в качестве аргумента, он выполняет
его, как только DOM готов (или напрямую).
Promise.all([loadFile("templates.xml"), owl.utils.whenReady()]).then(function ([templates]) {
const qweb = new owl.QWeb({ templates });
const env = { qweb };
await mount(App, { env, target: document.body });
});
или еще вариант:
owl.utils.whenReady(function () {
const qweb = new owl.QWeb();
const env = { qweb };
await mount(App, { env, target: document.body });
});
loadJS
loadJS
принимает URL-адрес (строку) ресурса javascript и загружает его
(путем добавления тега script в заголовок документа). Он возвращает промис,
поэтому вызывающая сторона может правильно отреагировать, когда он будет готово.
Кроме того, он умен: он поддерживает список URL-адресов, загруженных ранее (или
загружаемых в настоящее время), и предотвращает двойную работу.
Например, это полезно для ленивой загрузки внешних библиотек:
class MyComponent extends owl.Component {
willStart() {
return owl.utils.loadJS("/static/libs/someLib.js");
}
}
loadFile
loadFile
— это вспомогательная функция для загрузки файла. Он просто
выполняет запрос GET
и возвращает результирующую строку в промисе. Первоначальный
вариант использования этой функции — загрузить файл шаблона. Например:
async function makeEnv() {
const templates = await owl.utils.loadFile("templates.xml");
const qweb = new owl.QWeb({ templates });
return { qweb };
}
Обратите внимание, что в отличие от loadJS
, эта функция возвращает содержимое
файла в виде строки. Он не добавляет тег script
и не делает ничего.
escape
Иногда нам нужно отобразить динамические данные (например, данные, созданные
пользователем) в пользовательском интерфейсе. Если это делается с помощью
шаблона QWeb
, это не проблема:
<div><t t-esc="user.data"/></div>
Механизм QWeb
создаст узел div
и добавит содержимое строки user.data
в
качестве текстового узла, поэтому веб-браузер не будет анализировать его как html.
Однако это может быть проблемой, если это делается с помощью кода javascript,
подобного этому:
class BadComponent extends Component {
// какой то шаблон с ref в div
// какой-то код ...
mounted() {
this.divRef.el.innerHTML = this.state.value;
}
}
В этом случае содержимое div
будет проанализировано как html, что может привести
к нежелательному поведению. Чтобы исправить это, функция escape
просто преобразует
строку в экранированную версию той же строки, которая будет правильно отображаться
браузером, но не будет анализироваться как html (например, "<ok>"
экранируется в
строку: "<ok>"
). Итак, плохой пример выше можно исправить следующим изменением:
this.divRef.el.innerHTML = owl.utils.escape(this.state.value);
debounce
Функция debounce
полезна, когда мы хотим ограничить количество раз выполнения какой-либо
функции/действия. Например, это может быть полезно для предотвращения проблем с двойным
нажатием кнопки.
Она принимает три аргумента:
func
(функция): это функция, скорость которой будет ограничена.wait
(число): это количество миллисекунд, которое мы хотим использовать для ограничения скорости функцииfunc
immediate
(необязательный, логическое значение, по умолчанию=false): еслиimmediate
равно true, функция будет запущена немедленно (по переднему фронту интервала). Если false, функция будет запущена в конце (по заднему фронту).
Она возвращает функцию. Например:
const debounce = owl.utils.debounce;
window.addEventListener("mousemove", debounce(doSomething, 100));
Как показывает этот пример, такое бывает полезно для обработчиков событий, которые запускаются
очень быстро, например для таких событий scroll
или mousemove
.
shallowEqual
Эта функция проверяет, имеют ли два объекта одинаковые значения, назначенные каждому ключу:
shallowEqual({ a: 1, b: 2 }, { a: 1, b: 2 }); // true
shallowEqual({ a: 1, b: 2 }, { a: 1, b: 3 }); // false
Однако из соображений производительности предполагается, что два объекта имеют одинаковые ключи. Если мы находимся в ситуации, когда это не гарантируется, будет работать следующий код:
const completeShallowEqual = (a, b) => shallowEqual(a, b) && shallowEqual(b, a);