Список пользователей

1
Админ
Постов: 218
2
VIP
Постов: 72
3
Элита
Постов: 50
4
Проверенные
Постов: 35
5
VIP
Постов: 35
6
Проверенные
Постов: 32
7
Пользователи
Постов: 31
8
Проверенные
Постов: 29

  • Страница 1 из 1
  • 1
Модуль ВК «Блок друзей» для Ucoz v 9.1
Дата: Суббота, Сегодня, 02:55 | Сообщение # 1 | | Написал: Узнаваемый
Автор темы
Мурчанн не в сети
        Сообщений:218
         Регистрация:20.10.2016

Давно не обновлял блок друзей , он как-то совсем выпал из внимания.

Главная проблема, которая меня всё это время беспокоила, это постоянные задержки, подёргивания и подгрузка элементов. Постоянные обращения к серверу , не самое лучшее решение.

Гораздо эффективнее заранее загружать данные и хранить их в кэше, а затем незаметно проверять обновления в фоне. Если какие-то данные изменяются, обновление происходит мгновенно и без визуальных задержек.

В итоге получилась полностью переработанная версия: изменена логика работы, улучшена производительность и добавлены новые функции.

Перед тем как перейти к обновлениям, стоит немного вспомнить старые версии этого модуля друзей.

Ранее он работал достаточно просто, но со временем начал терять актуальность

1. модуль ВК «Друзья» для Ucoz v 6.0

Итак, что было сделано за последнее время.

Пустой блок друзей стал более информативным: добавлена иконка и описание, чтобы при отсутствии друзей пользователь сразу понимал ситуацию. Теперь отображается сообщение о том, что друзей нет и их можно добавить.

Также добавлена кнопка «Найти друзей». При нажатии она открывает список пользователей. В дальнейшем планируется полноценная страница со списком пользователей, аналогичная тому, как это реализовано во ВКонтакте, где также будет возможность добавлять друзей.



В целом задумка достаточно масштабная. Для её реализации потребуется немало времени, особенно учитывая, что не всё получается идеально с первого раза. По ходу разработки приходится постоянно улучшать и дорабатывать уже сделанные части, что тоже влияет на сроки.

Следующие изменения касаются всплывающего окна. Были немного переработаны CSS-стили и изменено расположение некоторых элементов для более удобного отображения.

Также добавлена функция удаления друга из списка. Это действительно важная функция, однако для её корректной работы потребуется повышение прав пользователей, чтобы они могли удалять свои записи в каталоге файлов. Именно там наш скрипт и создаёт записи друзей, отправляя соответствующие данные в виде отчётности.

Кроме того, добавлена дополнительная плашка внизу «Показать всех друзей →». Она предназначена для тех случаев, когда пользователь не сразу догадывается, что достаточно нажать на счётчик друзей, чтобы открыть всплывающее окно.

Остались, конечно, ещё нерешённые проблемы. Например, хотелось бы добиться такого же поведения, как в модуле фотографий — чтобы блок друзей отображался мгновенно, без морганий и задержек.

Почти всё уже кэшируется в браузере, данные сохраняются, и логика переписывалась множество раз, но достичь идеального результата пока не удалось. Возможно, со временем получится улучшить эту систему, но на данный момент она остаётся в текущем виде.

Также пока не получается нормально упаковать скрипт в минифицированный JS. При сжатии часть заложенного функционала почему-то теряется, что выглядит как довольно странная аномалия и требует дополнительного изучения.



Исходной код

Код
<!-- MINI BLOCK ДРУЗЬЯ -->
<div class="vk-old-block">
<div class="vk-old-header">Друзья</div>
<div class="vk-old-footer" id="friends-count">0 друзей</div>

<div class="vk-old-content">
<div class="vk-friends"></div>
</div>

<div class="vk-old-footer" id="friends-footer" title="Показать всех друзей">
Показать всех друзей →
</div>
</div>

<link rel="stylesheet" href="/css/friends.css" media="all">

<div id="uc-online-list" style="display:none;">
$ONLINE_USERS_LIST$
</div>

