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

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

  • Страница 1 из 1
  • 1
Вид новостей - шаблон социальная сеть V 1.2 uCoz
Дата: Пятница, 02.01.2026, 01:26 | Сообщение # 1 | | Написал: Узнаваемый
Автор темы
Мурчанн не в сети
        Сообщений:162
         Регистрация:20.10.2016

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

Сложность заключается в нескольких моментах:

1. Система рейтингов uCoz не предусматривает мгновенное обновление

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

Необходимость учёта повторного голосования

на uCoz нет встроенного механизма, который бы блокировал повторное нажатие на лайк. Чтобы пользователь не мог кликать несколько раз, пришлось использовать localStorage для хранения ID уже проголосовавших постов.



Отправка данных на сервер

Даже после того как пользователь нажал сердечко, рейтинг должен обновиться и на сервере uCoz.
Для этого используется AJAX-запрос через внутреннюю функцию _uPostForm, который имитирует стандартное действие рейтинга движка.

Адаптация под дизайн социальной сети

Кнопка «лайк» должна плавно менять цвет и масштабироваться при наведении или клике. С помощью CSS добавлены эффекты: увеличение, смена цвета фона, тень, чтобы визуально имитировать интерактивное сердечко.

Как работает скрипт лайка на примере кода:

На странице создаётся блок лайка с сердечком и счётчиком:

Код
<div class="vk-like" data-entryid="$ID$">
  <span class="likeHeart">❤</span>
  <span class="uLikeCount">$RATED$</span>
</div>


JavaScript перебирает все блоки .vk-like и проверяет localStorage, голосовал ли пользователь ранее:

Код
let votedPosts = JSON.parse(localStorage.getItem('votedPosts') || '[]');


Если пользователь уже голосовал, сердечко окрашивается в красный цвет (.liked).

1. При клике на сердечко:

2. проверяется, был ли уже голос (if (heart.classList.contains('liked')) return;)

3. если нет, сердечко окрашивается, увеличивается счётчик на странице

4. обновляется localStorage, чтобы помнить о голосе пользователя

отправляется AJAX-запрос на сервер uCoz для сохранения рейтинга

Код
_uPostForm('', {
  type: 'POST',
  url: '/publ',
  data: {
    a: 65,
    id: entryID,
    mark: 5,
    mod: 'publ',
    ajax: '2'
  }
});


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

Почему сложно сделать лайк на uCoz с нуля:

1. Отсутствие API для динамических голосований – нужно использовать внутренние POST-запросы.

2. Нет клиентской валидации повторного голосования – необходимо самим хранить информацию о том, кто уже голосовал.

3. Обновление визуальной части – сердечко должно менять состояние без перезагрузки страницы.

4. Совмещение с существующей системой рейтингов – счётчик на сервере должен совпадать с тем, что видит пользователь на фронтенде.

В итоге, чтобы получить привычный эффект лайка как в соцсетях, пришлось комбинировать CSS-анимацию, localStorage и AJAX-запрос к uCoz.

Особая деталь - буква X:

Для красоты и ещё одного способа визуализировать рейтинг была добавлена буква X, очень похожая на бренд соцсети Илона Маска. Она заполняется цветами в зависимости от количества лайков, создавая эффект прогресс-бара и делая визуал рейтинга более стильным и узнаваемым.

Чтобы получить привычный эффект лайка как в соцсетях, пришлось сочетать CSS-анимацию, localStorage и AJAX-запрос к uCoz, а буква X добавила интерактивности и красоты, делая рейтинг не только функциональным, но и визуально привлекательным.

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

Код
<!-- ЛЕНТА НОВОСТЕЙ -->
<style>
.vk-modern-feed{
    background:#f1f2f6;
    font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Arial,sans-serif;
}

/* POST */
.vk-modern-post{
    background:#fff;
    border-radius:12px;
    box-shadow:0 1px 3px rgba(0,0,0,.08);
    margin-bottom:14px;
    padding:12px;
}

/* HEADER */
.vk-modern-header{
    display:flex;
    align-items:center;
    position:relative;
}

.vk-modern-avatar img{
    width:42px;
    height:42px;
    border-radius:50%;
    display:block;
}

.vk-modern-author{
    margin-left:10px;
}

.vk-modern-name a{
    color:#2a5885;
    font-weight:600;
    text-decoration:none;
}
.vk-modern-name a:hover{
    text-decoration:underline;
}

.vk-modern-time{
    font-size:12px;
    color:#818c99;
}

/* MODER PANEL */
.entry-moder-container{
    position:absolute;
    top:0;
    right:0;
}

/* TEXT */
.vk-modern-text{
    margin:10px 0;
    line-height:1.45;
    font-size:14px;
}

/* IMAGE */
.vk-modern-attach img{
    width:100%;
    height:auto;
    display:block;
    border-radius:10px;
}

/* ACTIONS */
.vk-modern-actions{
    display:flex;
    justify-content:space-between;
    align-items:center;
    margin-top:10px;
    border-top:1px solid #e5e7eb;
    padding-top:8px;
}

.vk-actions-left{
    display:flex;
    gap:18px;
    font-size:14px;
}

.vk-action{
    display:flex;
    align-items:center;
    gap:6px;
    cursor:pointer;
    color:#626d7a;
}

.vk-action svg{
    width:20px;
    height:20px;
    fill:none;
    stroke:currentColor;
    stroke-width:2;
}

.vk-action:hover{
    color:#2a5885;
}

/* LIKE */
.vk-like-btn{
    font-size:20px;
    cursor:pointer;
    user-select:none;
}

.vk-like-count{
    font-size:14px;
    color:#626d7a;
}

.vk-actions-right{
    color:#626d7a;
    cursor:pointer;
    text-decoration:none;
}

.vk-modern-text img,
.vk-modern-attach img{
    max-width:100% !important;
    width:100% !important;
    height:auto !important;
    float:none !important;
    display:block !important;
    margin:8px 0 !important;
}

/* счётчик */
.vk-like span,
.vk-like b{
    font-size:18px;

    margin-left:-2px;
}

/* ховер */
.vk-like a:hover{
    opacity:.8;
}

.vk-actions-right {
  font-size: 18px;
  color: #626d7a;
  text-decoration: none;
  padding: 4px 8px;
  border-radius: 6px;
  transition: background .2s, color .2s;
}

.vk-actions-right:hover {
  background: #f1f2f6;
  color: #2a5885;
}

