Пользовательские скрипты в Opera Mobile для андроид
Ни для кого не секрет, что для андроида существует довольно много интернет браузеров, у каждого есть свои плюсы и минусы, приходится держась их штук пять в телефоне на всякий случай. Так уж сложилось что основным браузером для меня всегда была Opera Mobile, ну привык я к ней ещё со времён Symbian, для андроида даже сделали специальную Оперу с поддержкой расширений, как для декстопной версии, в мобильной Опере так же можно включить поддержку пользовательских скриптов (UserJS), делается это довольно просто через настройки в opera:config . Для начала надо определиться откуда будут грузиться наши скрипты, для себя я решил, что пускай и грузятся из папки UserJS, создал такую папку в телефоне и положил туда несколько скриптов, вот такой путь к папке у меня получился: /sdcard/Opera/UserJS, потом нужно активировать в Опере поддержку пользовательских скриптов, в адресной строке набираем opera:config#UserPrefs|UserJavaScript, откроются настройки, нужно отметить галочкой пункт User JavaScript а в поле User JavaScript File прописать путь к папке со скриптами в моём случае это: /mnt/sdcard/Opera/UserJS, нажмаем внизу кнопку «Сохранить» и перезапускаем Оперу. Сюда ubuntuone.com/4Vk16aVjrDTcvaAV1Bat7r я залил несколько скриптов для проверки, скрипт для удобного чтения bash.Im, парочка скриптов для хабра (HabrAjax и HabrPercentageRing), скрипт который убирает с DepositFiles капчу и таймер перед загрузкой файла, добавляет большую зелёную кнопку «Download» после тапа на которую начнётся немедленная загрузка файла, для него потребуеются дополнитеные настройки в opera:config, в адресной строке пишем: opera:config#UserPrefs|CustomUser-Agent, далее в поле Custom User-Agent нужно прописать DepositFiles/FileManager 0.9.9.206, а если вы через пробел ещё допишите там же YB/3.5.1, то с файлообменникаYandex Народ тоже пропадёт капча и загрузка файла будет начинаться сразу.
Настройка Expo
Есть два инструмента, которые вам нужны для разработки приложений с помощью Expo: приложение командной строки под названием Expo CLI для инициализации и обслуживания вашего проекта и мобильное клиентское приложение под названием Expo Go, чтобы открыть его на iOS и Android. Любой веб-браузер будет работать для открытия проекта в Интернете.
Вам не нужна macOS для создания приложения для iOS с Expo, вам нужно только устройство iOS для запуска приложения Expo Go. Поддерживаются Windows, Linux и macOS.
Expo CLI
Expo CLI — это приложение командной строки, которое является основным интерфейсом между разработчиком и инструментами Expo. Expo CLI также имеет веб-интерфейс, который появляется в вашем веб-браузере при запуске проекта — вы можете использовать графический интерфейс вместо интерфейса командной строки, если вам еще не комфортно использовать терминал или вы предпочитаете графические интерфейсы, оба имеют схожие возможности.
Требования
- Node.js LTS release
- Git
- Watchman для пользователей macOS
Рекомендуемые инструменты
- Редактор VSCode
- Расширение VSCode Expo для отладки и автозаполнения app.json.
- Yarn
- Пользователи Windows: PowerShell, Bash через WSL или терминал VSCode.
Установка Expo CLI
npm install --global expo-cli
Убедитесь, что установка прошла успешно, запустив expo whoami . Вы еще не вошли в систему, поэтому увидите «Not logged in». Вы можете создать учетную запись, запустив expo register , если хотите, или если у вас уже есть аккаунт в expo впишите expo login , но вам также не нужна учетная запись для начала.
Expo Go для iOS или Android
Самый быстрый способ начать работу — использовать приложение Expo Go на вашем устройстве iOS или Android. Expo Go позволяет открывать приложения, которые обслуживаются через Expo CLI. Скачать можно в Play Маркет(Android) или AppStore(iOS) Когда установка приложения Expo Go будет завершена, откройте его. Если вы создали учетную запись в expo-cli , вы можете войти здесь, на вкладке «Профиль». Это облегчит вам открытие проектов в клиенте, когда они будут открыты в разработке — они автоматически появятся на вкладке «Projects» клиентского приложения.
Создание проекта на Expo
Сначала мы создадим сам проект:
expo init test
Далее мы переходим в директорию проекта
cd test
Запуск сервера разработки
expo start
Когда вы запускаете expo start (или npm start ), Expo CLI запускает Metro Bundler, который представляет собой HTTP-сервер, который компилирует код JavaScript нашего приложения с помощью Babel и передает его приложению Expo. Он также открывает Expo Dev Tools, графический интерфейс для Expo CLI.
Вы можете закрыть окно Expo DEV Tools и отключить он не запустится в будущем, нажав shift + d в вашем терминале, на котором запущен Expo CLI. Запустите его снова в любое время, нажав d в терминале, на котором запущен Expo CLI.
Открытие приложения на вашем телефоне/планшете
Вы можете открыть проект на нескольких устройствах одновременно. Попробуйте его на iPhone и Android одновременно, если у вас есть и то, и другое под рукой.
На iPhone или iPad откройте приложение Apple «Камера» по умолчанию и отсканируйте QR-код, который вы видите в терминале или в Expo Dev Tools. На вашем устройстве Android нажмите «Сканировать QR-код» на вкладке «Проекты» приложения Expo Go и отсканируйте QR-код, который вы видите в терминале или в инструментах разработки Expo.
Hello World
После того, как мы установили и запустили VS Code можно начать работу. Для этого открываем файл App.js в корне проекта. В этом файле описано, что будет видеть пользователь при запуске приложения. Мы можем изменить несколько строк и при сохранении картинка на симуляторе изменится. Замените весь код в файле App.js на представленный ниже и сохраните файл:
import React from 'react' import StyleSheet, Text > from 'react-native' const App = () => return ( > Text style=styles.h1>>Hello WorldText> > ) > const styles = StyleSheet.create( h1: backgroundColor: '#BEFCE5', color: '#000', fontSize: 25, fontWeight: '700', padding: 20, textAlign: 'center' > >) export default App
Шрифты
И iOS, и Android, и большинство настольных операционных систем поставляются со своим собственным набором шрифтов платформы, но если вы хотите привнести в свое приложение еще немного индивидуальности бренда, хорошо подобранный шрифт может пройти долгий путь. И поскольку каждая операционная система имеет свой собственный набор шрифтов платформы, если вы хотите создать опыт, совместимый для всех пользователей, вы захотите использовать свои собственные шрифты в своем проекте. Это руководство покажет вам, как это сделать.
Использование шрифта Google
Expo имеет первоклассную поддержку всех шрифтов, перечисленных в Google Fonts Чтобы использовать один из них, ознакомьтесь с проектом Expo Google Fonts. С помощью этих пакетов вы можете быстро интегрировать любые варианты шрифтов или шрифтов. Чтобы использовать шрифт Inter, вы можете установить пакет [@expo-google-fonts/inter](https://www.npmjs.com/package/@expo-google-fonts/inter) с помощью приведенной ниже команды.
expo install expo-font @expo-google-fonts/inter
После этого вы можете интегрировать это в свой проект с помощью хука useFonts в корне вашего приложения.
import React from 'react' import View, Text > from 'react-native' import AppLoading from 'expo-app-loading' import useFonts, Inter_900Black > from '@expo-google-fonts/inter' export default function App() let [fontsLoaded] = useFonts( Inter_900Black, >) if (!fontsLoaded) return AppLoading /> > else return ( View style= flex: 1, justifyContent: 'center', alignItems: 'center' >>> Text style= fontFamily: 'Inter_900Black', fontSize: 40 >>>Inter BlackText> View> ) > >
Минимальный, но полный рабочий пример
Чтобы создать новый проект, включающий этот пример, запустите npx create-react-native-app —template with-custom-font в вашем терминале.
import React from 'react' import Text, View > from 'react-native' import AppLoading from 'expo-app-loading' import useFonts > from 'expo-font' export default props => let [fontsLoaded] = useFonts( 'Inter-Black': require('./assets/fonts/Inter-Black.otf'), >) if (!fontsLoaded) return AppLoading /> > else return ( View style= flex: 1, justifyContent: 'center', alignItems: 'center' >>> Text style= fontFamily: 'Inter-Black', fontSize: 40 >>>Inter BlackText> Text style= fontSize: 40 >>>Platform DefaultText> View> ) > >
Получение шрифта
Первое, что вам понадобится, это файл шрифта. В этом примере мы используем Inter Black из бесплатного семейства шрифтов Inter с открытым исходным кодом Расмуса Андерсона. Соглашение в приложениях Expo заключается в том, чтобы поместить шрифты в каталог ./assets/fonts , но вы можете поместить их в любом месте.
Поддерживаемые форматы шрифтов
Двумя официально поддерживаемыми форматами шрифтов для платформы Expo являются OTF и TTF. Вы должны использовать один из этих форматов, когда сможете. Если ваш шрифт имеет другой формат, попробуйте преобразовать его в один из этих форматов. Это единственные форматы шрифтов, которые последовательно работают в Expo в Интернете, Android и iOS. Если у вас есть версии шрифта OTF и TTF, предпочтите OTF. OTF — это более новый формат, а файлы .otf часто меньше, чем файлы .ttf, и иногда файлы OTF будут отображаться немного лучше в определенных контекстах. В целом, оба формата очень похожи и вполне приемлемы.
За пределами OTF и TTF
Если вам нужно использовать другой формат, вам может потребоваться настроить конфигурацию комплектации Metro, чтобы заставить работать что-либо, кроме TTF и OTF. В целом, просто не делайте этого, если вы действительно не уверены, что хотите. Попытка отобразить формат шрифта, который не поддерживает платформа, в некоторых случаях может привести к сбою вашего приложения.
Встроенные шрифты платформы
Если вы не хотите использовать пользовательский шрифт, лучше всего просто использовать шрифт платформы по умолчанию, не указывая гарнитуру. Каждая платформа, поддерживаемая приложениями Expo, имеет различный набор шрифтов, доступных по умолчанию, поэтому нет хорошего способа указать тот, который будет работать везде, не предоставляя свой собственный пользовательский шрифт. Если вам интересно, Nader Dabit ведет список шрифтов, всегда доступных на iOS и Android. А в Интернете вы можете указать ряд общих семейств шрифтов. Разные пользователи, браузеры и операционные системы будут настроены на использование разных шрифтов для каждой из спецификаций этих семейств шрифтов. Например, Safari на iPhone будет использовать Сан-Франциско по умолчанию без засечек, в то время как Microsoft Edge в Windows будет использовать Arial, а Chrome на Android обычно будет использовать Roboto, хотя телефоны OnePlus часто будут использовать Slate, etc., etc..
- sans-serif
- serif
- monospace
- fantasy
- cursive В целом, ваши самые безопасные ставки заключаются только в том, чтобы использовать системное значение по умолчанию, которое обычно будет легко читаемым шрифтом без засечек, с которым должен быть знаком пользователь любой системы; или использовать свой собственный пользовательский шрифт, чтобы у вас был точный контроль над тем, что увидит пользователь.
Использование компонента
Поскольку ваши шрифты не будут готовы сразу, как правило, рекомендуется ничего не отображать, пока шрифт не будет готов.
Отличный способ сделать это — использовать компонент . В простейшей форме вы можете просто отобразить его, пока ждете загрузки вашего приложения.
Иногда — особенно в Интернете — люди предпочитают отображать свой контент шрифтом платформы по умолчанию во время загрузки их пользовательских шрифтов. Или, в качестве альтернативы, для визуализации остальной части их контента, это не зависит от пользовательского шрифта во время загрузки шрифта. Эти подходы называются FOUT и FOIT, и вы можете прочитать о них гораздо больше в Интернете. Как правило, эти стратегии не рекомендуются для приложений Expo. Если вы включите свои шрифты в свой проект, шрифты всегда будут доставлены пользователю к моменту выполнения вашего кода. Единственное исключение из этого правила заключается в том, что вы можете предпочесть делать это в Интернете.
Дополнительная информация
Вам, вероятно, не нужно ничего знать за пределами этого в этом руководстве, чтобы эффективно использовать пользовательские шрифты в вашем приложении, но если вам интересно или ваш сценарий использования не был рассмотрен вышеуказанной информацией, пожалуйста, продолжайте читать.
Загрузка удаленного шрифта прямо из Интернета
В целом, лучше и безопаснее всего загружать шрифты из ваших локальных активов. Если вы отправите в магазины приложений, они будут включены в комплект загрузки и сразу же доступны. И вам не нужно беспокоиться о CORS или других потенциальных проблемах. Но если вы хотите это сделать, также можно загрузить удаленный файл шрифта непосредственно из Интернета, а не из активов вашего проекта. Для этого просто замените require (‘./assets/fonts/MyFont.otf’) URL-адресом вашего шрифта. Вот минимальный, полный пример.
import React from 'react' import Text, View > from 'react-native' import AppLoading from 'expo-app-loading' import useFonts > from 'expo-font' export default props => let [fontsLoaded] = useFonts( 'Inter-SemiBoldItalic': 'https://rsms.me/inter/font-files/Inter-SemiBoldItalic.otf?v=3.12', >) if (!fontsLoaded) return AppLoading /> > else return ( View style= flex: 1, justifyContent: 'center', alignItems: 'center' >>> Text style= fontFamily: 'Inter-SemiBoldItalic' >>>Inter SemiBoldItalicText> Text>Platform DefaultText> View> ) > >
При загрузке удаленных шрифтов убедитесь, что они обслуживаются из источника с правильно настроенным CORS. Если вы этого не сделаете, ваш удаленный шрифт может неправильно загрузиться на веб-платформе.
Использование Font.loadAsync вместо хука useFonts
Если вы не хотите использовать перехватчик useFonts (например, вы предпочитаете компоненты класса), вы можете использовать Font.loadAsync напрямую. Под капотом происходит то, что ваши шрифты загружаются с использованием Font.loadAsync из библиотеки expo-font . Вы можете использовать это напрямую, если хотите, или если вы хотите иметь более детальный контроль над тем, когда ваши шрифты загружаются перед рендерингом.
import React from 'react' import Text, View, StyleSheet > from 'react-native' import AppLoading from 'expo-app-loading' import * as Font from 'expo-font' let customFonts = 'Inter-Black': require('./assets/fonts/Inter-Black.otf'), 'Inter-SemiBoldItalic': 'https://rsms.me/inter/font-files/Inter-SemiBoldItalic.otf?v=3.12', > export default class App extends React.Component state = fontsLoaded: false, > async _loadFontsAsync() await Font.loadAsync(customFonts); this.setState( fontsLoaded: true >); > componentDidMount() this._loadFontsAsync(); > render() if (this.state.fontsLoaded) return ( View style= flex: 1, justifyContent: 'center', alignItems: 'center' >>> Text>Platform DefaultText> Text style= fontFamily: 'Inter-Black' >>>Inter BlackText> Text style= fontFamily: 'Inter-SemiBoldItalic' >>>Inter SemiBoldItalicText> View> ) > else return AppLoading /> > > >
Иконки
Как бы модно это ни было в наши дни, не каждое приложение должно использовать эмодзи для всех значков — может быть, вы хотите втянуть популярный набор через шрифт значков, такой как FontAwesome, Glyphicons или Ionicons, или вы просто используете некоторые PNG, которые тщательно выбрали в The Noun Project. Давайте посмотрим, как сделать оба этих подхода
@expo/vector-icons
Эта библиотека устанавливается по умолчанию в проект-шаблон, который проходит через expo init — она является частью пакета expo . Он включает популярные наборы значков, и вы можете просматривать все значки с помощью icons.expo.fyi.
import * as React from 'react' import View, StyleSheet > from 'react-native' import Ionicons > from '@expo/vector-icons' export default function App() return ( View style=styles.container>> Ionicons name="md-checkmark-circle" size=32> color="green" /> View> ) > const styles = StyleSheet.create( container: flex: 1, justifyContent: 'center', alignItems: 'center', >, >)
Этот компонент загружает шрифт Ionicons , если он еще не был загружен, и отображает значок галочки, который я нашел в каталоге векторных значков, упомянутом выше. @expo/vector-icons построен на основе react-native-vector-icons и использует аналогичный API. Единственная разница в том, что @expo/vector-icons использует более идиоматический стиль import : import < Ionicons >from ‘@expo/vector-icons’; вместо import Ionicons from ‘react-native-vector-icons/Ionicons’; .
Примечание: Как и в случае с любым пользовательским шрифтом в Expo, вы можете предварительно загрузить шрифты значков перед рендерингом вашего приложения. Объект font доступен в виде статического свойства компонента font, поэтому в приведенном выше случае это Ionicons.font , который вычисляется как .Узнайте больше о предварительной загрузке активов.
Пользовательские шрифты значков
Во-первых, убедитесь, что вы импортировали собственный шрифт значка. Узнайте больше о загрузке пользовательских шрифтов. После загрузки шрифта вам необходимо создать набор значков. @expo/vector-icons предоставляет три метода, которые помогут вам создать набор значков.
createIconSet
Возвращает ваш собственный шрифт на основе glyphMap , где ключ — это имя значка, а значение — либо символ UTF-8, либо его код символа. fontFamily — это имя шрифта, а НЕ имя файла. ExpoAssetId может быть любым, что вы можете передать в Font.loadAsync. Подробнее см. react-native-vector-icons.
import * as React from 'react' import * as Font from 'expo-font' import createIconSet > from '@expo/vector-icons' const glyphMap = 'icon-name': 1234, test: '∆' > const CustomIcon = createIconSet(glyphMap, 'FontName', 'custom-icon-font.ttf') export default class CustomIconExample extends React.Component render() return CustomIcon name="icon-name" size=32> color="red" /> > >
createIconSetFromFontello
Удобный метод для создания пользовательского шрифта на основе конфигурационного файла Fontello. Не забудьте импортировать шрифт, как описано выше, и перебросить config.json в удобное место в вашем проекте, используя Font.loadAsync .
// Как только ваш пользовательский шрифт будет загружен . import createIconSetFromFontello > from '@expo/vector-icons' import fontelloConfig from './config.json' // И имя шрифта, и файлы, экспортированные из Fontello, скорее всего, называются "fontello". const Icon = createIconSetFromFontello(fontelloConfig, 'fontello', 'fontello.ttf')
createIconSetFromIcoMoon
Удобный метод для создания пользовательского шрифта на основе конфигурационного файла IcoMoon. Не забудьте импортировать шрифт, как описано выше, и перебросить config.json в удобное место в вашем проекте, используя Font.loadAsync .
import React from 'react' import Text, View, StyleSheet > from 'react-native' import AppLoading from 'expo-app-loading' import useFonts > from 'expo-font' import createIconSetFromIcoMoon > from '@expo/vector-icons' const Icon = createIconSetFromIcoMoon( require('./assets/icomoon/selection.json'), 'IcoMoon', 'icomoon.ttf' ) export default function App() // Load the icon font before using it const [fontsLoaded] = useFonts( IcoMoon: require('./assets/icomoon/icomoon.ttf') >) if (!fontsLoaded) return AppLoading /> > return ( View style=styles.container>> Icon name="pacman" size=50> color="red" /> View> ) > const styles = StyleSheet.create( container: flex: 1, justifyContent: 'center', alignItems: 'center', >, >)
Изображения значков
Если вы знаете, как использовать компонент react-native , это будет очень просто.
import * as React from 'react' import Image, View, StyleSheet > from 'react-native' export default function App() return ( View style=styles.container>> Image source=require('./assets/images/slack-icon.png')> fadeDuration=0> style= width: 50, height: 50 >> /> View> ) > const styles = StyleSheet.create( container: flex: 1, justifyContent: 'center', alignItems: 'center', >, >)
Предположим, что наш класс SlackIcon находится в my-project/components/SlackIcon.js , а наши изображения значков находятся в my-project/assets/images , чтобы ссылаться на изображение, которое мы используем, требовать и включать относительный путь. Вы можете предоставить версии своего значка с различной плотностью пикселей, и соответствующее изображение будет автоматически использовано для вас. В этом примере у нас на самом деле есть slack-icon@2x.png и slack-icon@3x.png , поэтому, если я просматриваю это на iPhone 6s, я увижу изображение slack-icon@3x.png . Подробнее об этом читайте в руководстве по изображениям в документации по react-native. Мы также устанавливаем fadeDuration (свойство Android) равным 0 , потому что обычно мы хотим, чтобы значок появлялся немедленно, а не исчезал в течение нескольких сотен миллисекунд.
Компонент кнопки
Удобный компонент для создания кнопок со значком слева.
import * as React from 'react' import View, StyleSheet > from 'react-native' import FontAwesome > from '@expo/vector-icons' export default function App() const loginWithFacebook = () => console.log('Button pressed') > return ( View style=styles.container>> FontAwesome.Button name="facebook" backgroundColor="#3b5998" onPress=loginWithFacebook>> Login with Facebook FontAwesome.Button> View> ) > const styles = StyleSheet.create( container: flex: 1, justifyContent: 'center', alignItems: 'center', >, >)
Итог
На этом уроке мы научились устанавливать и установили Expo, шрифты и иконки.
Проблемы?
Пишите в Discord или телеграмм чат, а также подписывайтесь на наши новости
Done
Чтобы узнать, насколько хорошо вы усвоили этот урок, пройдите тест в мобильном приложении нашей школы по этой теме или в боте Telegram.

- Expo CLI
- Требования
- Рекомендуемые инструменты
- Установка Expo CLI
- Expo Go для iOS или Android
- Создание проекта на Expo
- Запуск сервера разработки
- Открытие приложения на вашем телефоне/планшете
- Hello World
- Шрифты
- Использование шрифта Google
- Минимальный, но полный рабочий пример
- Получение шрифта
- Поддерживаемые форматы шрифтов
- За пределами OTF и TTF
- Встроенные шрифты платформы
- Использование компонента
- Дополнительная информация
- Загрузка удаленного шрифта прямо из Интернета
- Использование Font.loadAsync вместо хука useFonts
- Иконки
- @expo/vector-icons
- Пользовательские шрифты значков
- createIconSet
- createIconSetFromFontello
- createIconSetFromIcoMoon
- Изображения значков
- Компонент кнопки
- Итог
- Проблемы?
- Done
События указателя
События указателя (Pointer events) – это современный способ обработки ввода с помощью различных указывающих устройств, таких как мышь, перо/стилус, сенсорный экран и так далее.
Краткая история
Сделаем небольшой обзор, чтобы вы поняли общую картину и место событий указателя среди других типов событий.
- Давным-давно, в прошлом, существовали только события мыши Затем получили широкое распространение сенсорные устройства, в частности телефоны и планшеты. Чтобы скрипты корректно работали, они генерировали (и до сих пор генерируют) события мыши. Например, касание сенсорного экрана генерирует событие mousedown . Таким образом, сенсорные устройства позволяли работать с существующими веб-страницами. Но сенсорные устройства во многих аспектах мощнее, чем мышь. Например, они позволяют касаться экрана сразу в нескольких местах («мульти-тач»). Однако, события мыши не имеют необходимых свойств для обработки таких прикосновений.
- Поэтому появились события касания (Touch events), такие как touchstart , touchend , touchmove , которые имеют специфичные для касаний свойства (мы не будем здесь рассматривать их подробно, потому что события указателя ещё лучше). Но и этих событий оказалось недостаточно, так как существует много других устройств, таких как перо, у которых есть свои особенности. Кроме того, универсальный код, который отслеживал бы и события касаний и события мыши, неудобно писать.
- Для решения этих задач был внедрён стандарт Pointer Events («События Указателя»). Он предоставляет единый набор событий для всех типов указывающих устройств.
К настоящему времени спецификация Pointer Events Level 2 поддерживается всеми основными браузерами, а Pointer Events Level 3 находится в разработке и почти полностью совместима с Pointer Events Level 2.
Если вы не разрабатываете под старые браузеры, такие как Internet Explorer 10, Safari 12, или более ранние версии, больше нет необходимости использовать события мыши или касаний – можно переходить сразу на события указателя.
При этом ваш код будет корректно работать и с сенсорными устройствами и с мышью. Впрочем, у событий указателя есть важные особенности, которые нужно знать, чтобы их правильно использовать, без лишних сюрпризов. Мы отметим их в этой статье.
Типы событий указателя
Схема именований событий указателя похожа на события мыши:
| Событие указателя | Аналогичное событие мыши |
|---|---|
| pointerdown | mousedown |
| pointerup | mouseup |
| pointermove | mousemove |
| pointerover | mouseover |
| pointerout | mouseout |
| pointerenter | mouseenter |
| pointerleave | mouseleave |
| pointercancel | — |
| gotpointercapture | — |
| lostpointercapture | — |
Как мы видим, для каждого mouse есть соответствующее pointer , которое играет аналогичную роль. Также есть 3 дополнительных события указателя, у которых нет соответствующего аналога mouse. , скоро мы их разберём.
Замена mouse <событий>на pointer в кодесобытий>
Мы можем заменить события mouse. на аналогичные pointer. в коде и быть уверенными, что с мышью по-прежнему всё будет работать нормально.
При этом поддержка сенсорных устройств «волшебным» образом улучшится. Хотя, возможно, кое-где понадобится добавить touch-action: none в CSS. Подробнее мы разберём это ниже, в секции про pointercancel .
Свойства событий указателя
События указателя содержат те же свойства, что и события мыши, например clientX/Y , target и т.п., и несколько дополнительных:
- pointerId – уникальный идентификатор указателя, вызвавшего событие. Идентификатор генерируется браузером. Это свойство позволяет обрабатывать несколько указателей, например сенсорный экран со стилусом и мульти-тач (увидим примеры ниже).
- pointerType – тип указывающего устройства. Должен быть строкой с одним из значений: «mouse», «pen» или «touch». Мы можем использовать это свойство, чтобы определять разное поведение для разных типов указателей.
- isPrimary – равно true для основного указателя (первый палец в мульти-тач).
Некоторые устройства измеряют область контакта и степень надавливания, например пальца на сенсорном экране, для этого есть дополнительные свойства:
- width – ширина области соприкосновения указателя (например, пальца) с устройством. Если не поддерживается, например мышью, то всегда равно 1 .
- height – высота области соприкосновения указателя с устройством. Если не поддерживается, например мышью, то всегда равно 1 .
- pressure – степень давления указателя в диапазоне от 0 до 1. Для устройств, которые не поддерживают давление, принимает значение 0.5 (нажато) либо 0 .
- tangentialPressure – нормализованное тангенциальное давление.
- tiltX , tiltY , twist – специфичные для пера свойства, описывающие положение пера относительно сенсорной поверхности.
Эти свойства большинством устройств не поддерживаются, поэтому редко используются. При необходимости, подробности о них можно найти в спецификации.
Мульти-тач
Одной из функций, которую абсолютно не поддерживают события мыши, является мульти-тач: возможность касаться сразу нескольких мест на телефоне или планшете или выполнять специальные жесты.
События указателя позволяют обрабатывать мульти-тач с помощью свойств pointerId и isPrimary .
Вот что происходит, когда пользователь касается сенсорного экрана в одном месте, а затем в другом:
- При касании первым пальцем:
- происходит событие pointerdown со свойством isPrimary=true и некоторым pointerId .
- При касании вторым и последующими пальцами (при остающемся первом):
- происходит событие pointerdown со свойством isPrimary=false и уникальным pointerId для каждого касания.
Обратите внимание: pointerId присваивается не на всё устройство, а для каждого касающегося пальца. Если коснуться экрана 5 пальцами одновременно, получим 5 событий pointerdown , каждое со своими координатами и индивидуальным pointerId .
События, связанные с первым пальцем, всегда содержат свойство isPrimary=true .
Мы можем отслеживать несколько касающихся экрана пальцев, используя их pointerId . Когда пользователь перемещает, а затем убирает палец, получаем события pointermove и pointerup с тем же pointerId , что и при событии pointerdown .
Вот небольшое демо, выводящее события pointerdown и pointerup :
Обратите внимание: чтобы увидеть разницу в pointerId/isPrimary , вам нужно использовать устройство с сенсорным экраном, такое как телефон или планшет. Для устройств без поддержки мульти-тач, таких как мышь, всегда будет один и тот же pointerId со свойством isPrimary=true , для всех событий указателя.
Событие: pointercancel
Событие pointercancel происходит, когда текущее действие с указателем по какой-то причине прерывается, и события указателя больше не генерируются.
К таким причинам можно отнести:
- Указывающее устройство было физически выключено.
- Изменилась ориентация устройства (перевернули планшет).
- Браузер решил сам обработать действие, считая его жестом мыши, масштабированием и т.п.
Мы продемонстрируем pointercancel на практическом примере, чтобы увидеть, как это влияет на нас.
Допустим, мы реализуем перетаскивание («drag-and-drop») для нашего мяча, как в начале статьи Drag’n’Drop с событиями мыши.
Вот последовательность действий пользователя и соответствующие события:
- Пользователь нажимает на изображении, чтобы начать перетаскивание
- происходит событие pointerdown
- Затем он перемещает указатель, двигая изображение
- происходит событие pointermove (возможно, несколько раз)
- И тут происходит сюрприз! Браузер имеет встроенную поддержку «Drag’n’Drop» для изображений, которая запускает и перехватывает процесс перетаскивания, генерируя при этом событие pointercancel .
- Теперь браузер сам обрабатывает перетаскивание изображения. У пользователя есть возможность перетащить изображение мяча даже за пределы браузера, в свою почтовую программу или файловый менеджер.
- Событий pointermove для нас больше не генерируется.
Таким образом, браузер «перехватывает» действие: в начале переноса drag-and-drop запускается событие pointercancel , и после этого события pointermove больше не генерируются.
Вот демо drag’n’drop с записью событий указателя (только up/down , move и cancel ) в textarea :
Мы бы хотели реализовать перетаскивание самостоятельно, поэтому давайте скажем браузеру не перехватывать его.
Предотвращайте действие браузера по умолчанию, чтобы избежать pointercancel .
Нужно сделать две вещи:
- Предотвратить запуск встроенного drag’n’drop
- Мы можем сделать это, задав ball.ondragstart = () => false , как описано в статье Drag’n’Drop с событиями мыши.
- Это работает для событий мыши.
- Для устройств с сенсорным экраном существуют другие действия браузера, связанные с касаниями, кроме drag’n’drop. Чтобы с ними не возникало проблем:
- Мы можем предотвратить их, добавив в CSS свойство #ball < touch-action: none >.
- Затем наш код начнёт корректно работать на устройствах с сенсорным экраном
После того, как мы это сделаем, события будут работать как и ожидается, браузер не будет перехватывать процесс и не будет вызывать событие pointercancel .
В данном демо произведены нужные действия:
Как вы можете видеть, событие pointercancel больше не срабатывает.
Теперь мы можем добавить код для перемещения мяча и наш drag’n’drop будет работать и для мыши и для устройств с сенсорным экраном.
Захват указателя
Захват указателя – особая возможность событий указателя.
Общая идея очень проста, но поначалу может показаться странной, так как для других событий ничего подобного просто нет.
- elem.setPointerCapture(pointerId) – привязывает события с данным pointerId к elem . После такого вызова все события указателя с таким pointerId будут иметь elem в качестве целевого элемента (как будто произошли над elem ), вне зависимости от того, где в документе они произошли.
Другими словами, elem.setPointerCapture(pointerId) меняет target всех дальнейших событий с данным pointerId на elem .
Эта привязка отменяется:
- автоматически, при возникновении события pointerup или pointercancel ,
- автоматически, если elem удаляется из документа,
- при вызове elem.releasePointerCapture(pointerId) .
Захват указателя используется для упрощения операций с переносом (drag’n’drop) элементов.
В качестве примера давайте вспомним реализацию слайдера из статьи Drag’n’Drop с событиями мыши.
Мы делаем элемент для слайдера – полоску с «ползунком» ( thumb ) внутри:
Со стилями, это выглядит следующим образом:
Затем он работает так:
- Пользователь сначала нажимает на ползунок thumb – срабатывает pointerdown .
- Затем двигает его указателем – срабатывает pointermove , и наш код перемещает элемент thumb .
- …Причём, по мере движения, указатель может покидать ползунок – перемещаться выше или ниже. При этом ползунок должен передвигаться строго по горизонтали, на одной линии с указателем.
В решении, основанном на событиях мыши, для отслеживания всех движений указателя, включая те, которые происходят выше/ниже элемента thumb , мы должны были назначить обработчик события mousemove на весь документ document .
Однако это не самое правильное решение. Одна из проблем – это то, что движения указателя по документу могут вызвать сторонние эффекты, заставить работать другие обработчики (например, mouseover ), не имеющие отношения к слайдеру.
Именно здесь вступает в игру setPointerCapture :
- Мы можем вызывать thumb.setPointerCapture(event.pointerId) в обработчике pointerdown ,
- Тогда дальнейшие события указателя до pointerup/cancel будут привязаны к thumb .
- Затем, когда произойдёт pointerup (передвижение завершено), привязка будет автоматически удалена, нам об этом не нужно беспокоиться.
Так что, даже если пользователь будет двигать указателем по всему документу, обработчики событий будут вызваны на thumb . Причём все свойства объекта события, такие как clientX/clientY , будут корректны – захват указателя влияет только на target/currentTarget .
Вот основной код:
thumb.onpointerdown = function(event) < // перенацелить все события указателя (до pointerup) на thumb thumb.setPointerCapture(event.pointerId); // начать отслеживание перемещения указателя thumb.onpointermove = function(event) < // перемещение слайдера: отслеживание thumb, т.к все события указателя перенацелены на него let newLeft = event.clientX - slider.getBoundingClientRect().left; thumb.style.left = newLeft + 'px'; >; // если сработало событие pointerup, завершить отслеживание перемещения указателя thumb.onpointerup = function(event) < thumb.onpointermove = null; thumb.onpointerup = null; // . при необходимости также обработайте "конец перемещения" >; >; // примечание: нет необходимости вызывать thumb.releasePointerCapture, // это происходит автоматически при pointerup
В демонстрационном примере также имеется дополнительный элемент с обработчиком onmouseover , показывающий текущую дату.
Обратите внимание: пока вы перетаскиваете ползунок, вы можете навести курсор на этот элемент, и его обработчик не сработает.
Таким образом, благодаря setPointerCapture перетаскивание теперь не имеет побочных эффектов.
Таким образом, мы имеем два бонуса:
- Код становится чище, поскольку нам больше не нужно добавлять/удалять обработчики для всего документа. Удаление привязки происходит автоматически.
- Если в документе есть какие-то другие обработчики pointermove , то они не будут нечаянно вызваны, пока пользователь находится в процессе перетаскивания слайдера.
События при захвате указателя
Существует два связанных с захватом события:
- gotpointercapture срабатывает, когда элемент использует setPointerCapture для включения захвата.
- lostpointercapture срабатывает при освобождении от захвата: явно с помощью releasePointerCapture или автоматически, когда происходит событие pointerup / pointercancel .
Итого
События указателя позволяют одновременно обрабатывать действия с помощью мыши, касания и пера, в едином фрагменте кода.
События указателя расширяют события мыши. Мы можем заменить mouse на pointer в названиях событий и код продолжит работать для мыши, при этом получив лучшую поддержку других типов устройств.
При обработке переносов и сложных касаний, которые браузер может попытаться обработать сам, не забывайте отменять действие браузера и ставить touch-action: none в CSS для элементов, с которыми мы взаимодействуем.
Дополнительные возможности событий указателя:
- Поддержка мультитач с помощью pointerId и isPrimary .
- Особые свойства для определённых устройств, такие как pressure , width/height и другие.
- Захват указателя: мы можем перенаправить все события указателя на определённый элемент до наступления события pointerup / pointercancel .
На данный момент события указателя поддерживаются в основных браузерах, поэтому мы можем безопасно переходить на них, особенно если нет необходимости в поддержке IE10 и Safari 12. И даже для этих браузеров есть полифилы, которые добавляют эту поддержку.
Зарабатывайте вместе с нами

Для пополнения программы в поиске введите «UTAX» (Ваш город) — позывной – оплата. Пополняйте счёт через платежные системы: iBOX, EASY PAY, ФК Система, Приват 24, 2Click, monobank. Так же можете выполнять безнальные заказы, сумма будет зачислена на баланс в программе
Что такое скилл и зачем он нужен?
Скилл — это функция, которая позволяет пользоваться определёнными привилегиями, такими как: выставление радиуса подачи, сектора, междугородние заказы. Скилл просчитывается в процентном соотношении за принятые заказы, чем выше скилл — тем больше функций Вам будет доступно
