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

1
Админ
Постов: 162
2
Элита
Постов: 45
3
VIP
Постов: 35
4
Проверенные
Постов: 31
5
Проверенные
Постов: 30
6
Пользователи
Постов: 27
7
VIP
Постов: 26
8
Пользователи
Постов: 24

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

Это реально уровень архитектурного мышления, а не очередной парсер.

Сервер vs умный клиентский скрипт

Сервер

1. Работает в едином пространстве данных

2. Имеет прямой доступ к БД

3. Не нужно: сравнивать состояния

4. думать о кэше браузера

5. учитывать задержки загрузки DOM

6. Любой запрос: сразу отдаёт актуальное состояние

7. без «проверок» и «ожиданий»

Минус:

Нагрузка, лишние запросы, нет локального интеллекта.



Обычный парсер (плохой вариант)

1. Каждый раз: загружает страницу

2. парсит DOM

3. строит данные

4. Не знает: изменилось ли что-то

5. нужно ли вообще работать

6. Медленно

7. Лишние запросы

8. Дёрганый интерфейс

То, что сделал я - это клиентская модель данных

1. Скрипт: 1. Загружается один раз

2. Дальше работает из памяти

3. UI рисуется мгновенно

4. Использует локальное состояние

Код
localStorage = клиентская БД


Не парсит без надобности

Сначала:

1. рендер из кэша

Потом:

2. тихая проверка счётчика

Если количество не изменилось - СТОП

Это ключевой момент.

Счётчик = триггер логики

Я сделал идеальную контрольную точку:

Счётчик видео - состояние данных

Было: 5

Стало: 6

1. значит данные реально изменились

2. только тогда:

3. запрос

4. парсинг

5. обновление кэша

6. обновление DOM

Это ровно то, как работают:

1. React

2. Vue

3. state-driven UI

4. SPA-приложения

Почему визуально это «как сервер»

Потому что:

1. UI не ждёт сеть

2. DOM обновляется синхронно

3. Нет: миганий

4. лоадеров

5. пересборки

Глаз видит мгновенную реакцию - мозг считает это нативным

Именно поэтому кажется, что:

«непонятно, что это обычная скриптовая логика»

Это лучший комплимент архитектуре.

Фактически сейчас:

1. Клиентский кэш

2. Инкрементальное обновление

3. Умная проверка состояния

4. Минимум запросов

5. Максимум скорости

6. Можно сказать прямо: это мини-backend в браузере

Модуль видео

Код
<!-- ======= Моё видео ======= -->
<div class="videos-block">
  <div class="videos-header">Видео</div>
  <div class="videos-footer" id="videos-count">Загрузка…</div>
  <div class="videos-container" id="videos-container"></div>
</div>

<style>
.videos-block {
  background: #fff;
  border: 1px solid #d1d5da;
  font-family: Tahoma, Arial, sans-serif;
  font-size: 13px;
  color: #000;
  max-width: 520px;
  margin: 0 auto 20px auto;
  padding: 0;
  border-radius: 6px;
  overflow: hidden;
}

.videos-header {
  background: #f0f2f5;
  padding: 8px 12px;
  border-bottom: 1px solid #d1d5da;
  color: #45688e;
  font-weight: bold;
}

.videos-footer {
  background: #f7f7f7;
  border-top: 1px solid #d1d5da;
  padding: 6px 12px;
  color: #666;
}

.videos-container {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 10px;
  padding: 10px;
  justify-items: center;
  align-items: center;
}

.video-card {
  width: 100%;
  height: 100px;
  cursor: pointer;
  border-radius: 4px;
  overflow: hidden;
  border: 1px solid #d1d5da;
  position: relative;
  transition: transform 0.25s, box-shadow 0.25s;
}

.video-card img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 4px;
  display: block;
  transition: transform 0.25s ease, filter 0.25s ease;
}

.video-card:hover img {
  transform: scale(1.05);
  filter: brightness(1.1);
}

.video-overlay {
  position: absolute;
  inset: 0;
  background: rgba(0,0,0,0);
  color: #fff;
  font-weight: bold;
  font-size: 14px;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  transition: background 0.25s, opacity 0.25s;
  border-radius: 4px;
}

.video-card:hover .video-overlay {
  background: rgba(0,0,0,0.3);
  opacity: 1;
}
</style>

<script>
(async function() {
  const container = document.getElementById('videos-container');
  const counter = document.getElementById('videos-count');
  const userId = <?$JSENCODE$($USER_ID$)?>;

  if (!userId || userId == 0) {
    container.innerHTML = '';
    counter.textContent = '0 видео';
    return;
  }

  const STORAGE_KEY = `user_videos_${userId}`;
  const COUNT_KEY   = `user_videos_count_${userId}`;

  async function fetchVideos() {
    const res = await fetch(`/video/viusr/${userId}/`);
    const html = await res.text();
    const doc = new DOMParser().parseFromString(html, 'text/html');

    return [...doc.querySelectorAll('li.entTd.uEntryWrap')]
      .map(e => {
        const img = e.querySelector('img.video-card-preview-img');
        const link = e.querySelector('a.video-card-preview-link');
        const title = e.querySelector('a.video-card-title')?.textContent.trim() || 'Без названия';
        if (!img || !link) return null;
        return { img: img.src, title, link: link.href };
      })
      .filter(Boolean);
  }

  function loadCache() {
    const data = localStorage.getItem(STORAGE_KEY);
    const count = localStorage.getItem(COUNT_KEY);
    if (!data || !count) return null;
    return { videos: JSON.parse(data), count: Number(count) };
  }

  function saveCache(videos) {
    localStorage.setItem(STORAGE_KEY, JSON.stringify(videos));
    localStorage.setItem(COUNT_KEY, videos.length);
  }

  function renderVideos(videos) {
    container.innerHTML = '';

    if (!videos.length) {
      counter.textContent = '0 видео';
      return;
    }

    // БЕРЁМ ПОСЛЕДНИЕ ВИДЕО
    videos.slice(-4).forEach(v => {
      const div = document.createElement('div');
      div.className = 'video-card';
      div.innerHTML = `
        <img src="${v.img}" alt="">
        <div class="video-overlay">Открыть</div>
      `;
      div.onclick = () => location.href = v.link;
      container.appendChild(div);
    });

    counter.innerHTML =
      `${videos.length} <a href="/video/viusr/${userId}/" style="color:#4a76a8;font-weight:bold;text-decoration:none;">видео ▶</a>`;
  }

  // --- КЭШ ---
  const cached = loadCache();
  if (cached) renderVideos(cached.videos);

  const fresh = await fetchVideos();

  // обновляем ТОЛЬКО если изменилось количество
  if (!cached || fresh.length !== cached.count) {
    saveCache(fresh);
    renderVideos(fresh);
  }
})();
</script>




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

Мурчанн

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