项目简介

author: 水儿

这是一个理想中的店铺浏览项目,dream-shop ,页面展示如下所示:

http://img02.taobaocdn.com/tps/i2/T1kqtNXAXfXXXbps2S-1263-885.png

店铺页面是由一个个模块组成的,页面主要可以看到950布局下的店铺招牌和导航模块,还有190布局下的宝贝分类模块,及750布局下的宝贝推荐模块

这个项目是以淘宝旺铺的一个简化版和理想版,想通过这个项目的介绍让大家对基于kissy 1.3开发一个项目的过程,有一个直观的认识和参考, 也许你们能够做出更好的出来。 请 下载本示例的源代码 ,打开 dream-shop > src > demo > pages > index.php 查看效果。

目录组织

首先按照下图所示,创建该项目的目录结构

http://img01.taobaocdn.com/tps/i1/T1hQtzXsxgXXafEjcD-222-359.jpg

这些目录的用途如下: dream-shop - 项目名称 –.idea - 是idea工程自动生成的,忽略 – build-combo - 是项目组件打包后自动生成的目录 – src - 源码目录,存放项目源码 —- assets - 存放项目的资源文件 —— css - 存放项目样式文件 —— img - 存放项目图片 —— js - 存放项目脚本 —- demo - 存放项目的html – tools - 工具目录,存放项目项目中用到的工具包 —- kissy-tools - kissy complier结合ant合成的工具包 – build-js.xml - 用于打包的ant脚本 – dream-shop.iml - idea工程自动生成的,忽略 – readme.txt - 用于记录项目的基本信息, 如项目介绍,关键页面链接等。

编写项目组件

建立目录结构

项目组件的目录结构如下:

http://img01.taobaocdn.com/tps/i1/T1uhpzXttgXXXO4Zsa-278-281.jpg

说明:

– js —- shop - 组件的包名,比较重要(因为可能要被其他业务方引用),需要好好命名 —— mods - 该目录下存放的都是一个一个模块的脚本 —— widget - 该目录下存放一些共用的组件 —— init - 负责脚本的初始化逻辑

编写脚本

示例:店铺招牌模块的脚本

// 不用写组件名,打包后会自动生成
KISSY.add(function(S,Core){

    var S = KISSY, E = S.Event, D = S.DOM;

    // 构造器
    function TshopPbsmShopCustomBanner(context){
        var self = this;
        self._mod = context.mod;
        if(!self._mod) return;

        self._init();
    }

    // 方法
    S.augment(TshopPbsmShopCustomBanner,{
        _init: function(){
            S.log("TshopPbsmShopCustomBanner init start");
        }
    });
    TshopPbsmShopCustomBanner.selector = '.tshop-pbsm-shop-banner';
    return TshopPbsmShopCustomBanner;
    // 依赖的组件,可以是kissy的组件,也可以是本地的组件
},{requires:['core']});

模块初始化逻辑init.js

KISSY.ready(function(S){

   // 模块间的依赖关系
   /*Generated by KISSY Module Compiler*/
   KISSY.config('modules', {
   'shop/mods/item-cates': {requires: ['core']},
   'shop/mods/header': {requires: ['core','cookie','suggest','overlay','shop/widget/compatible']},
   'shop/mods/custom-banner': {requires: ['core']},
   'shop/widget/compatible': {requires: ['core']},
   'shop/mods/item-recommend': {requires: ['core','shop/widget/compatible']},
   'shop/mods/nav': {requires: ['core','overlay','shop/widget/compatible']}
   });

   // 包配置
   S.config(
        {
            combine: true,  // 是否开启combo模式
            debug: true,     // 是否开启debug模式
            packages:[
                {
                    name:"shop",                       //包名
                    tag:"20130131",                   //时间戳, 添加在动态脚本路径后面, 用于更新包内模块代码
                    path: "../../../build-combo/",   //包对应路径, 相对路径指相对于当前页面路径
                    charset:"utf-8"                      //包里模块文件编码格式
                }
            ]
        }
   );

   // 页面实际存在的模块,由开发给出
    var mods = window.shop_config.mods;

   // 获取需要use的模块名称数字
    var comboMods = [];

     for(var i=0; i<mods.length; i++){
         comboMods.push("shop/mods/"+mods[i]);
     }

    // 把需要use的模块放在一起一次use,这样这些模块的js脚本就会combo请求,只会有一个请求
     S.use(comboMods,function(S){
         var args = S.makeArray(arguments).slice(1);
         S.each(args, function(mod){
             new mod({mod: S.DOM.get("#page " + mod.selector)});
         })
     });

});

打包

方式一:打包可以用ant结合kissy 1.3打包工具KISSY Module Compiler 方式二:利用kissy pie,对1.3的支持正在开发中

下面介绍一下idea下ant结合kissy 1.3打包工具KISSY Module Compiler的步骤.

使用ant打包

第一步:编写ant打包脚本

<!--
build example for kissy loader
@author yiminghe@gmail.com
-->
<project name="js.build" default="build" basedir="." xmlns:ac="antlib:net.sf.antcontrib">

    <!--入口文件模块所在目录-->
    <dirname property="current.dir" file="${ant.file.compressor.build}"/>
    <property name="assets.dir" location="${current.dir}/src/assets/js/"/>
    <property name="build.dir" location="${current.dir}/build-combo/"/>

    <!--项目文件编码-->
    <property name="charset" value="utf-8"/>

    <!-- kissy tools 项目源码目录 -->
    <!-- 注意:请用 kissy tools 中的 ant 运行此 xml -->
     <property name="ks.tools" value="${current.dir}/tools/kissy-tools"/>

    <property name="module.compiler" value="${ks.tools}\module-compiler\module-compiler.jar"/>
    <property name="yui.compiler" value="${ks.tools}\yuicompressor\yuicompressor.jar"/>

    <!-- js 构建-->
    <target name='jsrun' depends="combo">
    </target>

    <target name='prepare'>
        <mkdir dir="${build.dir}"></mkdir>
        <delete>
            <fileset dir="${build.dir}" includes="**/*.js"/>
        </delete>
        <copy encoding="${charset}" todir="${build.dir}">
            <fileset dir="${assets.dir}" includes="**/*"/>
        </copy>
    </target>

    <!--js  combo 地址获取-->
    <target name='combo' depends="prepare">
        <java classname="com.taobao.f2e.ExtractDependency">
            <arg value="-baseUrls"/>
            <arg value="${build.dir}"/>

            <arg value="-encodings"/>
            <arg value="${charset}"/>

            <arg value="-outputEncoding"/>
            <arg value="utf-8"/>

            <arg value="-output"/>
            <arg value="${build.dir}/deps.js"/>

            <arg value="-fixModuleName"/>
            <!--自动 combo 需要补全文件名-->
            <arg value="true"/>

            <classpath>
                <pathelement path="${module.compiler}"/>
                <pathelement path="${java.class.path}"/>
            </classpath>
        </java>
    </target>

     <!-- 用 YUICompressor 压缩 CSS,JS -->
    <target name="compress">
        <apply executable="java" verbose="true" dest="${build.dir}">
            <fileset dir="${build.dir}" includes="**/*.js"/>
            <arg line="-jar"/>
            <arg path="${yui.compiler}"/>
            <arg line="--charset ${charset}"/>
            <srcfile/>
            <arg line="-o"/>
            <targetfile/>
            <mapper type="regexp" from="^(.*)\.(css|js)$" to="\1-min.\2"/>
        </apply>
    </target>
    <!-- END OF 用YUICompressor 压缩 CSS -->

    <!-- 对 JS 文件 ASCII 化 -->
    <target name="native2ascii"  depends="compress">
        <mkdir dir="${build.dir}/tmp"/>
        <copy todir="${build.dir}/tmp">
            <fileset dir="${build.dir}"/>
        </copy>
        <native2ascii encoding="${charset}"
                      src="${build.dir}/tmp/"
                      dest="${build.dir}"
                      includes="**/*-min.js">
        </native2ascii>
        <delete dir="${build.dir}/tmp"/>
    </target>

    <!--项目(js,css)构建-->
    <target name="build" depends="jsrun,compress,native2ascii"/>

</project>

第二步:选择打包的脚本xml

http://img03.taobaocdn.com/tps/i3/T1Nt0OXppcXXaL7K.U-762-578.jpg

第三步:配置打包的ant环境

http://img03.taobaocdn.com/tps/i3/T1HtpMXAFiXXae06Tn-811-651.jpg http://img01.taobaocdn.com/tps/i1/T1swNOXE0aXXXPaJZW-900-664.jpg http://img04.taobaocdn.com/tps/i4/T1RvJOXz0bXXcRejYn-808-649.jpg

打包后的目录如下

http://img01.taobaocdn.com/tps/i1/T12NXBXEBaXXbQbQ7o-317-517.jpg

说明:其中deps.js是模块之间的依赖关系 查看模块打包后的脚本

KISSY.add("shop/mods/custom-banner", function(S, Core) {
  var S = KISSY, E = S.Event, D = S.DOM;
  function TshopPbsmShopCustomBanner(context) {
    var self = this;
    self._mod = context.mod;
    if(!self._mod) {
      return
    }
    self._init()
  }
  S.augment(TshopPbsmShopCustomBanner, {_init:function() {
    S.log("TshopPbsmShopCustomBanner init start")
  }});
  TshopPbsmShopCustomBanner.selector = ".tshop-pbsm-shop-banner";
  return TshopPbsmShopCustomBanner
}, {requires:["core"]});

查看依赖关系

/*Generated by KISSY Module Compiler*/
KISSY.config('modules', {
'shop/mods/item-cates': {requires: ['core']},
'shop/mods/header': {requires: ['core','cookie','suggest','overlay','shop/widget/compatible']},
'shop/mods/custom-banner': {requires: ['core']},
'shop/widget/compatible': {requires: ['core']},
'shop/mods/item-recommend': {requires: ['core','shop/widget/compatible']},
'shop/mods/nav': {requires: ['core','overlay','shop/widget/compatible']}
});

实际的脚本请求

http://img03.taobaocdn.com/tps/i3/T1vOxNXpBeXXc7ctbS-934-291.jpg

从上图可以看出,页面脚本请求: - seed.js - switchable, overlay等组件combo在一起的url - init.js 页面初始化脚本 - nav.js, header.js等模块脚本combo在一起的url

编写项目dpl

项目dpl 有使用less(使用参考:http://www.lesscss.net/),其实还有sass可选(具体使用请参考:http://sass-lang.com/) 在正式编码之前,我们常常需要抽象出一个项目页面中共同的视觉元素,如盒子。 如宝贝分类和宝贝推荐模块的盒子颜色,如下图所示

如mixins/default.less里面这段用less写的盒子模型到dpl

.skin-box-default(){
    margin-bottom: 10px;
    .clearfix;    /* 在模块最外层添加清除浮动的样式,避免ie6下装修时,模块高度发生改变,模块之间错位的问题发生 */
    .hidden{
        visibility: hidden;
    }
    .disappear{
       display: none;
    }
    .skin-box-hd{
        border-width: @hd-border-width;
        border-color: @hd-border-color;
        border-style: @hd-border-style;
        background: @hd-background;
        padding: @hd-paddding;
        h3 span{
           border-bottom: @title-border-width @title-border-style @title-border-color;
           display: inline-block;

           font-weight: @title-font-weight;
           font-size: @title-font-size;
           color: @title-font-color;
        }
    }
    .skin-box-bd{
        .clearfix;
        border-color: @bd-border-color;
        border-width: @bd-border-width;
        border-style: @bd-border-style;

        background: @bd-background;

        color: @font-color;
        a{
           color: @font-color;
        }
    }
}

使用less来打包各个模块的皮肤

使用less的@import把所有模块的皮肤打包到一起,形成一个完整的模板皮肤

http://img04.taobaocdn.com/tps/i4/T1TbdOXENbXXaDgpvo-674-314.jpg

编写项目demo

编写模块html

<div class="J_TModule">
    <div class="skin-box tb-module tshop-pbsm tshop-pbsm-shop-item-recommend">
        <div class="skin-box-hd">
            <i class="hd-icon"></i>
            <h3>
                <span>宝贝推荐 【950布局下一行显示4个-230】</span>
            </h3>
            <div class="skin-box-act">
                <a class="more" href="http://shop51186914.daily.taobao.net/list.htm?search=y&amp;orderType=coefp_desc">更多&gt;</a>
            </div>
        </div>
        <input type="hidden"
               value="http://rate.daily.taobao.net/batch_query_rate.htm?sellerId=45092523&amp;itemIds=1500012736005,1500012553329&amp;source=shop"
               class="J_TItemRatesUrl">
        <div class="skin-box-bd">
            <div class="item4line1">
                <dl class="item">
                    <dt class="photo">
                        <a href="#">
                            <img src="http://img02.taobaocdn.com/bao/uploaded/i2/T1xga_XctoXXbWHc6a_120455.jpg">
                        </a>
                    </dt>
                    <dd class="detail">
                        <a href="#" class="item-name">宝贝描述宝贝描述 宝贝描述宝贝描述 宝贝描述宝贝描述 宝贝描述宝贝描述 </a>
                        <div class="attribute">
                            <div class="cprice-area">
                                <span class="symbol">&yen;</span><span class="c-price">256.00</span>
                            </div>
                            <div class="sprice-area">
                                <span class="symbol">&yen;</span><span class="s-price">256.00</span>
                            </div>
                            <div class="sale-area">
                                已售:<span class="sale-num">207</span></div>
                        </div>
                    </dd>
                    <dd class="rates">
                        <div class="title">
                            <h4>
                                评论(<span>1566</span>)
                            </h4>
                            <a href="#">更多&gt;</a>
                        </div>
                        <p class="rate J_TRate">
                            一条评论,最多36个汉字,超出部分截断一条评论,最多36个汉字,超出部分截断
                        </p>
                    </dd>
                </dl>
            </div>
        </div>
    </div>
</div>

编写页面html,并调用模块的html

<!doctype html>
<html>
<head>
    <meta charset="gbk"/>
    <meta name="keywords" content="淘宝, 店铺, 旺铺, 店铺名"/>
    <meta name="description" content="欢迎前来淘宝网某某旺铺,选购某某商品,想了解更多某某商品,请进入某某旺铺,众多商品任你选购"/>
    <title>首页-c测试账号152店铺-test-网店/网络服务/软件- 淘宝网 </title>
    <script>
        window.g_hb_monitor_st = +new Date();
        window.g_config = {appId: 2, assetsHost: "http://assets.daily.taobao.net", toolbar: false, pageType: "wangpu"};
        window.shop_config = {};
        window.shop_config.mods = ["header", "custom-banner", "nav", "item-cates", "item-recommend"];
    </script>
    <link rel="shortcut icon" href="http://www.taobao.com/favicon.ico" type="image/x-icon"/>
    <link rel="stylesheet" href="http://a.tbcdn.cn/??p/global/1.0/global-min.css?t=20120528.css"/>
    <link rel="stylesheet" href="http://assets.daily.taobao.net/apps/taesite/platinum/stylesheet/??view/layout-min.css"/>
    <link rel="stylesheet" href="../../assets/css/skin/default.css"/>
    <link rel="stylesheet" href="../../assets/css/skin/yellow.css"/>
    <script  src="http://assets.daily.taobao.net/??s/kissy/1.3.0/seed-min.js,p/global/1.0/global-min.js?t=20121127.js"></script>

</head>
<body>
<input type="hidden" id="J_TSelectedMenuInfo" value='{"selectedMenu":{"pageId":"1", "catId": "" , "linkId":""}}'>
<input type="hidden" value="21XUxjAl" name="tb_token" id="J_TokenField"/>

<div id="page">
<!-- 系统页头 -->
<?@include '../mods/header.php'?>
<div id="content" class="tb-shop">
    <div id="hd">
        <div class="layout grid-m0" data-id="5234984" data-prototypeid="1">
            <div class="col-main">
                <div class="main-wrap J_TRegion" data-modules="main" data-width="950">
                    <!-- your mod html goes here -->
                    <?@include '../mods/custom-banner.php'?>
                    <?@include '../mods/nav.php'?>
                </div>
            </div>
        </div>
    </div>
    <div id="bd">
        <div class="layout grid-s5m0" data-id="5022284" data-prototypeid="2">
            <div class="col-main">
                <div class="main-wrap J_TRegion" data-modules="main" data-width="b750">
                    <?@include '../mods/item-recommend.php'?>
                </div>
            </div>
            <div class="col-sub J_TRegion" data-modules="sub" data-width="b190">
                <?@include '../mods/item-cates.php'?>
            </div>
        </div>
    </div>
    <div id="ft">
        <div class="layout grid-m0" data-id="5234984" data-prototypeid="1">
            <div class="col-main">
                <div class="main-wrap J_TRegion" data-modules="main" data-width="950">
                </div>
            </div>
        </div>
    </div>
</div>

</div>

<script src="../../../build-combo/shop/init.js"></script>

</body>
</html>

插入页面级的css

<link rel="stylesheet" href="http://a.tbcdn.cn/??p/global/1.0/global-min.css?t=20120528.css"/>
<link rel="stylesheet" href="http://assets.daily.taobao.net/apps/taesite/platinum/stylesheet/??view/layout-min.css"/>
<link rel="stylesheet" href="../../assets/css/skin/default.css"/>
<link rel="stylesheet" href="../../assets/css/skin/yellow.css"/>

引入页面级的js

<script  src="http://assets.daily.taobao.net/??s/kissy/1.3.0/seed-min.js,p/global/1.0/global-min.js?t=20121127.js"></script>
<script src="../../../build-combo/shop/init.js"></script>

编写readme

http://img02.taobaocdn.com/tps/i2/T10ApMXrpfXXcXi3Te-670-459.jpg