<script>
(function(){

const USER_ID = window.UCOZ_DATA?.userId || "0";
if(USER_ID === "0") return;

const $container = $('.vk-friends');
const $counter = $('#friends-count');
const $footer = $('#friends-footer');

const DEFAULT_AVA = '/.s/src/profile/img/profile_photo_thumbnail.png';
const LS_FRIENDS = 'friends_' + USER_ID;

let allFriends = [];

/* =========================
РЕНДЕР МИНИ-БЛОКА
========================= */
function renderMini(friends){
const onlineHtml = $('#uc-online-list').text().toLowerCase();

if(!friends || friends.length === 0){
const empty = document.createElement('div');
empty.className = 'vk-empty-wrap';

empty.innerHTML = `
<div class="vk-empty-icon">
<svg width="58" height="58" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M16 11c1.66 0 3-1.34 3-3S17.66 5 16 5s-3 1.34-3 3 1.34 3 3 3zM8 11c1.66 0 3-1.34 3-3S9.66 5 8 5 5 6.34 5 8s1.34 3 3 3z" fill="#99a2ad"/>
<path d="M8 13c-2.67 0-8 1.34-8 4v2h10v-2c0-1.2.6-2.3 1.6-3.2C10.3 13.3 9 13 8 13zm8 0c-.9 0-2.3.2-3.6.8 1 .9 1.6 2 1.6 3.2v2h10v-2c0-2.66-5.33-4-8-4z" fill="#99a2ad"/>
</svg>
</div>
<div class="vk-empty-title">У вас нет друзей</div>
<div class="vk-empty-sub">Добавляйте людей, чтобы видеть их здесь</div>

<div class="vk-empty-action">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round">
<line x1="12" y1="5" x2="12" y2="19"></line>
<line x1="5" y1="12" x2="19" y2="12"></line>
</svg>
Добавить друзей
</div>
`;

empty.querySelector('.vk-empty-action').onclick = () => {
location.href = '/index/15-2';
};

$container[0].replaceChildren(empty);
$counter.html('0 друзей');
return;
}

/* Обычный список друзей */
$container.empty();
friends.slice(0, 6).forEach(f => {
const isOnline = onlineHtml.includes(f.nick.toLowerCase());
const statusDot = `<span class="statusDot ${isOnline ? 'onlineDot' : 'offlineDot'}"></span>`;

const card = $(`
<div class="vk-friend" title="${f.nick}">
<img src="${f.ava}">
<span>${f.nick}</span>
${statusDot}
</div>
`);

card.on('click', () => location.href = f.profile);
$container.append(card);
});

$counter.html(`${friends.length} друзей`);
}

/* =========================
POPUP (стрелка + удаление)
========================= */
function showPopup(){
if(!allFriends.length) return;

const overlay = $('<div class="vk-ui-overlay"></div>');

const popup = $(`
<div class="vk-ui-popup">
  <div class="vk-ui-header">
   <div class="vk-ui-title">
    Друзья <span class="vk-ui-title-count">${allFriends.length}</span>
   </div>

   <div class="vk-ui-search">
    <input type="text" placeholder="Поиск друзей" id="friend-search">
   </div>

   <button class="vk-ui-close" title="Закрыть">×</button>
  </div>

  <div class="vk-ui-list"></div>
</div>
`);

const list = popup.find('.vk-ui-list');
const onlineHtml = $('#uc-online-list').text().toLowerCase();

function renderList(filter = ''){
  list.empty();

  allFriends
   .filter(f => f.nick.toLowerCase().includes(filter.toLowerCase()))
   .forEach(f => {

    let badge = 'Без статуса', cls = 'nostatus', letter = '';
    const g = f.group.toLowerCase();

    if(g.includes('кумир')) { badge='Кумир'; cls='idol'; letter='К'; }
    else if(g.includes('друг')) { badge='Друг'; cls='friend'; letter='Д'; }
    else if(g.includes('сем')) { badge='Семья'; cls='family'; letter='С'; }
    else if(g.includes('знаком')) { badge='Знакомый'; cls='acquaintance'; letter='З'; }
    else if(g.includes('прият')) { badge='Приятель'; cls='buddy'; letter='П'; }

    const isOnline = onlineHtml.includes(f.nick.toLowerCase());

    const row = $(`
     <div class="vk-ui-row ${cls}">

      <!-- аватар -->
      <div class="vk-ui-ava">
       <img src="${f.ava}">
       ${letter ? `<span class="vk-ui-letter ${cls}">${letter}</span>` : ''}
       <span class="statusDot ${isOnline ? 'onlineDot' : 'offlineDot'}"></span>
      </div>

      <!-- инфо -->
      <div class="vk-ui-info">
       <div class="vk-ui-name">${f.nick}</div>
       <div class="vk-ui-badge ${cls}">${badge}</div>
      </div>

      <!-- правая часть -->
      <div class="vk-ui-actions">

       <!-- КОРЗИНА (удаление) -->
       <button class="vk-del-btn" title="Удалить">✕</button>

       <!-- СТРЕЛКА (переход) -->
       <div class="vk-ui-arrow">›</div>

      </div>

     </div>
    `);

    /* =========================
       ПЕРЕХОД В ПРОФИЛЬ (стрелка + строка)
    ========================= */
    row.on('click', () => location.href = f.profile);

    /* =========================
       УДАЛЕНИЕ (крестик)
    ========================= */
    row.find('.vk-del-btn').on('click', function(e){
     e.stopPropagation();

     if(!f.del){
      alert('Ошибка: нет ссылки удаления');
      return;
     }

     if(!confirm(`Удалить ${f.nick} из друзей?`)) return;

     const btn = $(this);
     btn.text('...');

     $.get(f.del)
      .done(() => {

       allFriends = allFriends.filter(x => x.nick !== f.nick);

       row.fadeOut(200, () => row.remove());

       renderMini(allFriends);

       $counter.html(`${allFriends.length} друзей`);

       localStorage.setItem(LS_FRIENDS, JSON.stringify(allFriends));

      })
      .fail(() => {
       alert('Ошибка удаления');
       btn.text('✕');
      });
    });

    list.append(row);
   });
}

renderList();

popup.find('#friend-search').on('input', function(){
  renderList($(this).val());
});

popup.find('.vk-ui-close').on('click', () => overlay.remove());
overlay.on('click', e => {
  if(e.target === overlay[0]) overlay.remove();
});

overlay.append(popup);
$('body').append(overlay);
}

/* =========================
ЗАГРУЗКА ДАННЫХ С СЕРВЕРА
========================= */
function loadFriends(){
$.get(`/blog/0-0-1-0-17-${USER_ID}`, html => {

const $tmp = $('<div>').html(html);
const updated = [];

$tmp.find('.friend').each(function(){
const $el = $(this);

let group = $el.find('.gr').text().trim() || 'Без статуса';
const g = group.toLowerCase();

if(!['друг','кумир','семья','знакомый','приятель'].some(k => g.includes(k))) {
group = 'Приятель';
}

// ВАЖНО: добавляем ссылку удаления
const delLink = $el.find('.del').text().trim();

updated.push({
nick: $el.find('.nick').text().trim(),
ava: $el.find('.ava').text().trim() || DEFAULT_AVA,
profile: $el.find('.url').text().trim(),
group: group,
del: delLink || null // ← теперь у каждого друга есть ссылка удаления
});
});

// сравнение теперь учитывает del
const changed = JSON.stringify(updated) !== JSON.stringify(allFriends);

if(changed){
allFriends = updated;

// сохраняем в кеш
localStorage.setItem(LS_FRIENDS, JSON.stringify(allFriends));

// обновляем UI
renderMini(allFriends);

console.log('Друзья обновлены:', allFriends.length);
}
})
.fail(() => {
console.warn('Не удалось загрузить список друзей');
});
}

/* =========================
ИНИЦИАЛИЗАЦИЯ
========================= */
$counter.add($footer)
.css('cursor','pointer')
.attr('title','Показать всех друзей')
.on('click', showPopup);

// Показываем кэш сразу
try {
const cached = JSON.parse(localStorage.getItem(LS_FRIENDS) || "[]");
if(cached.length){
allFriends = cached;
renderMini(allFriends);
} else {
renderMini([]);
}
} catch(e){
renderMini([]);
}

// Тихая загрузка актуальных данных
setTimeout(loadFriends, 800); // небольшая задержка, чтобы страница успела загрузиться

// Дополнительно обновляем каждые 30 секунд (на случай удаления/добавления друга)
setInterval(loadFriends, 30000);

})();
</script>


Мурчанн

Признаюсь, не знаю почему, но глядя на звезды мне всегда хочется мечтать.
  • Страница 1 из 1
  • 1
Поиск: