/** * Zibll前端剧集视频扩展 - 前端脚本 * Version: 1.0.0 */ (function($, window) { 'use strict'; // 等待DOM加载完成 $(document).ready(function() { // 稍微延迟初始化,确保主题JS已执行 setTimeout(function() { ZFVEManager.init(); }, 500); }); /** * 剧集视频管理器 */ var ZFVEManager = { // 配置 config: { episodeCounter: 1, // 从第1集开始计数 maxEpisodes: 88, // 最大剧集数 }, // DOM元素缓存 elements: {}, // 媒体选择器实例 mediaSelector: null, // 当前操作的剧集输入框 currentEpisodeInput: null, /** * 初始化 */ init: function() { // 检查是否在投稿页面(通过标题输入框判断) if (!$('.newposts-title').length && !$('.featured-edit').length) { return; } // 插入UI到页面 this.insertUI(); this.cacheElements(); this.bindEvents(); this.checkVideoStatus(); this.loadExistingData(); }, /** * 插入UI到页面 */ insertUI: function() { var $template = $('#zfve-ui-template'); if (!$template.length) { return; } // 查找标题输入框 var $titleBox = $('.newposts-title'); if (!$titleBox.length) { return; } // 从模板中获取内容类型选择器(始终显示) var $contentType = $template.find('.zfve-content-type').clone(); // 从模板中获取剧集视频设置(仅视频教程显示) var $videoEpisodes = $template.find('.zfve-video-episodes-wrapper').clone(); // 从模板中获取资源介绍(始终显示) var $description = $template.find('.zfve-resource-description').clone(); // 从模板中获取文件格式管理(仅资源类型显示) var $fileFormats = $template.find('.zfve-file-formats').clone(); // 从模板中获取模型属性(仅资源类型显示) var $modelAttributes = $template.find('.zfve-model-attributes').clone(); // 从模板中获取引擎属性(仅引擎格式显示) var $engineAttributes = $template.find('.zfve-engine-attributes').clone(); // 从模板中获取资源图片(始终显示) var $resourceImages = $template.find('.zfve-resource-images').clone(); // 插入到标题输入框之后,按正确顺序排列 $titleBox.after($contentType); $contentType.after($videoEpisodes); $videoEpisodes.after($description); $description.after($fileFormats); $fileFormats.after($modelAttributes); $modelAttributes.after($engineAttributes); $engineAttributes.after($resourceImages); // 移除模板(避免重复ID) $template.remove(); }, /** * 缓存DOM元素 */ cacheElements: function() { this.elements = { wrapper: $('.zfve-video-episodes-wrapper'), addBtn: $('#zfve_add_episode'), episodesList: $('#zfve_episodes_list') }; }, /** * 绑定事件 */ bindEvents: function() { var self = this; // 添加剧集按钮 this.elements.addBtn.on('click', function(e) { e.preventDefault(); self.addEpisode(); }); // 删除剧集(使用事件委托) this.elements.episodesList.on('click', '.zfve-remove-episode', function(e) { e.preventDefault(); self.removeEpisode($(this)); }); // 上传视频按钮(使用事件委托) this.elements.episodesList.on('click', '.zfve-upload-video-btn', function(e) { e.preventDefault(); self.openVideoSelector($(this)); }); // 监听付费内容开关(子比主题的付费模块) this.initPayModuleListener(); // 实时同步资源介绍内容到原有编辑器 $('#post_content').on('input change', function() { self.syncContentToOriginalEditor(); }); // 拦截AJAX请求,确保图片数据被包含 if (typeof $.ajaxSetup === 'function') { var originalBeforeSend = $.ajaxSettings.beforeSend; $.ajaxSetup({ beforeSend: function(xhr, settings) { // 检查是否是表单提交的AJAX请求 if (settings.type === 'POST' && settings.data && typeof settings.data === 'string') { if (settings.data.indexOf('post_content') > -1 || settings.data.indexOf('posts_id') > -1) { // 合并图片到post_content if (typeof ZFVEImagePicker !== 'undefined' && ZFVEImagePicker.resourceImages.length > 0) { var descriptionText = $('#post_content').val() || ''; var imagesHtml = ''; ZFVEImagePicker.resourceImages.forEach(function(url) { imagesHtml += '\n\n资源图片'; }); var fullContent = descriptionText + imagesHtml; // 修改AJAX数据 var params = new URLSearchParams(settings.data); params.set('post_content', fullContent); settings.data = params.toString(); } } } if (originalBeforeSend) { return originalBeforeSend.apply(this, arguments); } } }); } // 表单提交前,更新隐藏的input值并验证 $('form.new-post-form').on('submit', function(e) { // 强制更新所有隐藏字段(确保最新数据被提交) if (typeof ZFVEFileFormats !== 'undefined' && ZFVEFileFormats.updateFormatsData) { ZFVEFileFormats.updateFormatsData(); } if (typeof ZFVEModelAttributes !== 'undefined' && ZFVEModelAttributes.saveAttributes) { ZFVEModelAttributes.saveAttributes(); } if (typeof ZFVEEngineAttributes !== 'undefined' && ZFVEEngineAttributes.saveAttributes) { ZFVEEngineAttributes.saveAttributes(); } // 验证资源文件格式 if (!self.validateFormats()) { e.preventDefault(); alert('错误:至少需要选择一个资源文件格式!'); return false; } // 将图片HTML直接合并到post_content中 if (typeof ZFVEImagePicker !== 'undefined' && ZFVEImagePicker.resourceImages.length > 0) { var descriptionText = $('#post_content').val() || ''; var imagesHtml = ''; ZFVEImagePicker.resourceImages.forEach(function(url) { imagesHtml += '\n\n资源图片'; }); var fullContent = descriptionText + imagesHtml; $('#post_content').val(fullContent); // 同时更新隐藏字段(兼容) ZFVEImagePicker.updateHiddenField(); } // 同步资源介绍到原有编辑器 self.syncContentToOriginalEditor(); self.updateHiddenInputs(); }); }, /** * 检查内容类型并显示/隐藏剧集设置 */ checkVideoStatus: function() { // 获取当前内容类型 var currentType = $('input[name="zfve_content_type"]:checked').val() || 'resource'; // 如果是视频教程类型,始终显示剧集设置(无论是否有视频封面) if (currentType === 'video') { this.elements.wrapper.slideDown(300); } else { // 如果是资源内容类型,隐藏剧集设置 this.elements.wrapper.slideUp(300); } }, /** * 初始化付费内容模块监听器 */ initPayModuleListener: function() { var self = this; // 子比主题常见的付费开关选择器 var payModuleSelectors = [ '#pay-module', // 付费模块开关 '[name="pay_module"]', // 付费模块name属性 '#posts_price', // 价格输入框 '[name="posts_price"]', // 价格name属性 '.pay-module-switch', // 付费模块switch类 '.posts-price-input', // 价格输入框类 'input[id*="pay"]', // ID包含pay的input 'input[name*="pay"]', // name包含pay的input 'input[id*="price"]', // ID包含price的input 'input[name*="price"]', // name包含price的input '.checkbox-wrapper input', // checkbox包装器中的input '.pay-setting input', // 付费设置中的input '.sidebar-tab-main input[type="checkbox"]' // 侧边栏checkbox ]; // 尝试找到付费开关 var $paySwitch = null; for (var i = 0; i < payModuleSelectors.length; i++) { $paySwitch = $(payModuleSelectors[i]); if ($paySwitch.length) { break; } } if (!$paySwitch || !$paySwitch.length) { // 延迟重试(付费模块可能延迟加载) setTimeout(function() { self.initPayModuleListener(); }, 3000); // 使用MutationObserver监听DOM变化 this.observePayModuleChanges(); return; } // 初始状态检查 this.updateEpisodePaymentStatus($paySwitch); // 监听开关变化(适配不同的输入类型) $paySwitch.on('change', function() { self.updateEpisodePaymentStatus($(this)); }); // 如果是价格输入框,也监听input事件 if ($paySwitch.is('input[type="text"], input[type="number"]')) { $paySwitch.on('input', function() { self.updateEpisodePaymentStatus($(this)); }); } // 如果是复选框,也监听click事件 if ($paySwitch.is('input[type="checkbox"]')) { $paySwitch.on('click', function() { setTimeout(function() { self.updateEpisodePaymentStatus($paySwitch); }, 100); }); } }, /** * 使用MutationObserver监听付费模块DOM变化 */ observePayModuleChanges: function() { var self = this; // 监听整个右侧边栏的变化 var sidebarSelectors = ['.sidebar-tab-main', '.post-edit-sidebar', '.edit-sidebar', '#side-sortables']; sidebarSelectors.forEach(function(selector) { var sidebar = document.querySelector(selector); if (sidebar) { var observer = new MutationObserver(function(mutations) { mutations.forEach(function(mutation) { if (mutation.addedNodes.length) { setTimeout(function() { self.initPayModuleListener(); }, 500); } }); }); observer.observe(sidebar, { childList: true, subtree: true }); } }); }, /** * 更新剧集付费状态 */ updateEpisodePaymentStatus: function($paySwitch) { var isPayEnabled = false; // 判断付费功能是否开启 if ($paySwitch.is('input[type="checkbox"]')) { // 复选框类型 isPayEnabled = $paySwitch.is(':checked'); } else if ($paySwitch.is('input[type="text"], input[type="number"]')) { // 价格输入框,如果有值则认为开启付费 var price = $paySwitch.val(); isPayEnabled = price && price !== '' && parseFloat(price) > 0; } else if ($paySwitch.is('select')) { // 下拉选择框 var value = $paySwitch.val(); isPayEnabled = value && value !== '' && value !== '0'; } // 更新所有剧集的观看权限选择器状态 var $episodePaidSelects = $('.zfve-episode-is-paid'); if (isPayEnabled) { $episodePaidSelects.prop('disabled', false); $('.zfve-episode-is-paid').siblings('.px12').html( '已开启付费功能,可以设置付费剧集' ); } else { $episodePaidSelects.prop('disabled', true).val('0'); $('.zfve-episode-is-paid').siblings('.px12').html( '请先在右边栏开启"付费内容"功能后,才能设置付费剧集' ); } }, /** * 添加剧集 */ addEpisode: function() { if (this.elements.episodesList.find('.zfve-episode-item').length >= this.config.maxEpisodes) { this.showNotice('最多可添加' + this.config.maxEpisodes + '集', 'warning'); return; } var episodeNumber = this.config.episodeCounter++; var episodeHtml = this.createEpisodeHtml(episodeNumber); this.elements.episodesList.append(episodeHtml); // 添加淡入动画 var $newEpisode = this.elements.episodesList.find('.zfve-episode-item').last(); $newEpisode.addClass('zfve-fade-in'); // 滚动到新添加的剧集 this.scrollToEpisode($newEpisode); // 同步新剧集的付费状态(解决添加剧集后开启付费功能,新剧集状态不更新的bug) this.syncNewEpisodePaymentStatus(); }, /** * 同步新添加剧集的付费状态 */ syncNewEpisodePaymentStatus: function() { var self = this; // 尝试找到付费开关(使用相同的选择器列表) var payModuleSelectors = [ '#pay-module', '[name="pay_module"]', '#posts_price', '[name="posts_price"]', '.pay-module-switch', '.posts-price-input', 'input[id*="pay"]', 'input[name*="pay"]', 'input[id*="price"]', 'input[name*="price"]' ]; var $paySwitch = null; for (var i = 0; i < payModuleSelectors.length; i++) { $paySwitch = $(payModuleSelectors[i]); if ($paySwitch.length) { // 找到了付费开关,更新状态 setTimeout(function() { self.updateEpisodePaymentStatus($paySwitch); }, 100); return; } } // 如果找不到付费开关,检查现有剧集的状态 var $existingSelects = $('.zfve-episode-is-paid').not(':last'); if ($existingSelects.length > 0) { var isEnabled = !$existingSelects.first().prop('disabled'); var $newSelect = $('.zfve-episode-is-paid').last(); if (isEnabled) { // 如果现有剧集是启用的,新剧集也启用 $newSelect.prop('disabled', false); $newSelect.siblings('.px12').html( '已开启付费功能,可以设置付费剧集' ); } else { // 如果现有剧集是禁用的,新剧集也禁用 $newSelect.prop('disabled', true).val('0'); $newSelect.siblings('.px12').html( '请先在右边栏开启"付费内容"功能后,才能设置付费剧集' ); } } }, /** * 创建剧集HTML */ createEpisodeHtml: function(episodeNumber, title, url, isPaid) { title = title || ''; url = url || ''; isPaid = (isPaid === undefined || isPaid === null) ? false : isPaid; // 默认免费 return '
' + '
' + '第' + episodeNumber + '集' + '' + '' + '' + '
' + '
' + '
' + '' + '' + '
' + '
' + '' + '
' + '' + '' + '
' + '
支持本地视频以及m3u8、mpd、flv等流媒体格式
' + '
' + '
' + '' + '' + '
' + '请先在右边栏开启"付费内容"功能后,才能设置付费剧集' + '
' + '
' + '
' + '
'; }, /** * 删除剧集 */ removeEpisode: function($btn) { var self = this; var $episode = $btn.closest('.zfve-episode-item'); // 添加确认提示 if (confirm('确定要删除这个剧集吗?')) { $episode.fadeOut(300, function() { $(this).remove(); self.updateEpisodeNumbers(); }); } }, /** * 更新剧集编号 */ updateEpisodeNumbers: function() { var episodeNumber = 1; // 从第1集开始 this.elements.episodesList.find('.zfve-episode-item').each(function() { var $item = $(this); $item.attr('data-episode', episodeNumber); $item.find('.zfve-episode-number').text('第' + episodeNumber + '集'); // 更新placeholder var $titleInput = $item.find('.zfve-episode-title'); if (!$titleInput.val()) { $titleInput.attr('placeholder', '第' + episodeNumber + '集'); } episodeNumber++; }); this.config.episodeCounter = episodeNumber; }, /** * 打开视频选择器 */ openVideoSelector: function($btn) { var self = this; this.currentEpisodeInput = $btn.closest('.zfve-video-input-group').find('.zfve-episode-url'); // 检查是否有zib.media(Zibll主题的媒体选择器) if (typeof zib === 'undefined' || typeof zib.media === 'undefined') { this.showNotice('媒体选择器未加载,请确保Zibll主题已正确安装', 'danger'); return; } // 如果还没有创建媒体选择器,则创建 if (!this.mediaSelector) { var args = { type: 'video', is_upload: true, iframe: false, upload_multiple: 1, upload_size: window._win.upload_video_size || 30, multiple: 1, text: { title: '选择视频', subtitle: '请选择或上传视频文件' } }; this.mediaSelector = new zib.media(args); // 绑定选择事件 this.mediaSelector.$el.on('lists_submit upload', function(e, data) { var video = data.data ? data.data[0] : data; if (video && video.url && self.currentEpisodeInput) { self.currentEpisodeInput.val(video.url); } self.mediaSelector.close(); }); // 绑定手动输入事件 this.mediaSelector.$el.on('input_submit', function(e, data) { if (data.vals && data.vals[0] && self.currentEpisodeInput) { self.currentEpisodeInput.val(data.vals[0]); } }); } // 打开媒体选择器 this.mediaSelector.resetActiveLists(); this.mediaSelector.open(); }, /** * 验证文件格式 */ validateFormats: function() { // 检查是否为资源内容类型 var contentType = $('input[name="zfve_content_type"]:checked').val(); if (contentType !== 'resource') { // 如果是视频类型,不需要验证文件格式 return true; } // 检查文件格式数量 var totalFormats = $('.zfve-format-item').length; if (totalFormats < 1) { return false; } // 检查是否至少有一个格式选择了类型 var hasValidFormat = false; $('.zfve-format-item').each(function() { var formatType = $(this).find('.format-type-select').val(); if (formatType && formatType !== '') { hasValidFormat = true; return false; // 找到一个有效格式就退出循环 } }); return hasValidFormat; }, /** * 同步内容到原有编辑器 */ syncContentToOriginalEditor: function() { var content = $('#post_content').val() || ''; // 同步到TinyMCE编辑器 if (typeof tinymce !== 'undefined') { var editor = tinymce.get('post_content'); if (editor) { editor.setContent(content); } } // 同步到所有name="post_content"的元素 $('textarea[name="post_content"], input[name="post_content"]').each(function() { var $elem = $(this); if ($elem.attr('id') !== 'post_content') { $elem.val(content); } }); // 同步到WP编辑器的textarea var $wpEditor = $('#wp-post_content-editor-container textarea'); if ($wpEditor.length) { $wpEditor.val(content); } // 触发change事件确保表单验证能检测到 $('#post_content').trigger('change').trigger('input'); }, /** * 更新隐藏的input值(用于表单提交) */ updateHiddenInputs: function() { // 移除旧的隐藏input $('.zfve-hidden-input').remove(); var episodes = []; this.elements.episodesList.find('.zfve-episode-item').each(function() { var $item = $(this); var title = $item.find('.zfve-episode-title').val(); var url = $item.find('.zfve-episode-url').val(); var isPaid = $item.find('.zfve-episode-is-paid').val() === '1'; if (url) { // 只保存有URL的剧集 episodes.push({ title: title, url: url, is_paid: isPaid }); } }); // 添加隐藏input var $form = $('form.new-post-form'); episodes.forEach(function(episode, index) { $form.append(''); $form.append(''); $form.append(''); }); }, /** * 加载已有数据(编辑模式) */ loadExistingData: function() { var self = this; // 检查是否有编辑数据 if (typeof window.zfve_edit_data === 'undefined') { return; } var editData = window.zfve_edit_data; // 延迟加载,确保其他模块都已初始化 setTimeout(function() { // 加载资源介绍 if (editData.description) { $('#post_content').val(editData.description); } // 加载内容类型 if (editData.content_type) { $('input[name="zfve_content_type"][value="' + editData.content_type + '"]').prop('checked', true); $('#zfve_content_type_value').val(editData.content_type); // 触发内容类型切换 if (typeof ZFVEContentType !== 'undefined' && ZFVEContentType.switchContentType) { ZFVEContentType.switchContentType(editData.content_type); } } // 加载文件格式 if (editData.file_formats && typeof ZFVEFileFormats !== 'undefined' && ZFVEFileFormats.loadFormats) { ZFVEFileFormats.loadFormats(editData.file_formats); } // 加载模型属性 if (editData.model_attributes && typeof ZFVEModelAttributes !== 'undefined' && ZFVEModelAttributes.loadAttributes) { ZFVEModelAttributes.loadAttributes(editData.model_attributes); } // 加载引擎属性 if (editData.engine_attributes && typeof ZFVEEngineAttributes !== 'undefined' && ZFVEEngineAttributes.loadAttributes) { ZFVEEngineAttributes.loadAttributes(editData.engine_attributes); } // 加载剧集列表 if (editData.episodes && Array.isArray(editData.episodes) && editData.episodes.length > 0) { editData.episodes.forEach(function(episode, index) { var episodeNumber = index + 1; // 从第1集开始 var isPaid = (episode.is_paid === undefined || episode.is_paid === null) ? false : episode.is_paid; var episodeHtml = self.createEpisodeHtml( episodeNumber, episode.title, episode.url, isPaid ); self.elements.episodesList.append(episodeHtml); self.config.episodeCounter = episodeNumber + 1; }); } }, 200); // 延迟200ms确保其他模块已初始化 }, /** * 滚动到指定剧集 */ scrollToEpisode: function($episode) { if (!$episode.length) return; var container = this.elements.episodesList; var scrollTo = $episode.position().top + container.scrollTop() - 20; container.animate({ scrollTop: scrollTo }, 300); }, /** * 显示通知 */ showNotice: function(message, type) { type = type || 'info'; // 使用Zibll主题的通知系统 if (typeof zib !== 'undefined' && typeof zib.notify !== 'undefined') { zib.notify(message, type); } else { // 降级方案:使用alert alert(message); } }, /** * 转义HTML */ escapeHtml: function(text) { if (!text) return ''; var map = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }; return text.replace(/[&<>"']/g, function(m) { return map[m]; }); } }; // 导出到全局(如果需要外部访问) window.ZFVEManager = ZFVEManager; /** * 图片选择器管理器 */ var ZFVEImagePicker = { selectedImages: [], currentPage: 1, totalPages: 1, resourceImages: [], // 存储资源图片的URL数组 /** * 初始化 */ init: function() { this.bindEvents(); this.loadExistingImages(); }, /** * 绑定事件 */ bindEvents: function() { var self = this; // 添加图片按钮 $(document).on('click', '#zfve_add_images_btn', function(e) { e.preventDefault(); self.openPicker(); }); // 关闭选择器 $(document).on('click', '#zfve_picker_cancel_btn, .zfve-picker-backdrop, .zfve-picker-close', function() { self.closePicker(); }); // 确认选择 $(document).on('click', '#zfve_picker_confirm_btn', function() { self.confirmSelection(); }); // 上传按钮 $(document).on('click', '#zfve_picker_upload_btn', function() { $('#zfve_picker_file_input').click(); }); // 文件选择 $(document).on('change', '#zfve_picker_file_input', function(e) { self.uploadImages(e.target.files); }); // 搜索 var searchTimeout; $(document).on('input', '#zfve_picker_search', function() { clearTimeout(searchTimeout); var search = $(this).val(); searchTimeout = setTimeout(function() { self.currentPage = 1; self.loadImages(search); }, 500); }); // 删除图片 $(document).on('click', '.zfve-remove-image', function(e) { e.preventDefault(); e.stopPropagation(); var $item = $(this).closest('.zfve-image-item'); var url = $item.data('url'); self.removeImage(url); }); // 表单提交前更新隐藏字段 $('form').on('submit', function() { self.updateHiddenField(); }); }, /** * 加载已有图片 */ loadExistingImages: function() { if (window.zfve_edit_data && window.zfve_edit_data.images) { this.resourceImages = window.zfve_edit_data.images; this.renderGallery(); } }, /** * 打开选择器 */ openPicker: function() { this.selectedImages = []; this.currentPage = 1; $('#zfve_image_picker').fadeIn(300); $('body').css('overflow', 'hidden'); this.loadImages(); }, /** * 关闭选择器 */ closePicker: function() { $('#zfve_image_picker').fadeOut(300); $('body').css('overflow', ''); }, /** * 加载图片列表 */ loadImages: function(search) { var self = this; var container = $('#zfve_picker_grid'); container.html('
加载中...
'); $.ajax({ url: zfveData.ajaxUrl, type: 'POST', data: { action: 'zfve_get_user_images', page: self.currentPage, search: search || '', per_page: 30 }, success: function(response) { if (response.success && response.data.images) { var images = response.data.images; self.totalPages = response.data.total_pages || 1; if (images.length === 0) { container.html('

暂无图片,请先上传图片

'); return; } var html = ''; images.forEach(function(img) { var selected = self.selectedImages.indexOf(img.url) !== -1 ? 'selected' : ''; html += '
'; html += '
'; html += ''; html += '
'; html += '
'; html += '
'; }); container.html(html); self.updatePagination(); // 绑定点击事件 $('.zfve-picker-item').on('click', function() { var url = $(this).data('url'); var index = self.selectedImages.indexOf(url); if (index === -1) { self.selectedImages.push(url); $(this).addClass('selected'); } else { self.selectedImages.splice(index, 1); $(this).removeClass('selected'); } self.updateSelectedCount(); }); } else { container.html('

加载失败,请重试

'); } }, error: function() { container.html('

加载失败,请检查网络

'); } }); }, /** * 更新分页 */ updatePagination: function() { var self = this; var html = ''; if (self.currentPage > 1) { html += ''; } html += '第 ' + self.currentPage + ' / ' + self.totalPages + ' 页'; if (self.currentPage < self.totalPages) { html += ''; } $('#zfve_picker_pagination').html(html); $('.zfve-picker-page-btn').on('click', function() { self.currentPage = parseInt($(this).data('page')); self.loadImages($('#zfve_picker_search').val()); }); }, /** * 更新选中数量 */ updateSelectedCount: function() { var count = this.selectedImages.length; var text = count > 0 ? '添加选中的图片 (' + count + ')' : '请选择图片'; $('#zfve_picker_confirm_btn').text(text); $('#zfve_picker_confirm_btn').prop('disabled', count === 0); }, /** * 确认选择 */ confirmSelection: function() { var self = this; self.selectedImages.forEach(function(url) { if (self.resourceImages.indexOf(url) === -1) { self.resourceImages.push(url); } }); self.renderGallery(); self.updateHiddenField(); self.closePicker(); }, /** * 上传图片 */ uploadImages: function(files) { var self = this; if (files.length === 0) return; var formData = new FormData(); for (var i = 0; i < files.length; i++) { formData.append('files[]', files[i]); } formData.append('action', 'zfve_upload_images'); formData.append('nonce', zfveData.uploadNonce); $('#zfve_picker_upload_progress').show(); $('#zfve_picker_progress_bar').css('width', '0%'); $.ajax({ url: zfveData.ajaxUrl, type: 'POST', data: formData, processData: false, contentType: false, xhr: function() { var xhr = new window.XMLHttpRequest(); xhr.upload.addEventListener('progress', function(evt) { if (evt.lengthComputable) { var percentComplete = (evt.loaded / evt.total) * 100; $('#zfve_picker_progress_bar').css('width', percentComplete + '%'); } }, false); return xhr; }, success: function(response) { $('#zfve_picker_upload_progress').fadeOut(); $('#zfve_picker_file_input').val(''); if (response.success) { self.currentPage = 1; self.loadImages(); } else { alert('上传失败:' + (response.data || '未知错误')); } }, error: function() { $('#zfve_picker_upload_progress').fadeOut(); alert('上传失败,请重试'); } }); }, /** * 删除图片 */ removeImage: function(url) { var index = this.resourceImages.indexOf(url); if (index !== -1) { this.resourceImages.splice(index, 1); this.renderGallery(); this.updateHiddenField(); } }, /** * 渲染图片画廊 */ renderGallery: function() { var gallery = $('#zfve_images_gallery'); if (gallery.length === 0) { return; } if (this.resourceImages.length === 0) { gallery.html( '
' + '' + '

暂无图片,点击上方"添加图片"按钮开始上传

' + '
' ); } else { var html = ''; this.resourceImages.forEach(function(url) { html += '
'; html += '资源图片'; html += ''; html += '
'; }); gallery.html(html); } }, /** * 更新隐藏字段 - 将图片转为HTML格式 */ updateHiddenField: function() { var html = ''; this.resourceImages.forEach(function(url) { html += '

资源图片

'; }); $('#zfve_resource_images_html').val(html); } }; // 初始化图片选择器 $(document).ready(function() { setTimeout(function() { ZFVEImagePicker.init(); }, 600); }); // 导出到全局 window.ZFVEImagePicker = ZFVEImagePicker; })(jQuery, window); /** * 瀑布流布局管理器 - 真正的Masonry布局 * 用于前端文章页面的图片展示 */ (function($, window) { 'use strict'; var ZFVEWaterfallLayout = { // 配置 config: { columnGap: 15, // 列间距 defaultColumns: 4, // 默认列数 animationDelay: 50, // 动画延迟(毫秒) heightVariationMin: 0.5, // 最小高度变化系数(50%) heightVariationMax: 2.2, // 最大高度变化系数(220%) useRandomHeights: true // 是否使用随机高度变化 }, // 当前列数 currentColumns: 4, // 等待DOM加载完成后初始化 init: function() { var self = this; // 查找所有瀑布流容器 var $galleries = $('.zfve-waterfall-gallery'); if ($galleries.length === 0) { return; } // 为每个容器初始化布局 $galleries.each(function() { self.initGallery($(this)); }); // 监听窗口大小变化 var resizeTimer; $(window).on('resize', function() { clearTimeout(resizeTimer); resizeTimer = setTimeout(function() { $galleries.each(function() { self.layoutGallery($(this)); }); }, 250); }); }, /** * 初始化单个画廊 */ initGallery: function($gallery) { var self = this; var $items = $gallery.find('.zfve-waterfall-item'); if ($items.length === 0) { return; } // 等待所有图片加载完成 var images = $items.find('img'); var loadedCount = 0; var totalImages = images.length; if (totalImages === 0) { // 没有图片,直接布局 self.layoutGallery($gallery); return; } images.each(function() { var img = this; // 图片已加载或加载失败都继续 var checkLoad = function() { loadedCount++; if (loadedCount === totalImages) { self.layoutGallery($gallery); } }; if (img.complete) { checkLoad(); } else { $(img).on('load error', checkLoad); } }); }, /** * 计算当前应该使用的列数 */ getColumnCount: function() { var width = $(window).width(); if (width <= 480) { return 2; // 手机:2列 } else if (width <= 768) { return 2; // 平板:2列 } else if (width <= 1200) { return 3; // 中等屏幕:3列 } else { return 4; // 大屏幕:4列 } }, /** * 执行瀑布流布局 */ layoutGallery: function($gallery) { var self = this; var $items = $gallery.find('.zfve-waterfall-item'); if ($items.length === 0) { return; } // 计算列数 var columns = self.getColumnCount(); self.currentColumns = columns; // 计算容器宽度和列宽 var containerWidth = $gallery.width(); var gap = self.config.columnGap; var columnWidth = (containerWidth - (gap * (columns - 1))) / columns; // 初始化每列的高度数组 var columnHeights = []; for (var i = 0; i < columns; i++) { columnHeights[i] = 0; } // 为每个项目计算位置 $items.each(function(index) { var $item = $(this); var $img = $item.find('img'); // 获取图片的原始尺寸 var img = $img[0]; var imgWidth = img.naturalWidth || img.width || 800; var imgHeight = img.naturalHeight || img.height || 600; // 如果无法获取图片尺寸,使用随机高度范围 if (!img.naturalWidth && !img.width) { var randomHeights = [200, 300, 400, 500]; imgHeight = randomHeights[index % randomHeights.length]; imgWidth = columnWidth; } // 计算项目高度(保持宽高比) var aspectRatio = imgHeight / imgWidth; var itemHeight = aspectRatio * columnWidth; // 添加高度变化范围,让布局更自然 if (self.config.useRandomHeights) { // 使用预设的随机系数数组,循环使用 var heightVariations = [1, 2, 3]; var heightVariation = heightVariations[index % heightVariations.length]; itemHeight = itemHeight * heightVariation; } else { var heightVariation = 1.0; } // 限制高度范围,避免过高或过低 var minItemHeight = columnWidth * 0.5; // 最小高度为列宽的50% var maxItemHeight = columnWidth * 4.0; // 最大高度为列宽的400%(支持3倍系数) itemHeight = Math.max(minItemHeight, Math.min(maxItemHeight, itemHeight)); // 找到当前最短的列 var minHeight = Math.min.apply(Math, columnHeights); var columnIndex = columnHeights.indexOf(minHeight); // 计算位置 var left = columnIndex * (columnWidth + gap); var top = columnHeights[columnIndex]; // 设置项目的位置和尺寸 $item.css({ 'position': 'absolute', 'left': left + 'px', 'top': top + 'px', 'width': columnWidth + 'px', 'height': itemHeight + 'px' }); // 添加定位完成的类,触发显示动画 setTimeout(function() { $item.addClass('zfve-positioned'); }, self.config.animationDelay * index); // 更新该列的高度 columnHeights[columnIndex] += itemHeight + gap; }); // 设置容器高度为最高列的高度 var maxHeight = Math.max.apply(Math, columnHeights); $gallery.css('height', maxHeight + 'px'); } }; // DOM加载完成后初始化 $(document).ready(function() { // 延迟初始化,确保DOM完全渲染 setTimeout(function() { ZFVEWaterfallLayout.init(); }, 300); }); // 导出到全局 window.ZFVEWaterfallLayout = ZFVEWaterfallLayout; })(jQuery, window); 材质-ITCG资源网
材质-ITCG资源网
ITCG资源网
  • 首页
  • 资源商城
    • 3D模型资源
    • Unreal Engine资源
    • Unity资源
  • 作品集
  • 教程
    • 入门教程
      • 入门3Dsmax教程
      • 入门Maya教程
      • 入门Blender教程
      • 入门Unity教程
      • 入门Unreal Engine教程
    • 专项教程
      • 3Dsmax
      • Maya
      • Blender
      • Unreal Engine
      • Unity
  • 免费
    • 本月免费
    • 永久免费
  • 盒子AR
  • 工具软件
  • 技术问答
  • 更多
    • 声明
  • 登录
  • 注册
  • 首页
  • 资源商城
    • 3D模型资源
    • Unreal Engine资源
    • Unity资源
  • 作品集
  • 教程
    • 入门教程
    • 专项教程
  • 免费
    • 本月免费
    • 永久免费
  • 盒子AR
  • 工具软件
  • 技术问答
  • 更多
    • 声明
登录
注册
找回密码

快速登录

材质

材质
分类
    资源教程作品
子分类
    Unity资源Unreal Engine资...3D模型资源
子分类
    插件蓝图材质粒子特效场景交通工具人物实验展馆文物/雕塑机械/器械植物电子电器舞美/会议车辆建筑/室内/地产
排序
  • 更新
  • 发布
  • 浏览
  • 点赞
  • 评论
  • 收藏
  • 售价
  • 积分
  • 销量
  • 随机
    更新浏览点赞评论售价销量
UE4汽车变色特效源码工程-ITCG资源网
置顶

UE4汽车变色特效源码工程

付费资源¥698# 汽车# 汽车展示# 变色
186
电子沙盘新能源展示-ITCG资源网

电子沙盘新能源展示

付费资源¥220# 特效# UE5# 沙盘
292
大屏展示效果-ITCG资源网

大屏展示效果

付费资源¥60# UE5# 数字可视化# 大数据
268
桃花岛-ITCG资源网

桃花岛

永久免费# UE5# 场景
239
最新内容
分类-Unreal Engine资源-ITCG资源网 1.3W+
Unreal Engine资源
Unreal Engine资源
24篇文章更多文章
UE5最简单的方式保存应用数据
2个月前
ITCGHub 启动器 API插件
6个月前
工厂 仓库
10个月前
仓库场景
10个月前
UE5 MySQL插件
10个月前
推土机模拟工程源码
10个月前
分类-教程-ITCG资源网 8212
教程
视频教程
16篇文章更多文章
游戏美术手绘建模教程入门到精通
前天
Maya2023——入门篇
11个月前
Niagara火灾和烟雾爆炸教程
1年前
虚幻引擎5.4中的实时运动设计
1年前
虚幻引擎 5.4实时针织效果教程
1年前
UE5全景环幕教程
1年前
全站热门内容
补光灯的资产制作和交互功能开发(1)-ITCG资源网
586人已阅读
补光灯的资产制作和交互功能开发(1)
TOP1
3DsMax 2024教程 (入门篇)-ITCG资源网
3DsMax 2024教程 (入门篇)
2年前500人已阅读
TOP2
汽车绑定模拟驾驶-第一期绑定到UE5-ITCG资源网
汽车绑定模拟驾驶-第一期绑定到UE5
2年前476人已阅读
TOP3
汽车绑定模拟驾驶-第二期绑定到UE5-完结-ITCG资源网
汽车绑定模拟驾驶-第二期绑定到UE5-完结
2年前470人已阅读
TOP4
水电站机组水轮机-ITCG资源网
水电站机组水轮机
2年前429人已阅读
TOP5
电网工作人员-ITCG资源网
电网工作人员
2年前385人已阅读
TOP6
祝融号火星车-ITCG资源网
祝融号火星车
1年前352人已阅读
TOP7
数字云特效-ITCG资源网
数字云特效
2年前334人已阅读
TOP8
风力发电机带内部-ITCG资源网
风力发电机带内部
1年前331人已阅读
TOP9
雪材质-ITCG资源网
雪材质
2年前314人已阅读
TOP10
电线杆-ITCG资源网
电线杆
2年前293人已阅读
TOP11
电子沙盘新能源展示-ITCG资源网
电子沙盘新能源展示
2年前292人已阅读
TOP12
标签云
龙门架 (11)黄山 (1)鸡 (1)驾考 (1)驾校 (1)风格化小场景 (0)风机 (1)风力发电 (1)霸王龙 (1)雪地 (1)隔离开关 (11)防空系统 (1)防空导弹 (1)阀塔 (1)阀厅 (3)闸门 (2)闸机 (1)问界M9 (2)问界M8 (1)问界M7 (2)问界M5 (1)问界 (7)门卫室 (1)长江 (1)锻造 (1)锅炉 (1)铁水 (1)钢铁 (2)配电柜 (1)避雷针 (1)避雷器 (19)通风管道 (1)通信柜 (1)输送线 (1)输电塔 (1)轿车 (1)轮胎 (1)车辆 (1)车床 (1)车 (1)
  • ITCG资源网

    一站式3D数字资产分享与技术问答平台

    这里是面向3D互动仿真开发者的专业开源技术社区论坛,汇集了大量专业的3D开发原创内容,以分享专业.优质.高效的技术和经验为己任,为所有学习者提供平台
  • AI ITCG ITCG Hub

    Copyright © 2022 · ITCG资源网 · 由贵州虚幻数字科技.强力驱动 黔ICP备2022006773号-3 贵公网安备 52030002001287号
    扫一扫加微信-ITCG资源网
  • 公众号-ITCG资源网

    公众号

    平台管理-ITCG资源网

    平台管理
扫码添加微信-ITCG资源网
在手机上浏览此页面

ITCG资源网
登录
没有账号?立即注册
邮箱
验证码
账号密码登录
用户名或邮箱
登录密码
找回密码 | 免密登录

社交账号登录

注册
已有账号,立即登录
设置用户名
邮箱
验证码
设置密码
重复密码
扫码登录
使用其它方式登录或注册扫码登录

作品发布指南

通过平台发布3D作品,系统将自动生成专属在线展示应用。无论是求职面试时展示专业能力,还是向客户呈现项目效果,都能让您的创作以更直观的方式呈现。只需分享作品首页链接,即可让合作伙伴与朋友轻松了解您的创意成果。

  • 专业数据加密保护
    您发布的3D作品将全程采用行业领先的加密技术处理,让您在分享创意成果时无需担忧知识产权安全,真正实现安心便捷的作品传播。
  • 作品发布后暂未显示说明
    作品提交发布后,系统将自动进入后台审核流程,这是为了确保平台内容质量与合规性。审核通过后,您的作品会立即在"作品栏"中展示。

如有任何疑问,请联系我们的客服。

发布作品