我想要寫一個顯示照片的app,只需要在自己電腦上的瀏覽器能執行即可,不需要靠遠端的伺服器來執行,請幫幫我。 需求如下,我以JavaScript語法在最後附上我的相簿位置,請注意,這僅供參考,我以後會自行增減。 (1) 生成一個單獨而完整的html。 (2) 提供一個下拉選單,可讓我選擇不同的相簿。 (3) 相簿的照片先以縮圖方式呈現,等我進一步點選後才呈現完整的照片。 (4) 除了能讓我能單獨選擇照片外,另外提供一個"播放/暫停"按鍵,可依序自動播放所選相簿內的所有照片,這同一按鍵也可以暫停。 (5) "播放/暫停"按鍵的功能可用鍵盤的空白鍵來取代。 (6) 自動播放時,照片顯示的時間可讓我指定,單位以秒計算。 (7) 注意!當處在暫停狀態時,照片會永遠顯示,也就是說照片顯示時間這個設定會跟著失效。一旦恢復播放模式,照片顯示時間才有作用。 (8) 下拉選單、播放按鍵和控制照片顯示時間的輸入這三項請固定在畫面最上方。縮圖以一條水平列呈現,固定在畫面最下方。中間大部分空白則顯示完整的圖片。注意照片下方的描述文字別被遮掉,也需要安排些空間來正常顯示。const sources = {
  "my_hiking_1":
  { path:
      "../photo_galleries/my_album_1/",
    data: 
    [
      "001.jpg",
      "002.jpg",
      "003.jpg",
    ],
    description:
    [
      "001_comment",
      "002_comment",
      "003_comment",
     ]         
  },
  "my_hiking_2":
  { path:
      "../photo_galleries/my_album_2/",
    data: 
    [
      "001.jpg",
      "002.jpg",
    ],
    description:
    [
      "001_comment",
      "002_comment",
     ]         
  },       
};
好的,我要寫一個照片展示的網頁應用,這個應用不需要依賴遠端的伺服器,只在本地瀏覽器上運行。我需要生成一個完整的HTML文件,並且這個HTML文件中要包含JavaScript和CSS來實現所需的功能。
首先,我需要理解需求:
  1. 生成一個單獨而完整的HTML:這意味著我需要將所有代碼(HTML、CSS、JavaScript)都放在一個文件中,或者至少確保它們能夠在本地運行而不需要外部依賴。
  2. 下拉選單選擇相簿:我需要一個下拉選單,裡面列出所有可用的相簿,比如 "my_hiking_1" 和 "my_hiking_2"。
  3. 縮圖展示:所選相簿中的照片要以縮圖的形式展示在頁面底部,點擊縮圖後顯示完整照片。
  4. 播放/暫停按鍵:這個按鍵可以啟動自動播放相簿中的照片,也可以暫停播放。同時,鍵盤的空白鍵也可以控制播放和暫停。
  5. 自動播放時間設定:我需要一個輸入框來設定自動播放時每張照片顯示的時間,單位是秒。
  6. 暫停狀態:當處於暫停狀態時,當前照片會一直顯示,直到恢復播放。
  7. 頁面佈局:下拉選單、播放按鍵和時間輸入框固定在頁面頂部;縮圖水平排列在頁面底部;中間部分顯示完整照片,並確保照片描述文字不被遮擋。
接下來,我需要考慮如何實現這些功能。
HTML結構
  • 頂部:包含下拉選單、播放/暫停按鍵、時間輸入框。
  • 中間:顯示完整照片和描述文字。
  • 底部:縮圖列表。
CSS
  • 需要設置頂部和底部的元素固定在視窗的頂部和底部。
  • 中間部分需要足夠的空間來顯示照片和描述。
  • 縮圖需要水平排列,可能需要使用flexbox或grid來實現。
JavaScript
  • 載入相簿數據:我需要從提供的sources對象中獲取相簿路徑和照片列表。
  • 下拉選單:當選擇相簿時,載入對應的照片縮圖和描述。
  • 縮圖:點擊縮圖時,顯示對應的完整照片和描述。
  • 播放/暫停:實現自動播放功能,定時切換照片;暫停時停止切換。
  • 鍵盤控制:監聽空白鍵來切換播放/暫停狀態。
  • 時間設定:從輸入框獲取時間,設置自動播放的間隔。
