收到一則挑戰:

Silverlight常見一種多功能區塊以格狀排列的UI設計,若點選其中一個區塊,該區塊會放大佔滿全部顯示空間,其他區塊縮小收至下排或淡出隱藏,關閉時則恢復原狀。有無可能使用網頁技術(Javascript + CSS)實作出類似效果?

為了替jQuery爭一口氣,也為了"不負技術顧問的名譽"(謎之聲: 幹啥? 你是金田一嗎?),我實作了一個簡單驗證,做不到Silverlight純向量元素的完美縮放,所以我採行小區塊時先顯示圖檔,並將Width、Height設成百分比,如此在區塊放大、縮小時也能同比例放大,而在最後階段才顯示全畫面時要顯示的內容。至於動畫功能,原則上靠animate(), fadeIn(), fadeOut()就能輕鬆完成:

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Zoom Nav Demo</title>
    <script src="http://ajax.microsoft.com/ajax/jquery/jquery-1.4.2.js?WT.mc_id=DOP-MVP-37580" 
            type="text/javascript"></script>
    <style type="text/css">
        .b  
        {
            float: left; width: 300px; height: 200px;
            border: 1px solid black; margin: 5px; 
            cursor: pointer; text-align: center;
            font-family: Tahoma; color: White;
        }
        .b img { width: 85%; height: 85% }
        .b div { display: none; text-align: left; padding: 10px; }
        #container { width: 1000px; }
    </style>
    <script type="text/javascript">
        $(function () {
            var $blocks = $("div.b");
            var c = ["red", "orange", "yellow", "green", "blue", "purple"];
            //取得最左上到最右下的範圍
            var x1, y1, x2, y2;
            x1 = y1 = 9999; x2 = y2 = -1;
            var animDura = 1000; //動畫時間
            $blocks.each(function (i) {
                var $b = $(this);
                //保留各DIV的位置及大小
                var t = $b.position().top, l = $b.position().left;
                var w = $b.width(), h = $b.height();
                //順便調查總範圍
                var r = l + w, b = t + h;
                if (l < x1) x1 = l; if (r > x2) x2 = r;
                if (t < y1) y1 = t; if (b > y2) y2 = b;
                $b.data({
                    sn: i, ow: w, oh: h, ot: t, ol: l
                });
            }).each(function () {
                var $b = $(this);
                //換算為絕對座標
                $b.css({
                    "background-color": c[$b.data("sn")],
                    position: "absolute",
                    left: $b.data("ol") + "px",
                    top: $b.data("ot") + "px"
                });
            }).click(function () {
                var $b = $(this);
                var $others = $blocks.not(this);
                //動畫過程會有交疊,故設z-index讓被點選者在前,其餘在後
                $b.css("z-index", 9);
                $others.css("z-index", 0);
                //若已是放大狀態,縮回原大小
                if ($b.data("m") == "zoom") {
                    $b.animate({
                        width: $b.data("ow"), height: $b.data("oh"),
                        top: $b.data("ot"), left: $b.data("ol")
                    }, animDura, function () {
                        $b.data("m", "normal");
                    });
                    //淡出文字內容,顯現圖檔
                    $b.children("div").fadeOut(animDura * 0.1, function () {
                        $b.children("img").fadeIn(animDura * 0.9);
                    });
                    //動畫後期,其餘區塊開始顯現
                    $others.animate({ "opacity": 1 }, animDura / 2)
                    .fadeIn(animDura / 2);
                }
                else { //放大至佔滿全部範圍
                    $b.animate({
                        top: y1, left: x1,
                        width: x2 - x1, height: y2 - y1
                    }, animDura)
                    .data("m", "zoom");
                    //淡出圖檔, 顯現文字內容(晚一點才
                    $b.children("img").fadeOut(animDura * 0.9, function () {
                        $b.children("div").fadeIn(animDura * 0.1);
                    });
                    //以一半的動畫時間長度將其他區塊淡出
                    $others.fadeOut(animDura / 2);
                }
            });
        });
    </script>
</head>
<body>
<div id="container">
<div class="b">Block 1<br />
<img src="mountain.jpg" />
<div>
<p>最近要將一個大專案翻版成...略...</p>
</div></div>
<div class="b">Block 2</div>
<div class="b">Block 3</div>
<div class="b">Block 4</div>
<div class="b">Block 5</div>
<div class="b">Block 6</div>
</div>
</body>
</html>

與Silverlight相比,在流暢性及酷炫程度上差了一截,不過意思到了,呵!

我放了一個Live Demo,有興趣的人可以玩看看。


Comments

# by michael

你好,我是你的BLOG讀者 你的文章都很受用,學習了很多 這邊想請教你一個問題 你有甚麼措施可以保護你的程式 讓其他人沒辦法經由反組譯輕易取得你的CODE? 市面上有很多反組譯程式 試過了許多套,有好有壞 所以想問問你的做法 感謝

# by Jeffrey

to michael, 我工作的專案以ASP.NET為主,自己做的潛盾機傾向Open Source不怕人看,所以對程式碼防窺的研究很少(倒是常用Reflector研究別人的程式就是了)。市面上有不少.NET用的混淆器(Obfuscator),可以對.NET程式做特殊處理防止反組譯程式還原回原始碼,效果都不錯,但免費版及試用版防護程度多半很弱,真正要到實用地步,多半需要採購正式版(價格不低就是了)。用.NET + Obfuscator關鍵字查詢,應該就可以找到相關產品的資訊。

# by 您的Fans

to 黑暗大 您好, 我想請教的是 這個區塊式導覽可以放大縮小 那裡面的文字是否也可以一併放大縮小呢?? 我利用大大的範例在作練習 我在<div>裡面加了連結字串 那假如我要讓他也可以隨著點選而放大縮小 是否在code 裡面加入 $b.children("a").XXXXXXX 我買的書 羅子洋編著的 愛上jQuery 好像沒看到可以控制字型大小的 是否可以請黑暗大 再稍微指點一下呢?? 感謝

# by 您的Fans

to 黑暗大 抱歉打擾您寶貴的時間 小弟己經找到了 >////< 在您的放大及縮小的code碼裡面 各加上 // 設定初始化的文字大小 this.style.fontSize = '要顯現的大小'; 即可在點選時將字體放大縮小 ... 因為我覺得有人可能上了年紀眼睛會不好 所以才想要增加這個選項 感覺效果還不錯 ... 謝謝黑暗大的範例給我的啟發 ...

# by Jeffrey

to Fans同學,Good Job! this.style.fontSize在jQuery也可寫成$(this).css(fontSize, "10pt");,同時要設多個格式時還可以寫成$(this).css({ fontSize: "10pt", color: "red" });,還能更精簡,謹供參考。

# by 您的Fans

to 黑暗大 哦哦 !! 我不知道還能這樣子寫呢!! 受教 ... 另外 老大... 當div的資料太多時.. 剛開始Load進來的畫面 資料會超出div的範圍 但再點其它的div後, 它又會收回去該div裡面 ... 我有辦法讓它一開始的時候就全部收在div裡面 不會露出它的馬腳出來嘛 ?? 因為我還在看jQuery的code 不知道老大的判斷是寫在哪 呵呵 >"< 還看不到要怎麼樣馬腳才不會露出來的方法說 QQ

# by Jeffrey

to Fans同學,不太能理解露馬腳問題,看你能不能做個Bug Reproducer(茶包再生器)讓大家下載回去玩,好幫你研究看看。

# by 您的Fans

To 黑暗大 其實就是老大您的這個div裡面的東西而己 假如<div class="b">Block 2</div> 置換成 <div class="b"> <li>Test Rows</li> <li>Test Rows</li> <li>Test Rows</li> <li>Test Rows</li> <li>Test Rows</li> <li>Test Rows</li> <li>Test Rows</li> <li>Test Rows</li> <li>Test Rows</li> <li>Test Rows</li> <li>Test Rows</li> <li>Test Rows</li> <li>Test Rows</li> </div> 那一開始時, 超過div框架的li 就會露在框架外面 只要資料有多長, 他就露多長 但是只要點選其中一個框架讓它伸展之後再收合, 那些超過框架的資料就通通會縮回框架裡面 所以我才想請教老大, 如何在一開始就讓它縮在框架裡面不會露出來 因為我實在是不大想用假裝點選後再讓它縮回去的方式 請問老大 有可以直接讓它把超過框架的資料直接縮回框架的方法嘛? 謝謝 >"< ...

# by Jeffrey

to Fans, 我沒有試出"點選其中一個框架讓它伸展之後再收合,超過框架的資料就通通會縮回框架裡面"的情形,用IE8及FF測試,放大收合後都還是維持原來的樣子。不過針對內容超出框框的問題,我想應可用<div class="b" style="overflow: hidden">,加上overflow CSS設定解決。

# by 您的Fans

to 黑暗大 我是用IE7 的說 不過老大教的方法很有用 ... 己經解決了 AA" 太cool 了 感謝老大的指導 ...

# by VC

to 黑暗大 小弟是jQuery的新手 , 請問老大這種效果要怎麼應用在table上(包括各種元件) thanks

# by Jeffrey

to VC, 不是很確定你要呈現的效果,是否能提供更明確的描述或舉例? (改成放大Table中的<td>,而<td>內包含有很多HTML元素也要一起等比例放大?)

# by VC

to 黑暗大 謝謝黑暗大的回應, 不好意思,可能我說的不是很清楚 如果table中所有的元素(ex:文字,按鈕,圖片...等)也要跟著等比例放大,這樣會很複雜嗎~? 如果不用等比例放大會比較容易嗎? (這樣做的原因是想讓user能focus在table,確認table上資料是否正確後,再做一個submit的動作) 麻煩黑暗大解惑

# by Jeffrey

to VC, 等比例放大恐需要CSS的2D Scale Transform(http://www.w3schools.com/css3/css3_2dtransforms.asp),不難實現,但要留意舊版瀏覽器不支援的問題。若不要等比例放大,我想到的做法是放大Container元素(如<div><td>)的寬和高,其中的元件(含圖檔)也跟著調大寬高並放大字體,但看起來手續不少,也頗複雜就是了。

# by VC

to 黑暗大 謝謝你的回應和建議, 我已經做出來, 再做個調整就行了 你網站的文章資料很棒很實用!! 讓我獲益良多 ^^

# by Jeffrey

to VC, GJ! 恭喜閣下成功破關~~ 也歡迎你跟大家分享你的做法哦!

# by VC

to 黑暗大 離破關只差一步!! 我想問一個很笨的問題, 就這個例子來說,我想把click事件改成特定button觸發 程式要怎麼修改? 我怎麼試都沒辦法成功,麻煩黑暗大指導了 謝謝

# by Jeffrey

to VC, 我想可以寫成: $("#button_id").click(function() { var $table = $("#table_id"); //....操作$table實現放大效果.... });

Post a comment