Автор: Хань Юнхао, инженер по фронтенд-разработке, отдел мобильных разработок.
В начале ноября этого года наша компания приняла участие в «Азиатской ежегодной конференции по дошкольному образованию 2017 (APEAC)» и добилась очень хороших результатов. Мне посчастливилось отвечать за разработку внешнего интерфейса этой отображаемой страницы, и в этой статье описаны ключевые ссылки в процессе разработки.
Страница отображения разделена на три модуля: отображение данных, динамическое отображение и отображение карты. Эффект следующий:
Отображение данных
Этот модуль отображает различные данные нашей компании на данный момент и регулярно обновляется с помощью асинхронных запросов.
Динамический эффект перехода номера аналогичен эффекту игрового автомата.Новый номер соответствующей цифры заменяет старый номер снизу вверх.Если номер цифры не изменился, эффекта перехода нет.
Для достижения этого эффекта первый шаг - это побитовое нарезать число побитового питания:
// 分离每个数字
function split(num) {
return (num || 0).toString().split('');
}
Затем увеличьте тысячный разряд, то есть начните с единицы, и через каждые три цифры ставьте запятую.Код реализации выглядит следующим образом:
function toThousands(num) {
var num = (num || 0).toString(), result = '';
while (num.length > 3) {
result = ',' + num.slice(-3) + result;
num = num.slice(0, num.length - 3);
}
if (num) { result = num + result; }
return result;
}
Наконец, используйте стиль для управления анимацией перехода Код клавиши выглядит следующим образом:
<ul id="main" class="number">
<li class="group">
<span class="old">1</span>
<span class="new">1</span>
</li>
<li class="group">
<span class="old">,</span>
<span class="new">,</span>
</li>
<li class="group">
<span class="old">4</span>
<span class="new">1</span>
</li>
<li class="group">
<span class="old">5</span>
<span class="new">5</span>
</li>
<li class="group">
<span class="old">6</span>
<span class="new">2</span>
</li>
</ul>
.number li {
width: 0.18rem;
height: 0.24rem;
line-height: 0.24rem;
display: inline-block;
overflow: hidden;
}
.number li span {
display: block;
transform: translateY(0%);
}
.number li.active span {
animation: move 0.3s;
animation-fill-mode: forwards; // 让动画结束后保持最后一帧
}
@keyframes move {
from {
transform: translateY(0);
}
to {
transform: translateY(-100%);
}
}
var $main = document.querySelector('#main');
// 填充数字
function update(fromArr, toArr) {
// 从个位数开始对齐位数
fromArr = fromArr.reverse();
toArr = toArr.reverse();
if (fromArr.length > toArr.length) {
toArr.length = fromArr.length
} else {
fromArr.length = toArr.length
}
fromArr = fromArr.reverse();
toArr = toArr.reverse();
// 渲染节点并激活动画
var numberHTML = ''
for (var i = 0; i < toArr.length; i++) {
// 如果该位数的数字没有发生变化,则没有过渡效果
if (formArr[i] !== toArr[i]) {
numberHTML += ('<li class="group active">' +
'<span class="old">' + formArr[i] || '' + '</span>' +
'<span class="new">' + toArr[i] || '' + '</span>' +
'</li>');
} else {
numberHTML += ('<li class="group">' +
'<span class="old">' + formArr[i] || '' + '</span>' +
'<span class="new">' + toArr[i] || '' + '</span>' +
'</li>');
}
}
if (numberHTML) {
$main.innerHTML = numberHTML;
}
}
Динамический дисплей
Этот модуль представляет собой зону для взаимодействия туристов на месте. Пока вы сканируете QR-код и лайкаете, будет добавлена новая динамика. Во время работы страницы могут одновременно публиковать новости несколько человек, поэтому должен быть поток для регулярного запроса данных и сохранения данных в очереди:
В то же время другому потоку нужно считать данные очереди на отрисовку:
Код ключа следующий:
var cacheList = []; // 队列列表
var CHECK_INTERVAL = 2000; // 每个两秒检查一下队列
var UPDATE_INTERVAL = 1000; // 插入数据间隔
var MIN_CACHE = 10; // 储备数
// 检查队列
function checkCache() {
if (cacheList.length < MIN_CACHE) {
// 异步请求数据
ajax(function(res) {
if (res && res.length) {
cacheList = cacheList.concat(res); // 把新的数据合并到队列列表
setTimeout(checkCache, CHECK_INTERVAL); // 轮询检查数据
}
}
}
}
// 开始加载
function loadData() {
if (cacheList.length > 0) {
render(cacheList[0]);
cacheList = cacheList.splice(0, 1);
}
setTimeout(start, UPDATE_INTERVAL); // 轮询读取数据
}
loadData(); // 数据启动
checkCache(); // 队列启动
отображение карты
Этот модуль состоит из карты Китая, фиксированных световых пятен, мигающих световых пятен и динамических пузырей. Поскольку и блики, и пузыри связаны с географическим местоположением (с точностью до провинции), каждая провинция сначала размечается на карте. Однако оккупация провинций нерегулярна, и разделить их будет сложно. Первоначальная идея состоит в том, что каждая провинция имеет фиксированное количество очков, и пузыри и блики будут появляться только в этих позициях. Хотя эффект может быть достигнут, он выглядит относительно жестким и не достигает эффекта дизайна. Поэтому другой план был изменен. При вычислении площади неправильной фигуры исчисление делит большую неправильную фигуру на несколько маленьких прямоугольников, чтобы покрыть всю неправильную фигуру. Точно так же вам нужно только нарисовать несколько маленьких прямоугольников, соответствующих провинциям, и записать их, чтобы световые пятна и пузыри могли появиться в позициях соответствующих провинций в соответствии с этими координатами. Для того, чтобы легко рисовать эти маленькие прямоугольники, я сделал небольшой инструмент, эффект выглядит следующим образом:
Поскольку страница адаптируется к ширине и высоте в соответствии с разрешением экрана, размер карты на странице не фиксирован (но масштаб фиксирован), поэтому здесь делается небольшая корректировка, а вместо этого генерируются координаты в процентах. значений пикселей. Например:
// 记录的省份数据
var positionData = {
新疆: [
{
startX: '6.7164179104477615%',
endX: '34.07960199004975%',
startY: '8.602941176470589%',
endY: '19.77941176470588%'
},
{
startX: '25.37313432835821%',
endX: '35.69651741293532%',
startY: '3.5049019607843137%',
endY: '8.602941176470589%'
},
...
],
广东: [
{
...
},
...
],
...
};
Наконец, вам нужно только выбрать блок в разделенном маленьком прямоугольнике, а затем случайным образом выбрать точку из области этого маленького прямоугольника для отображения световых пятен и пузырьков:
// 地图
var $map = document.querySelector('#map');
// 随机获取一个点
function getPosition(province) {
// 获取省里面随机一个小矩形
function getPositionArea(areaArray) {
return areaArray[Math.round(Math.random() * areaArray.length)];
}
// 选定一个小矩形
var area = getPositionArea(positionData[province]);
var x = parseFloat(area.endX) - parseFloat(area.startX);
var y = parseFloat(area.endY) - parseFloat(area.startY);
return {
x: parseFloat(area.startX) + (Math.random() * x) + '%',
y: parseFloat(area.startY) + (Math.random() * y) + '%'
};
}
// 获取新的光点
function getPoint($point, province) {
if (!$point) {
$point = document.createElement('div');
// 如果动画结束则移除光点,并重新开始
$point.addEventListener('animationend', function() {
$point.classList.remove('active');
start($point);
});
}
// 更新节点坐标和其他样式
var position = getPosition(provice);
...
return $point;
}
// 刷新样式并随机加入地图
function start($point) {
$point = getPoint($point);
setTimeout(function() {
$point.classList('active');
}, Math.round(Math.radom() * 1000))
}
// 创建六百个光点
var POINT_COUNT = 600;
for (var i = 0; i < POINT_COUNT; i++) {
start();
}
Закончено.
первая помощь
Из вышеизложенного видно, что на странице много данных и анимаций, и оборудование выставки может не соответствовать таким требованиям производительности. Если вы столкнулись с машиной с более низкой производительностью, вам необходимо уменьшить данные или уменьшить эффект анимации. Для облегчения настройки выездным персоналом эта страница поддерживает указание параметров производительности с помощью параметров URL. Например:
/exhibition?pointCount=300
Параметр pointCount используется для изменения количества световых точек, по умолчанию 600. Кроме того, есть и другие параметры, которые не будут перечислены один за другим. Наконец, давайте посмотрим на эффект вместе!