現在,我開始構思代碼結構。
首先,我需要一個HTML模板,包含上述元素。
html
<!DOCTYPE html>
<html lang="zh-TW">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>照片展示</title>
    <style>
        /* CSS styles here */
    </style>
</head>
<body>
    <div id="top-bar">
        <select id="album-select">
            <!-- Options will be populated by JavaScript -->
        </select>
        <button id="play-pause">播放</button>
        <input type="number" id="interval" min="1" value="3">    </div>
    <div id="main-content">
        <img id="full-image" src="" alt="照片">
        <p id="description"></p>
    </div>
    <div id="thumbnail-bar">
        <!-- Thumbnails will be populated by JavaScript -->
    </div>
    <script>
        // JavaScript code here
    </script>
</body>
</html>
接下來,我需要填充CSS和JavaScript。
CSS部分
  • #top-bar 固定在頂部。
  • #thumbnail-bar 固定在底部,內部縮圖水平排列。
  • #main-content 位於中間,顯示完整照片和描述。
我可以使用position: fixed來固定頂部和底部。
css
body {
    margin: 0;
    padding: 0;
    overflow: hidden;
}

#top-bar {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    background-color: #f0f0f0;
    padding: 10px;
    z-index: 10;
}

#main-content {
    position: absolute;
    top: 50px; /* Adjust based on top-bar height */
    bottom: 100px; /* Adjust based on thumbnail-bar height */
    left: 0;
    right: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    overflow: auto;
}

#full-image {
    max-width: 90%;
    max-height: 80%;
}

#description {
    margin-top: 10px;
    text-align: center;
}

#thumbnail-bar {
    position: fixed;
    bottom: 0;
    left: 0;
    width: 100%;
    height: 100px;
    background-color: #e0e0e0;
    overflow-x: auto;
    white-space: nowrap;
    z-index: 10;
}

.thumbnail {
    display: inline-block;
    margin: 5px;
    cursor: pointer;
}

