loading页面(2017.12.13)

本文介绍了一个使用HTML5 Canvas API实现的动态加载界面示例。通过定时更新画布内容,实现了旋转的圆形图案和渐进式的加载进度条效果。

利用canvas 画布API写的一个简单的loading界面,代码如下:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<title>loading</title>
</head>
<style type="text/css">
    *{
    margin:0;
    padding:0;
    }
    canvas{
    display:block;
    background:#000000;
    }
    </style>
<body>
<canvas id="loading"></canvas>
</body>
<script type="text/javascript">
    var canvas = document.getElementById("loading");
    canvas.width = innerWidth;
    canvas.height = innerHeight;
        
    var ctx = canvas.getContext("2d");
    var width = innerWidth;
    var height = innerHeight;
    var timer = null;
    var speed = 5;
    var loading = 0.5*width-150;
    var count = 0;
    var deg = new Array(0,300,265,180,165,105);
    var rad = new Array(0.1*height,0.08*height,0.06*height);
    onload = function(){  timer = setInterval("draw()",100);  };
    window.onresize = function(){
                                   clearInterval(timer);
                                   canvas.width = innerWidth;
                                   canvas.height = innerHeight;
                                   width = innerWidth;
                                   height = innerHeight;
                                   count = 0;
                                   rad[0] = 0.1*height;
                                   rad[1] = 0.08*height;
                                   rad[2] = 0.06*height;
                                   loading = 0.5*width-150;
                                   timer = setInterval("draw()",100);
                                  }
    
    
    function draw(){
    ctx.strokeStyle="#00ffff";   //画笔颜色必须每次都规定,否则默认为黑色
    /*中心圆圈*/
    ctx.clearRect(0,0,width,0.64*height);
    for(var j=0,k=0;j<3;j++)
    {
        ctx.beginPath();
        ctx.arc(0.5*width,0.5*height,rad[j],dToR(deg[k]),dToR(deg[k+1]),false);
        ctx.stroke();
        k += 2;
    }
    for(var i=0;i<7;i++){  deg[i] += speed; }
    /*loading字体和进度*/
    var percent = (count++)+"%";
    ctx.clearRect(0,0.66*height,width,height);
    ctx.fillStyle = "#00ffff";
    ctx.font = "italic 1.2em serif";
    ctx.fillText("Loading...",0.5*width-40.5,0.5*height+7.5);
    ctx.fillText(percent,0.5*width-10,0.68*height);
    /*进度条*/
    ctx.beginPath();
    ctx.arc(0.5*width-150,0.65*height,0.01*height,dToR(90),dToR(270),false);
    ctx.arc(0.5*width+150,0.65*height,0.01*height,dToR(270),dToR(90),false);
    ctx.moveTo(0.5*width-150,0.66*height);
    ctx.lineTo(0.5*width+150,0.66*height);
    ctx.stroke();
    ctx.beginPath();
    ctx.arc(loading,0.65*height,0.01*height,0,2*Math.PI,true);
    ctx.closePath();
    ctx.fill();
    loading += 3;
    if(loading == 0.5*width+153)  /*153是为了把最后的一点画上*/
    {
         clearInterval(timer);
         alert("page is completely    loaded");
         }         
    }
    function dToR(degree){
    if(degree>360)
        return ((degree-360)*Math.PI)/180;
        else
            return (degree*Math.PI)/180;
            }
</script>

</html>

大致效果如下:

index.html: <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>闽货优品 - 福建特产文化推广</title> <link rel="stylesheet" href="style.css"> <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> </head> <body> <div id="app"> <!-- 顶部导航栏 --> <nav class="main-nav"> <div class="container"> <a href="index.html" class="nav-logo">🍜 闽货优品</a> <div class="nav-links"> <a href="index.html" class="nav-link active">首页</a> <a href="products.html" class="nav-link">特产档案</a> <a href="craftsmen.html" class="nav-link">匠人故事</a> <a href="videos.html" class="nav-link">短视频</a> <a href="cold-knowledge.html" class="nav-link">冷知识</a> </div> </div> </nav> <!-- 文化标语 --> <section class="hero-banner"> <div class="container"> <h1 class="hero-title">味道,是故乡最深的记忆</h1> <p class="hero-subtitle">探寻福建非遗美食,传承千年文化韵味</p> </div> </section> <!-- 文化冷知识 --> <!-- 在 index.html 的文化冷知识部分 --> <section class="cultural-trivia-section"> <div class="container"> <div class="section-header"> <span class="section-icon">🎯</span> <h2 class="section-title">每日文化冷知识</h2> <p class="section-subtitle">每天发现闽清非遗的新鲜故事</p> </div> <!-- 冷知识轮播 --> <!-- 冷知识轮播 --> <div class="trivia-carousel"> <div class="carousel-container"> <div v-for="(trivia, index) in dailyTrivias" :key="index" :class="['carousel-item', { active: currentTriviaIndex === index }]"> <div class="trivia-content"> <!-- 图标和分类同行 --> <div class="trivia-header"> <span class="trivia-icon">{{ trivia.icon }}</span> <h3 class="trivia-category">{{ trivia.category }}</h3> </div> <p>{{ trivia.content }}</p> </div> </div> </div> <!-- 轮播指示器 --> <div class="carousel-indicators" v-if="dailyTrivias.length > 1"> <button v-for="(_, index) in dailyTrivias" :key="index" :class="['indicator', { active: currentTriviaIndex === index }]" @click="currentTriviaIndex = index"> </button> </div> <!-- 轮播控制按钮 --> <button class="carousel-btn prev" @click="prevTrivia" v-if="dailyTrivias.length > 1">‹</button> <button class="carousel-btn next" @click="nextTrivia" v-if="dailyTrivias.length > 1">›</button> </div> <!-- 特产档案 --> <section class="products-section"> <div class="container"> <h2 class="section-title">🍜 特色美食档案</h2> <!-- 加载状态 --> <div v-if="isLoading" class="loading"> <p>正在加载特产数据...</p> </div> <!-- 产品网格 --> <div v-else class="products-grid"> <div v-for="product in products" :key="product.id" class="product-card"> <!-- 添加产品主图 --> <img v-if="mainImageUrl" :src="'http://127.0.0.1:8000' + product.main_image_url" :alt="product.product_name" class="hero-image"> <div class="product-header"> <h3>{{ product.product_name }}</h3> <span class="category">{{ product.category }}</span> </div> <div class="product-origin">📍 {{ product.origin }}</div> <div class="product-taste">👅 {{ product.taste_profile }}</div> <button class="detail-btn" @click="showDetail(product)">查看详情</button> </div> </div> <!-- 空状态 --> <div v-if="!isLoading && products.length === 0" class="no-data"> <p>暂无特产数据</p> </div> <!-- 查看更多 --> <div class="more-section"> <a href="products.html" class="btn-primary">浏览全部特产档案</a> </div> </div> </section> <footer class="footer"> <div class="container"> <p>闽货优品 - 传承福建美食文化 © 2024</p> </div> </footer> </div> <script src="app.js"></script> </body> </html> 匠人界面: <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>匠人故事 - 闽货优品</title> <link rel="stylesheet" href="style.css"> <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> </head> <body> <div id="app"> <!-- 顶部导航栏 --> <nav class="main-nav"> <div class="container"> <a href="index.html" class="nav-logo">🍜 闽货优品</a> <div class="nav-links"> <a href="index.html" class="nav-link">首页</a> <a href="products.html" class="nav-link">特产档案</a> <a href="craftsmen.html" class="nav-link active">匠人故事</a> <a href="videos.html" class="nav-link">短视频</a> <a href="cold-knowledge.html" class="nav-link">冷知识</a> </div> </div> </nav> <!-- 匠人故事标语 --> <section class="hero-banner"> <div class="container"> <h1 class="hero-title">匠心传承,非遗之光</h1> <p class="hero-subtitle">聆听非遗传承人的坚守与创新故事</p> </div> </section> <!-- 匠人故事列表 --> <section class="craftsmen-section"> <div class="container"> <h2 class="section-title">👨‍🍳 非遗传承匠人</h2> <!-- 加载状态 --> <div v-if="isLoading" class="loading"> <p>正在加载匠人故事...</p> </div> <!-- 匠人网格 --> <div v-else class="craftsmen-grid"> <div v-for="craftsman in craftsmen" :key="craftsman.id" class="craftsman-card"> <!-- 匠人头像 --> <div class="craftsman-avatar"> <div class="avatar-placeholder"> 👨‍🍳 </div> </div> <div class="craftsman-content"> <h3 class="craftsman-name">{{ craftsman.name }}</h3> <div class="craftsman-specialty">🏷️ {{ craftsman.specialty_name }}</div> <div class="craftsman-experience">⏳ {{ craftsman.years_experience }}年经验</div> <p class="craftsman-story">{{ getStoryExcerpt(craftsman.story_content) }}</p> <div class="craftsman-honors" v-if="craftsman.honors"> <strong>🏆 荣誉:</strong> {{ craftsman.honors }} </div> <button class="detail-btn" @click="showCraftsmanDetail(craftsman)">了解更多</button> </div> </div> </div> <!-- 空状态 --> <div v-if="!isLoading && craftsmen.length === 0" class="no-data"> <p>暂无匠人数据</p> </div> </div> </section> <footer class="footer"> <div class="container"> <p>闽货优品 - 传承福建美食文化 © 2024</p> </div> </footer> </div> <script> const { createApp } = Vue; createApp({ data() { return { craftsmen: [], isLoading: true, API_BASE: 'http://127.0.0.1:8000' } }, async mounted() { await this.loadCraftsmen(); }, methods: { async loadCraftsmen() { try { console.log('正在加载匠人数据...'); const response = await fetch(`${this.API_BASE}/api/craftsmen/`); if (!response.ok) { throw new Error('匠人API请求失败'); } let data = await response.json(); this.craftsmen = data; console.log('匠人数据加载成功:', this.craftsmen); } catch (error) { console.error('加载匠人失败:', error); this.craftsmen = []; } finally { this.isLoading = false; } }, getStoryExcerpt(story) { if (!story) return '暂无故事内容'; return story.length > 100 ? story.substring(0, 100) + '...' : story; }, showCraftsmanDetail(craftsman) { alert(`${craftsman.name}\n\n${craftsman.story_content}\n\n荣誉: ${craftsman.honors || '暂无'}`); } } }).mount('#app'); </script> </body> </html> app.js: const { createApp } = Vue; createApp({ data() { return { products: [], isLoading: true, // 冷知识轮播数据 dailyTrivias: [], currentTriviaIndex: 0, autoPlayInterval: null, API_BASE: 'http://127.0.0.1:8000' } }, async mounted() { await this.loadProducts(); await this.loadDailyTrivias(); this.startAutoPlay(); }, methods: { async loadProducts() { try { const response = await fetch('http://127.0.0.1:8000/api/specialties/'); this.products = await response.json(); // 强制修改图片URL为绝对路径 this.products = this.products.map(product => { if (product.main_image_url) { product.main_image_url = 'http://127.0.0.1:8000' + product.main_image_url; } if (product.recipes) { product.recipes = product.recipes.map(recipe => { if (recipe.image_url) { recipe.image_url = 'http://127.0.0.1:8000' + recipe.image_url; } return recipe; }); } return product; }); } catch (error) { console.error('加载特产失败:', error); this.products = []; } finally { this.isLoading = false; } }, async loadDailyTrivias() { try { console.log('正在加载每日冷知识...'); const response = await fetch('http://127.0.0.1:8000/api/daily-trivias/'); if (response.ok) { this.dailyTrivias = await response.json(); console.log('冷知识加载成功:', this.dailyTrivias); } else { console.warn('冷知识API请求失败,使用默认数据'); this.dailyTrivias = this.getDefaultTrivias(); } } catch (error) { console.error('加载冷知识失败:', error); this.dailyTrivias = this.getDefaultTrivias(); } }, getDefaultTrivias() { // 默认冷知识数据 return [ { icon: "🧂", category: "闽清糟菜", content: "非遗技艺:闽清糟菜采用传统陶缸发酵工艺,2017年列入福州非遗" }, { icon: "🤖", category: "创新故事", content: "机器人主厨:全国首家机器人制作闽清美食的数字化餐厅" }, { icon: "🌿", category: "闽清糟菜", content: "健康价值:富含乳酸菌和氨基酸,是天然的益生元食品" } ]; }, nextTrivia() { this.currentTriviaIndex = (this.currentTriviaIndex + 1) % this.dailyTrivias.length; this.resetAutoPlay(); }, prevTrivia() { this.currentTriviaIndex = (this.currentTriviaIndex - 1 + this.dailyTrivias.length) % this.dailyTrivias.length; this.resetAutoPlay(); }, startAutoPlay() { if (this.dailyTrivias.length > 1) { this.autoPlayInterval = setInterval(() => { this.nextTrivia(); }, 5000); // 5秒自动切换 } }, resetAutoPlay() { if (this.autoPlayInterval) { clearInterval(this.autoPlayInterval); this.startAutoPlay(); } }, showDetail(product) { window.location.href = `detail.html?id=${product.id}`; }, closeModal() { this.selectedProduct = null; } }, beforeUnmount() { // 清理定时器 if (this.autoPlayInterval) { clearInterval(this.autoPlayInterval); } } }).mount('#app');以上是我的代码,问题是我的首页本应该是特产档案的地方,出现了匠人档案
最新发布
11-09
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值