/* Контейнер лайка */
.vk-like {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

/* Само сердечко */
.likeHeart {
  cursor: pointer;
  font-size: 4px;          /* размер сердечка */
  color: red;               /* цвет сердечка по умолчанию */
  background: white;        /* фон */
  border-radius: 50%;       /* круг */
  padding: 0px 3px;         /* внутренние отступы */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: all 0.3s ease; /* плавные изменения */
  user-select: none;
}

/* Ховер эффект */
.likeHeart:hover {
  transform: scale(1.4);   /* немного увеличиваем сердечко при наведении */
}

/* Состояние "лайк поставлен" */
.likeHeart.liked {
  background: red;          /* фон после лайка */
  color: white;             /* цвет сердечка после лайка */
  cursor: default;          /* нельзя кликать повторно */
  transform: scale(1.3);    /* эффект увеличения при клике */
  box-shadow: 0 0 2px rgba(255, 0, 0, 0.6); /* лёгкая тень */
}

/* Счётчик лайков */
.uLikeCount {
  color: #f44336;
  font-size: 10px;
  margin-left: 0px;
  user-select: none;
}

/* Убираем подчёркивание у ссылок vk-action */
.vk-action {
  text-decoration: none;
}

/* Контейнер рейтинга */
.rating-shift {
  margin-left: 12px;   /* ← ВОТ ТУТ двигаешь вправо */
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 13px;
  color: #626d7a;
}

/* Заголовок "Рейтинг" */
.rating-shift .ed-title {
  font-weight: 500;
  color: #818c99;
}

/* Числа рейтинга */
.rating-shift .ed-value {
  font-weight: 600;
  color: #2a5885;
}

/* Лайк */
.likeHeart {
  cursor: pointer;
  font-size: 14px;
  color: red;
  transition: all 0.3s;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-right: 6px;
}

.likeHeart.liked {
  color: white;
  background: red;
  border-radius: 50%;
  cursor: default;
}

/* Звёзды рейтинга */
.star-rating {
  display: inline-flex;
  align-items: center;
  margin-left: 10px;
  font-size: 0;
}

.star-rating .stars {
  --star-size: 20px;
  --star-color: #f2b40a;
  --star-background: #ff6011;
  --stars-total: 3;
  display: inline-block;
  position: relative;
  font-size: var(--star-size);
  width: calc(var(--star-size) * var(--stars-total));
  height: var(--star-size);
  background: linear-gradient(
    to right,
    var(--star-color) 10%,
    var(--star-color) calc(var(--rating) / var(--stars-total) * 100%),
    var(--star-background) calc(var(--rating) / var(--stars-total) * 100%),
    var(--star-background) 100%
  );
  -webkit-clip-path: polygon(
    10% 0%, 40% 0%, 50% 30%, 60% 0%, 90% 0%, 65% 45%, 75% 80%, 50% 60%, 25% 80%, 35% 45%
  );
  clip-path: polygon(
    10% 0%, 40% 0%, 50% 30%, 60% 0%, 90% 0%, 65% 45%, 75% 80%, 50% 60%, 25% 80%, 35% 45%
  );
}

.star-rating .rated-count {
  font-size: 14px;
  color: #626d7a;
  margin-left: 0px;
}

/* Контейнер звёзд */
.stars {
  display: inline-block;
  font-size: 16px;
  color: #ddd; /* серые звёзды по умолчанию */
  position: relative;
  width: 120px; /* ширина для 5 звёзд по 18px каждая */
  height: 16px;
}

.stars::before {
  content: "★★★★★"; /* 5 звёзд */
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  overflow: hidden;
  color: #ffcc00; /* цвет закрашенных звёзд */
}

</style>

<div class="vk-modern-feed">

<div class="vk-modern-post">

    <!-- HEADER -->
    <div class="vk-modern-header">

  <div class="vk-modern-avatar">
   <?if($AVATAR_URL$)?>
    <img src="$AVATAR_URL$" alt="$USERNAME$">
   <?else?>
    <img src="/.s/img/avatar.png">
   <?endif?>
  </div>

  <div class="vk-modern-author">
   <div class="vk-modern-name">
    <a href="$PROFILE_URL$">$USERNAME$</a>
   </div>
   <div class="vk-modern-time" title="$TIME$">$DATE$</div>
  </div>

  <?if($MODER_PANEL$)?>
  <div class="entry-moder-container">$MODER_PANEL$</div>
  <?endif?>

    </div>

    <!-- TEXT -->
    <?if($MESSAGE$)?>
    <div class="vk-modern-text">
  $MESSAGE$
    </div>
    <?endif?>

    <!-- IMAGE -->
    <?if($COVER_IMAGE$)?>
    <div class="vk-modern-attach">
  <picture>
   <source srcset="$COVER_SMALL_URL$" media="(min-width:769px)">
   <img src="$COVER_URL$" alt="$TITLE$" loading="lazy">
  </picture>
    </div>
    <?endif?>

    <!-- ACTIONS -->
    <div class="vk-modern-actions">

  <div class="vk-actions-left">

<div class="vk-like" data-entryid="$ID$">
  <span class="likeHeart" title="Поставить лайк">❤</span>
  <span class="uLikeCount">$RATED$</span>
</div>

<script>
(function() {
  // получаем все блоки сердечек на странице
  const likeBlocks = document.querySelectorAll('.vk-like');

  // проверка/инициализация localStorage
  let votedPosts = JSON.parse(localStorage.getItem('votedPosts') || '[]');

  likeBlocks.forEach(block => {
    const entryID = parseInt(block.dataset.entryid);
    const heart = block.querySelector('.likeHeart');
    const likeCount = block.querySelector('.uLikeCount');

    // если уже голосовал — сразу ставим красное сердечко
    if (votedPosts.includes(entryID)) {
      heart.classList.add('liked');
    }

    heart.addEventListener('click', function() {
      if (heart.classList.contains('liked')) return; // уже голосовал

      heart.classList.add('liked');

      // обновляем localStorage
      votedPosts.push(entryID);
      localStorage.setItem('votedPosts', JSON.stringify(votedPosts));

      // обновляем счетчик лайков на странице
      if (likeCount) {
        likeCount.textContent = parseInt(likeCount.textContent || '0') + 1;
      }

      // отправка реального голоса на uCoz
      _uPostForm('', {
        type: 'POST',
        url: '/publ',
        data: {
          a: 65,       // действие рейтинга
          id: entryID, // ID статьи
          mark: 5,     // плюс 1
          mod: 'publ',
          ajax: '2'
        }
      });
    });
  });
})();
</script>

<!-- COMMENTS -->
<?if($COMMENTS_URL$)?>
<a class="vk-action" href="$COMMENTS_URL$">
<svg viewBox="0 0 24 24">
<path d="M21 6h-18v10h4v4l4-4h10z"/>
</svg>
<span>$COMMENTS_NUM$</span>
</a>
<?endif?>

<!-- READS -->
<div class="vk-action">
<svg viewBox="0 0 24 24">
<path d="M1 12s4-7 11-7 11 7 11 7-4 7-11 7S1 12 1 12z"/>
<circle cx="12" cy="12" r="3"/>
</svg>

<span>$READS$</span>

<?if($RATING$)?><span class="ed-sep"></span>
<span class="e-rating rating-shift">
  <span class="ed-title"><!--<s3119>-->Рейтинг<!--</s>-->:</span>
  <span class="ed-value">
    <span id="entRating$ID$">$RATING$</span>/<span id="entRated$ID$">$RATED$</span>
  </span>
</span>
<?endif?>

  <!-- Звёзды рейтинга -->
  <div class="star-rating">
    <span class="stars" style="--rating: $RATING$;"></span>
    <span class="rated-count">($RATED$)</span>
  </div>

<?if($RATING$)?>
<span class="ed-sep"> </span>
<span class="e-rating">

  <span class="ed-value">
    <span class="stars" data-rating="$RATING$"></span>

  </span>
</span>
<?endif?>

<script>
document.querySelectorAll('.stars').forEach(function(starElem){
    const rating = parseFloat(starElem.dataset.rating) || 0;
    const percent = Math.min(Math.max(rating / 5 * 100, 0), 100); // процент заполнения
    starElem.style.setProperty('--rating-percent', percent + '%');

    // Устанавливаем ширину закрашенной части через inline стиль ::before
    const style = document.createElement('style');
    style.innerHTML = `
      .stars[data-rating="${rating}"]::before {
        width: ${percent}%;
        overflow: hidden;
      }
    `;
    document.head.appendChild(style);
});
</script>

</div>
</div>

<a class="vk-actions-right" href="$ENTRY_URL$">📄</a>

</div>

</div>
</div>



Мурчанн

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