.thumbnail img {
    width: 80px;
    height: 80px;
    object-fit: cover;
}
JavaScript部分
首先,我需要定義sources對象。
javascript
const sources = {
    "my_hiking_1": {
        path: "../photo_galleries/my_album_1/",
        data: ["001.jpg", "002.jpg", "003.jpg"],
        description: ["001_comment", "002_comment", "003_comment"]
    },
    "my_hiking_2": {
        path: "../photo_galleries/my_album_2/",
        data: ["001.jpg", "002.jpg"],
        description: ["001_comment", "002_comment"]
    }
};
然後,我需要初始化下拉選單。
javascript
const albumSelect = document.getElementById('album-select');
for (let album in sources) {
    let option = document.createElement('option');
    option.value = album;
    option.textContent = album;
    albumSelect.appendChild(option);
}
接下來,當選擇相簿時,載入縮圖。
javascript
albumSelect.addEventListener('change', function() {
    const selectedAlbum = this.value;
    loadThumbnails(selectedAlbum);
});
loadThumbnails函數:
javascript
function loadThumbnails(album) {
    const thumbnailBar = document.getElementById('thumbnail-bar');
    thumbnailBar.innerHTML = '';
    const albumData = sources[album];
    albumData.data.forEach((photo, index) => {
        const thumbDiv = document.createElement('div');
        thumbDiv.className = 'thumbnail';
        const img = document.createElement('img');
        img.src = albumData.path + photo;
        img.alt = albumData.description[index];
        thumbDiv.appendChild(img);
        thumbDiv.addEventListener('click', function() {
            displayPhoto(album, index);
        });
        thumbnailBar.appendChild(thumbDiv);
    });
}
displayPhoto函數:
javascript
function displayPhoto(album, index) {
    const albumData = sources[album];
    const fullImage = document.getElementById('full-image');
    fullImage.src = albumData.path + albumData.data[index];
    const description = document.getElementById('description');
    description.textContent = albumData.description[index];
}
現在,實現播放/暫停功能。
我需要一個變量來追蹤當前狀態(播放或暫停),以及當前顯示的照片索引。
javascript
let isPlaying = false;
let currentAlbum = null;
let currentIndex = 0;
let intervalId = null;
播放/暫停按鍵的事件監聽:
javascript
const playPauseButton = document.getElementById('play-pause');
playPauseButton.addEventListener('click', function() {
    togglePlayPause();
});
togglePlayPause函數:
javascript
function togglePlayPause() {
    if (isPlaying) {
        clearInterval(intervalId);
        playPauseButton.textContent = '播放';
        isPlaying = false;
    } else {
        if (currentAlbum) {
            const intervalInput = document.getElementById('interval');
            const intervalTime = parseInt(intervalInput.value) * 1000;
            intervalId = setInterval(function() {
                currentIndex = (currentIndex + 1) % sources[currentAlbum].data.length;
                displayPhoto(currentAlbum, currentIndex);
            }, intervalTime);
            playPauseButton.textContent = '暫停';
            isPlaying = true;
        }
    }
}
還需要處理當選擇相簿時,設置currentAlbum和currentIndex。
loadThumbnails函數中添加:
javascript
currentAlbum = album;
currentIndex = 0;
displayPhoto(album, 0);
這樣,當選擇相簿時,會顯示第一張照片。
另外,為了讓播放從頭開始,可以在切換相簿時停止播放。
loadThumbnails函數中添加:
javascript
if (isPlaying) {
    clearInterval(intervalId);
    isPlaying = false;
    playPauseButton.textContent = '播放';
}
現在,實現鍵盤空白鍵控制。
javascript
document.addEventListener('keydown', function(event) {
    if (event.code === 'Space') {
        event.preventDefault(); // 防止頁面滾動
        togglePlayPause();
    }
});
最後,確保在載入頁面時,選擇第一個相簿並載入縮圖。
javascript
// 載入第一個相簿
if (albumSelect.options.length > 0) {
    albumSelect.selectedIndex = 0;
    loadThumbnails(albumSelect.value);
}
這樣,整個功能就基本實現了。
我還需要注意一些細節:
  • 確保照片和描述的顯示不會被頂部和底部的元素遮擋。
  • 縮圖的寬度可能需要調整,以適應不同數量的照片。
  • 照片的路徑是相對路徑,確保在本地環境下能夠正確載入。
  • 可能需要處理照片載入失敗的情況。
但基本功能已經覆蓋了需求。
現在,我將所有代碼整合到HTML文件中。
最終的HTML文件
html
<!DOCTYPE html>
<html lang="zh-TW">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>照片展示</title>
    <style>
        body {
            margin: 0;
            padding: 0;
            overflow: hidden;
        }

        #top-bar {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            background-color: #f0f0f0;
            padding: 10px;
            z-index: 10;
        }

        #main-content {
            position: absolute;
            top: 50px;
            bottom: 100px;
            left: 0;
            right: 0;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            overflow: auto;
        }

        #full-image {
            max-width: 90%;
            max-height: 80%;
        }

        #description {
            margin-top: 10px;
            text-align: center;
        }

        #thumbnail-bar {
            position: fixed;
            bottom: 0;
            left: 0;
            width: 100%;
            height: 100px;
            background-color: #e0e0e0;
            overflow-x: auto;
            white-space: nowrap;
            z-index: 10;
        }

        .thumbnail {
            display: inline-block;
            margin: 5px;
            cursor: pointer;
        }

        .thumbnail img {
            width: 80px;
            height: 80px;
            object-fit: cover;
        }
    </style>
</head>
<body>
    <div id="top-bar">
        <select id="album-select">
            <!-- Options will be populated by JavaScript -->
        </select>
        <button id="play-pause">播放</button>
        <input type="number" id="interval" min="1" value="3">    </div>
    <div id="main-content">
        <img id="full-image" src="" alt="照片">
        <p id="description"></p>
    </div>
    <div id="thumbnail-bar">
        <!-- Thumbnails will be populated by JavaScript -->
    </div>
    <script>
        const sources = {
            "my_hiking_1": {
                path: "../photo_galleries/my_album_1/",
                data: ["001.jpg", "002.jpg", "003.jpg"],
                description: ["001_comment", "002_comment", "003_comment"]
            },
            "my_hiking_2": {
                path: "../photo_galleries/my_album_2/",
                data: ["001.jpg", "002.jpg"],
                description: ["001_comment", "002_comment"]
            }
        };

        const albumSelect = document.getElementById('album-select');
        for (let album in sources) {
            let option = document.createElement('option');
            option.value = album;
            option.textContent = album;
            albumSelect.appendChild(option);
        }

        let isPlaying = false;
        let currentAlbum = null;
        let currentIndex = 0;
        let intervalId = null;

        albumSelect.addEventListener('change', function() {
            const selectedAlbum = this.value;
            loadThumbnails(selectedAlbum);
        });

        function loadThumbnails(album) {
            if (isPlaying) {
                clearInterval(intervalId);
                isPlaying = false;
                document.getElementById('play-pause').textContent = '播放';
            }
            const thumbnailBar = document.getElementById('thumbnail-bar');
            thumbnailBar.innerHTML = '';
            const albumData = sources[album];
            albumData.data.forEach((photo, index) => {
                const thumbDiv = document.createElement('div');
                thumbDiv.className = 'thumbnail';
                const img = document.createElement('img');
                img.src = albumData.path + photo;
                img.alt = albumData.description[index];
                thumbDiv.appendChild(img);
                thumbDiv.addEventListener('click', function() {
                    displayPhoto(album, index);
                });
                thumbnail/views.appendChild(thumbDiv);
            });
            currentAlbum = album;
            currentIndex = 0;
            displayPhoto(album, 0);
        }

        function displayPhoto(album, index) {
            const albumData = sources[album];
            const fullImage = document.getElementById('full-image');
            fullImage.src = albumData.path + albumData.data[index];
            const description = document.getElementById('description');
            description.textContent = albumData.description[index];
            currentIndex = index;
        }

        const playPauseButton = document.getElementById('play-pause');
        playPauseButton.addEventListener('click', function() {
            togglePlayPause();
        });

        function togglePlayPause() {
            if (isPlaying) {
                clearInterval(intervalId);
                playPauseButton.textContent = '播放';
                isPlaying = false;
            } else {
                if (currentAlbum) {
                    const intervalInput = document.getElementById('interval');
                    const intervalTime = parseInt(intervalInput.value) * 1000;
                    intervalId = setInterval(function() {
                        currentIndex = (currentIndex + 1) % sources[currentAlbum].data.length;
                        displayPhoto(currentAlbum, currentIndex);
                    }, intervalTime);
                    playPauseButton.textContent = '暫停';
                    isPlaying = true;
                }
            }
        }

        document.addEventListener('keydown', function(event) {
            if (event.code === 'Space') {
                event.preventDefault();
                togglePlayPause();
            }
        });

        // 載入第一個相簿
        if (albumSelect.options.length > 0) {
            albumSelect.selectedIndex = 0;
            loadThumbnails(albumSelect.value);
        }
    </script>
</body>
</html>
這個HTML文件包含了所有必要的代碼,可以在本地瀏覽器中運行,實現了所描述的功能。
以下是針對您需求的完整解答,我將提供一個單獨的 HTML 文件,包含 HTML、CSS 和 JavaScript,實現您想要的照片展示應用,並確保它能在本地瀏覽器運行,不依賴遠端伺服器。根據您的要求,我已經設計好代碼,並使用您提供的 sources 結構作為相簿數據範例。
完整 HTML 文件
以下是完整的代碼,您可以直接複製到一個 .html 文件中(例如 photo_gallery.html),然後在瀏覽器中打開即可使用。請確保您的照片文件路徑與 sources 中的 path 相符。
html
<!DOCTYPE html>
<html lang="zh-TW">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>照片展示應用</title>
    <style>
        /* 基本樣式,重置邊距並防止滾動條干擾 */
        body {
            margin: 0;
            padding: 0;
            overflow: hidden;
            font-family: Arial, sans-serif;
        }

        /* 頂部控制區域 */
        #top-bar {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            background-color: #f0f0f0;
            padding: 10px;
            z-index: 10;
            box-shadow: 0 2px 5px rgba(0,0,0,0.1);
        }

        #top-bar select, #top-bar button, #top-bar input {
            margin-right: 10px;
            padding: 5px;
        }

        /* 中間照片顯示區域 */
        #main-content {
            position: absolute;
            top: 60px; /* 根據頂部高度調整 */
            bottom: 110px; /* 根據底部高度調整 */
            left: 0;
            right: 0;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            overflow: auto;
        }

        #full-image {
            max-width: 90%;
            max-height: 80%;
            object-fit: contain;
        }

        #description {
            margin-top: 10px;
            text-align: center;
            font-size: 16px;
            color: #333;
        }

        /* 底部縮圖區域 */
        #thumbnail-bar {
            position: fixed;
            bottom: 0;
            left: 0;
            width: 100%;
            height: 100px;
            background-color: #e0e0e0;
            overflow-x: auto;
            white-space: nowrap;
            z-index: 10;
            padding: 5px 0;
            box-shadow: 0 -2px 5px rgba(0,0,0,0.1);
        }

        .thumbnail {
            display: inline-block;
            margin: 5px;
            cursor: pointer;
        }

        .thumbnail img {
            width: 80px;
            height: 80px;
            object-fit: cover;
            border: 2px solid transparent;
        }

        .thumbnail img:hover {
            border-color: #007BFF;
        }
    </style>
</head>
<body>
    <!-- 頂部控制區域 -->
    <div id="top-bar">
        <select id="album-select"></select>
        <button id="play-pause">播放</button>
        <input type="number" id="interval" min="1" value="3">    </div>

    <!-- 中間照片顯示區域 -->
    <div id="main-content">
        <img id="full-image" src="" alt="照片">
        <p id="description"></p>
    </div>

    <!-- 底部縮圖區域 -->
    <div id="thumbnail-bar"></div>

    <script>
        // 相簿數據,您可以自行增減
        const sources = {
            "my_hiking_1": {
                path: "../photo_galleries/my_album_1/",
                data: ["001.jpg", "002.jpg", "003.jpg"],
                description: ["001_comment", "002_comment", "003_comment"]
            },
            "my_hiking_2": {
                path: "../photo_galleries/my_album_2/",
                data: ["001.jpg", "002.jpg"],
                description: ["001_comment", "002_comment"]
            }
        };

        // DOM 元素
        const albumSelect = document.getElementById('album-select');
        const playPauseButton = document.getElementById('play-pause');
        const intervalInput = document.getElementById('interval');
        const thumbnailBar = document.getElementById('thumbnail-bar');
        const fullImage = document.getElementById('full-image');
        const description = document.getElementById('description');

        // 狀態變量
        let isPlaying = false;
        let currentAlbum = null;
        let currentIndex = 0;
        let intervalId = null;

        // 初始化下拉選單
        for (let album in sources) {
            const option = document.createElement('option');
            option.value = album;
            option.textContent = album;
            albumSelect.appendChild(option);
        }

        // 載入縮圖並顯示第一張照片
        function loadThumbnails(album) {
            // 停止當前播放
            if (isPlaying) {
                clearInterval(intervalId);
                isPlaying = false;
                playPauseButton.textContent = '播放';
            }

            // 清空縮圖區域
            thumbnailBar.innerHTML = '';
            const albumData = sources[album];

            // 生成縮圖
            albumData.data.forEach((photo, index) => {
                const thumbDiv = document.createElement('div');
                thumbDiv.className = 'thumbnail';
                const img = document.createElement('img');
                img.src = albumData.path + photo;
                img.alt = albumData.description[index];
                thumbDiv.appendChild(img);
                thumbDiv.addEventListener('click', () => displayPhoto(album, index));
                thumbnailBar.appendChild(thumbDiv);
            });

            // 設置當前相簿並顯示第一張照片
            currentAlbum = album;
            currentIndex = 0;
            displayPhoto(album, 0);
        }

        // 顯示完整照片
        function displayPhoto(album, index) {
            const albumData = sources[album];
            fullImage.src = albumData.path + albumData.data[index];
            description.textContent = albumData.description[index];
            currentIndex = index;
        }

        // 切換播放/暫停
        function togglePlayPause() {
            if (isPlaying) {
                clearInterval(intervalId);
                playPauseButton.textContent = '播放';
                isPlaying = false;
            } else if (currentAlbum) {
                const intervalTime = parseInt(intervalInput.value) * 1000;
                intervalId = setInterval(() => {
                    currentIndex = (currentIndex + 1) % sources[currentAlbum].data.length;
                    displayPhoto(currentAlbum, currentIndex);
                }, intervalTime);
                playPauseButton.textContent = '暫停';
                isPlaying = true;
            }
        }

        // 事件監聽
        albumSelect.addEventListener('change', () => loadThumbnails(albumSelect.value));
        playPauseButton.addEventListener('click', togglePlayPause);
        document.addEventListener('keydown', (event) => {
            if (event.code === 'Space') {
                event.preventDefault(); // 防止頁面滾動
                togglePlayPause();
            }
        });

        // 初始化:載入第一個相簿
        if (albumSelect.options.length > 0) {
            albumSelect.selectedIndex = 0;
            loadThumbnails(albumSelect.value);
        }
    </script>
</body>
</html>
功能說明
這個應用滿足您的所有需求,以下是每個需求的實現方式:
  1. 單獨完整的 HTML
    所有代碼(HTML、CSS、JavaScript)都包含在一個文件中,無需外部依賴,可直接在本地瀏覽器運行。
  2. 下拉選單選擇相簿
    頁面頂部的 <select> 元素會列出 sources 中的所有相簿(如 "my_hiking_1"、"my_hiking_2"),選擇後會載入對應縮圖。
  3. 縮圖展示與點擊顯示完整照片
    底部水平排列的縮圖來自所選相簿,點擊縮圖會在中間區域顯示完整照片及其描述。
  4. 播放/暫停按鍵
    "播放/暫停" 按鍵位於頂部,點擊可啟動自動播放或暫停,播放時會依序顯示相簿中的照片。
  5. 空白鍵控制
    鍵盤的空白鍵可以切換播放與暫停狀態,實現與按鍵相同的功能。
  6. 自動播放時間設定
    頂部的輸入框允許您指定播放間隔(單位:秒),預設為 3 秒,輸入後生效於下一次播放。
  7. 暫停狀態行為
    當處於暫停狀態時,當前照片會持續顯示,不受播放時間影響;恢復播放後,時間設定重新生效。
  8. 頁面佈局
    • 頂部:下拉選單、播放/暫停按鍵、時間輸入框,固定顯示。
    • 中間:完整照片和描述,佔據主要空間,描述文字不會被遮擋。
    • 底部:縮圖水平排列,固定在畫面底部,可左右滾動。
使用方法
  1. 將上述代碼保存為 photo_gallery.html
  2. 確保您的照片文件位於正確的路徑(例如 ../photo_galleries/my_album_1/001.jpg),並與 sources 中的 pathdata 匹配。
  3. 在瀏覽器中打開該文件(例如雙擊或拖入瀏覽器)。
  4. 選擇相簿、點擊縮圖查看照片,或使用播放功能自動瀏覽。
注意事項
  • 照片路徑:請根據您的實際文件結構調整 sources 中的 path,目前是相對路徑。
  • 相簿增減:您可以直接修改 sources 對象,新增或刪除相簿,應用會自動適應。
  • 錯誤處理:如果照片路徑無效,圖片可能無法顯示,建議測試時確認路徑正確。
  • 樣式調整:如需更改縮圖大小或佈局,可修改 CSS 中的 .thumbnail img 或其他樣式。
希望這個應用符合您的期待!如果有任何問題或需要進一步調整,請告訴我。