├── .gitignore ├── README.md ├── example ├── dev │ ├── css │ │ └── index.css │ ├── img │ │ ├── 1.jpg │ │ ├── 2.jpg │ │ ├── 3.jpg │ │ ├── 4.jpg │ │ ├── 5.jpg │ │ ├── bg.png │ │ ├── icon_login.png │ │ ├── icon_share.png │ │ ├── pointer.png │ │ ├── sohulogo.jpg │ │ └── start.png │ ├── index.html │ ├── js │ │ └── index.js │ └── perf.html ├── dist │ ├── css │ │ └── index.css │ ├── img │ │ ├── 0.jpg │ │ ├── 1.jpg │ │ ├── 2.jpg │ │ ├── 3.jpg │ │ ├── 4.jpg │ │ ├── 5.jpg │ │ ├── bg.png │ │ ├── icon_login.png │ │ ├── icon_share.png │ │ ├── pointer.png │ │ ├── sohulogo.jpg │ │ └── start.png │ ├── index.html │ ├── js │ │ └── index.js │ └── perf.html └── src │ ├── _lib │ ├── js │ │ └── share.js │ └── scss │ │ └── ani │ │ ├── ani_circle.scss │ │ ├── ani_loading.scss │ │ └── ani_spinner.scss │ ├── css │ ├── base │ │ └── base.scss │ ├── index.scss │ └── index │ │ ├── carousel.scss │ │ ├── flip.scss │ │ ├── piccut.scss │ │ ├── picpager.scss │ │ ├── scratchcard.scss │ │ ├── scroll.scss │ │ ├── share.scss │ │ ├── sidebox.scss │ │ ├── turntable.scss │ │ └── ui.scss │ ├── gulpfile.js │ ├── html │ ├── base │ │ ├── header.html │ │ └── navbar.html │ └── index │ │ ├── carousel.html │ │ ├── flip.html │ │ ├── home.html │ │ ├── piccut.html │ │ ├── picpager.html │ │ ├── scratchcard.html │ │ ├── scroll.html │ │ ├── share.html │ │ ├── sidebox.html │ │ ├── sub.html │ │ ├── sub2.html │ │ ├── turntable.html │ │ └── ui.html │ ├── img │ ├── 1.jpg │ ├── 2.jpg │ ├── 3.jpg │ ├── 4.jpg │ ├── 5.jpg │ ├── bg.png │ ├── icon_login.png │ ├── icon_share.png │ ├── pointer.png │ ├── sohulogo.jpg │ └── start.png │ ├── index.html │ ├── js │ ├── index.js │ └── index │ │ ├── carousel.js │ │ ├── flip.js │ │ ├── home.js │ │ ├── piccut.js │ │ ├── picpager.js │ │ ├── scratchcard.js │ │ ├── scroll.js │ │ ├── share.js │ │ ├── turntable.js │ │ └── ui.js │ ├── package.json │ └── perf.html ├── jq.js ├── jqlite.js ├── plugin ├── alert.js ├── alert.scss ├── carousel.js ├── carousel.scss ├── dialog.js ├── dialog.scss ├── flip.js ├── flip.scss ├── piccut.js ├── piccut.scss ├── picpager.js ├── picpager.scss ├── scratchcard.js ├── scroll.js ├── scroll.scss ├── scrollto.js ├── swatchbook.js ├── swatchbook.scss ├── turntable.js └── turntable.scss ├── scss └── var.scss └── ui ├── base.js ├── base.scss ├── body_scroll.scss ├── ui.js └── ui.scss /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | **/node_modules/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # jq.js 2 | jq.js is a javascript library like jQuery lite for modern browsers, faster and lighter(3.2KB compressed and gzip) than zepto.js. 3 | 4 | For detail view [demo](http://soneway.github.io/jq/example/dist/) -------------------------------------------------------------------------------- /example/dev/img/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soneway/jq/74ac0a9f0711e825b2abcb289b96d51d5e4601cc/example/dev/img/1.jpg -------------------------------------------------------------------------------- /example/dev/img/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soneway/jq/74ac0a9f0711e825b2abcb289b96d51d5e4601cc/example/dev/img/2.jpg -------------------------------------------------------------------------------- /example/dev/img/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soneway/jq/74ac0a9f0711e825b2abcb289b96d51d5e4601cc/example/dev/img/3.jpg -------------------------------------------------------------------------------- /example/dev/img/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soneway/jq/74ac0a9f0711e825b2abcb289b96d51d5e4601cc/example/dev/img/4.jpg -------------------------------------------------------------------------------- /example/dev/img/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soneway/jq/74ac0a9f0711e825b2abcb289b96d51d5e4601cc/example/dev/img/5.jpg -------------------------------------------------------------------------------- /example/dev/img/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soneway/jq/74ac0a9f0711e825b2abcb289b96d51d5e4601cc/example/dev/img/bg.png -------------------------------------------------------------------------------- /example/dev/img/icon_login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soneway/jq/74ac0a9f0711e825b2abcb289b96d51d5e4601cc/example/dev/img/icon_login.png -------------------------------------------------------------------------------- /example/dev/img/icon_share.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soneway/jq/74ac0a9f0711e825b2abcb289b96d51d5e4601cc/example/dev/img/icon_share.png -------------------------------------------------------------------------------- /example/dev/img/pointer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soneway/jq/74ac0a9f0711e825b2abcb289b96d51d5e4601cc/example/dev/img/pointer.png -------------------------------------------------------------------------------- /example/dev/img/sohulogo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soneway/jq/74ac0a9f0711e825b2abcb289b96d51d5e4601cc/example/dev/img/sohulogo.jpg -------------------------------------------------------------------------------- /example/dev/img/start.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soneway/jq/74ac0a9f0711e825b2abcb289b96d51d5e4601cc/example/dev/img/start.png -------------------------------------------------------------------------------- /example/dev/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 模板页面 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 |
22 | 23 | 24 |  25 | 44 | 45 | 46 | 47 | 48 |
49 |

jq.js是适用于现代浏览器的简化版jQuery,体积比zepto小(是其1/4),效率比zepto高(是其2倍左右),兼容jquery语法,实现大多常用api.

50 | 56 |
57 | 58 |  59 |
60 |

ui.js是一个ui框架,包含页面切换,边栏,弹出框,导航栏等功能

61 | 81 |
82 | 83 |  84 | 95 | 96 |  97 |
98 |

flip.js插件适合有限张图片3d切换展示,除了图片,还适用于普通html容器

99 |

横向切换

100 |
101 |
102 |

竖向切换

103 |
104 |
105 |
106 | 107 |  108 |
109 |

picpager.js插件适合无限张图片切换展示,可动态添加图片数据

110 |
111 |
112 |
113 | 114 |  115 |
116 |
117 |
118 | 119 | 裁剪 120 | 121 |
122 | 123 | 124 |
125 |

scroll.js用于模拟页面滚动效果,本DEMO中的可滚动的导航栏就是用该插件实现

126 |

竖向滚动

127 |
128 |
129 | 今年夏季,海鲜品类的持续走红,给很多餐饮企业在产品研发方面提供了新思路。以重油重辣炒料加工的海鲜类拼锅成为消费者和餐饮企业热捧的新宠。然而,日前发生在金掌勺东北菜广渠门店的消费者食用海鲜拼锅后患肠胃炎的事件为今夏食品安全敲响了警钟。有业内人士分析认为,海鲜类爆品固然能为餐厅带来可观的收益,但同时,海鲜类时令性较强且新鲜度要求较高,也是食品安全的隐患所在。 130 | 131 | 事件起因 132 | 133 | 一家五口疑似被“海鲜大咖”放倒 134 | 135 | 6月13日傍晚,网友梦幻少女有人爱发微博称其一家7口在金掌勺东北菜广渠门店食用过店内的“海鲜大咖”后,有5人出现上吐下泻的症状,经医院诊断,5人均患上急性肠胃炎,疑似食物中毒。同时发出当日食用的“海鲜大咖”照片、医院诊断说明,以及与商家负责人后期沟通过程中的照片。 136 | 137 | 北京商报记者随即联系到当事人消费者崔女士,崔女士表示,他们一行7人于6月11日晚间在金掌勺东北菜广渠门店进行家庭聚会,并于到店2天前预定了金掌勺家售价为499元的“海鲜大咖”,在用餐过程中还加点了店内的其他少量特色菜品,以及酸梅汤、啤酒等饮品。 138 | 139 | 次日清晨,崔女士感到肠胃不适,并出现呕吐和腹泻、腹痛的症状,在联系前日共同进餐的家人后得知,崔女士一行7人,除了2位没有食用“海鲜大咖”的消费者外,剩下5人均出现了类似情况,崔女士随即与家人前往宣武医院就诊,被主治医生诊断为急性肠胃炎,经过输液等相关治疗后,崔女士一行人的症状有所缓解。 140 | 141 | 记者调查 142 | 143 | 双方各执一词协商未果 144 | 145 | 根据崔女士提供的线索,北京商报记者随即电话联系到金掌勺广渠门店,该店负责人表示,“海鲜大咖”是金掌勺于去年夏天推出的海鲜拼锅产品,根据用料及分量差异分为299元、499元以及799元三档,其中价格499元的“海鲜大咖”销量最高。据该负责人介绍,“海鲜大咖”自上线以来颇受消费者欢迎,其中499元的“海鲜大咖”中包括:螃蟹、鲍鱼、扇贝、蚬子、烤鱼等多种海鲜类产品,经过加工处理后做成海鲜拼锅。该负责人回忆,崔女士一行人到店消费时,店内有超过200位消费者在用餐,当天售出的“海鲜大咖”超过20份。由于崔女士一行人还点了酸梅汤、啤酒等饮品,店内相关服务人员还提醒过崔女士在食用海鲜后应慎重食用含有VC的食物或刺激性饮料。此外,除了崔女士一行人出现了在食用“海鲜大咖”后引发急性肠胃炎的情况,并没有收到当天其他消费者的类似投诉。 146 | 147 | 但在北京商报记者向崔女士核实金掌勺广渠门店负责人所述信息时,崔女士却表示,当日一同用餐后出现肠胃不适的5人中有2人因开车并未饮用啤酒,此外,在点餐后,也没有服务人员提示他们不能在食用海鲜的同时饮用含有VC的酸梅汤。她同时表示,在她发出微博并被网友转发后,还有2位自称是当天到店食用过“海鲜大咖”的消费者向崔女士表示也出现了肠胃不适的症状,并提供了当天到店的消费证明。 148 | 149 | 截至北京商报记者发稿前,双方仍在就该事件进行协商处理,金掌勺也于6月14日在其微博上发布声明,称已成立了相关调查小组对该事件进行调查,愿意承担崔女士一家人因此而产生的医疗及检查费用。崔女士则表示,希望能够通过相关渠道维护自身利益。 150 | 151 | 事件总结 152 | 153 | 海鲜品类是把双刃剑 154 | 155 | 对此有业内人士认为,夏季是海鲜等产品的销售旺季,尤其是近两年,餐饮行业向大众化转型的过程中破除了海鲜类产品曾经的高端定位壁垒,将海鲜类以多样的形式呈献给大众消费人群。但是,海鲜类产品对于食材的新鲜度要求更高,餐饮企业应当在采购海鲜类食材的过程中更加注重食材的质量,并根据销量调整采购数量,以防出现食材积压的情况。此外,海鲜的走红已然让供应链成为商家的必争之地,但就目前而言,海鲜的供应链仍存在不完善的地方,餐饮企业在选择供应商的时候应更加慎重。 156 | 157 | 另据一位不愿透露姓名的餐厅负责人介绍,相比蔬菜、粮油,海鲜类产品的供应链更加冗长复杂,不够透明,这就为食品安全埋下了隐患,商家为迎合消费者的口味喜好,通常加工海鲜类产品时会加上重油重辣的辅料,遮盖了食材本身的味道,消费者在食用过程中也不易察觉所食用的海鲜是否新鲜。 158 | 159 | 中国烹饪协会在日前公布今年5月全国餐饮收入数据时表示,随着入夏温度升高,消费者对于餐饮服务的种类选择也发生一定变化。餐饮企业应避免夏季食品安全问题发生,及时调整菜品结构,对风险食品、风险环节采取预防措施,以优质服务迎合消费需求。 160 | 今年夏季,海鲜品类的持续走红,给很多餐饮企业在产品研发方面提供了新思路。以重油重辣炒料加工的海鲜类拼锅成为消费者和餐饮企业热捧的新宠。然而,日前发生在金掌勺东北菜广渠门店的消费者食用海鲜拼锅后患肠胃炎的事件为今夏食品安全敲响了警钟。有业内人士分析认为,海鲜类爆品固然能为餐厅带来可观的收益,但同时,海鲜类时令性较强且新鲜度要求较高,也是食品安全的隐患所在。 161 | 162 | 事件起因 163 | 164 | 一家五口疑似被“海鲜大咖”放倒 165 | 166 | 6月13日傍晚,网友梦幻少女有人爱发微博称其一家7口在金掌勺东北菜广渠门店食用过店内的“海鲜大咖”后,有5人出现上吐下泻的症状,经医院诊断,5人均患上急性肠胃炎,疑似食物中毒。同时发出当日食用的“海鲜大咖”照片、医院诊断说明,以及与商家负责人后期沟通过程中的照片。 167 | 168 | 北京商报记者随即联系到当事人消费者崔女士,崔女士表示,他们一行7人于6月11日晚间在金掌勺东北菜广渠门店进行家庭聚会,并于到店2天前预定了金掌勺家售价为499元的“海鲜大咖”,在用餐过程中还加点了店内的其他少量特色菜品,以及酸梅汤、啤酒等饮品。 169 | 170 | 次日清晨,崔女士感到肠胃不适,并出现呕吐和腹泻、腹痛的症状,在联系前日共同进餐的家人后得知,崔女士一行7人,除了2位没有食用“海鲜大咖”的消费者外,剩下5人均出现了类似情况,崔女士随即与家人前往宣武医院就诊,被主治医生诊断为急性肠胃炎,经过输液等相关治疗后,崔女士一行人的症状有所缓解。 171 | 172 | 记者调查 173 | 174 | 双方各执一词协商未果 175 | 176 | 根据崔女士提供的线索,北京商报记者随即电话联系到金掌勺广渠门店,该店负责人表示,“海鲜大咖”是金掌勺于去年夏天推出的海鲜拼锅产品,根据用料及分量差异分为299元、499元以及799元三档,其中价格499元的“海鲜大咖”销量最高。据该负责人介绍,“海鲜大咖”自上线以来颇受消费者欢迎,其中499元的“海鲜大咖”中包括:螃蟹、鲍鱼、扇贝、蚬子、烤鱼等多种海鲜类产品,经过加工处理后做成海鲜拼锅。该负责人回忆,崔女士一行人到店消费时,店内有超过200位消费者在用餐,当天售出的“海鲜大咖”超过20份。由于崔女士一行人还点了酸梅汤、啤酒等饮品,店内相关服务人员还提醒过崔女士在食用海鲜后应慎重食用含有VC的食物或刺激性饮料。此外,除了崔女士一行人出现了在食用“海鲜大咖”后引发急性肠胃炎的情况,并没有收到当天其他消费者的类似投诉。 177 | 178 | 但在北京商报记者向崔女士核实金掌勺广渠门店负责人所述信息时,崔女士却表示,当日一同用餐后出现肠胃不适的5人中有2人因开车并未饮用啤酒,此外,在点餐后,也没有服务人员提示他们不能在食用海鲜的同时饮用含有VC的酸梅汤。她同时表示,在她发出微博并被网友转发后,还有2位自称是当天到店食用过“海鲜大咖”的消费者向崔女士表示也出现了肠胃不适的症状,并提供了当天到店的消费证明。 179 | 180 | 截至北京商报记者发稿前,双方仍在就该事件进行协商处理,金掌勺也于6月14日在其微博上发布声明,称已成立了相关调查小组对该事件进行调查,愿意承担崔女士一家人因此而产生的医疗及检查费用。崔女士则表示,希望能够通过相关渠道维护自身利益。 181 | 182 | 事件总结 183 | 184 | 海鲜品类是把双刃剑 185 | 186 | 对此有业内人士认为,夏季是海鲜等产品的销售旺季,尤其是近两年,餐饮行业向大众化转型的过程中破除了海鲜类产品曾经的高端定位壁垒,将海鲜类以多样的形式呈献给大众消费人群。但是,海鲜类产品对于食材的新鲜度要求更高,餐饮企业应当在采购海鲜类食材的过程中更加注重食材的质量,并根据销量调整采购数量,以防出现食材积压的情况。此外,海鲜的走红已然让供应链成为商家的必争之地,但就目前而言,海鲜的供应链仍存在不完善的地方,餐饮企业在选择供应商的时候应更加慎重。 187 | 188 | 另据一位不愿透露姓名的餐厅负责人介绍,相比蔬菜、粮油,海鲜类产品的供应链更加冗长复杂,不够透明,这就为食品安全埋下了隐患,商家为迎合消费者的口味喜好,通常加工海鲜类产品时会加上重油重辣的辅料,遮盖了食材本身的味道,消费者在食用过程中也不易察觉所食用的海鲜是否新鲜。 189 | 190 | 中国烹饪协会在日前公布今年5月全国餐饮收入数据时表示,随着入夏温度升高,消费者对于餐饮服务的种类选择也发生一定变化。餐饮企业应避免夏季食品安全问题发生,及时调整菜品结构,对风险食品、风险环节采取预防措施,以优质服务迎合消费需求。 191 |
192 |
193 |

横向滚动

194 |
195 |
196 |
197 |
198 | 199 | 200 |
201 |
202 |
203 | 204 |  205 |
206 |

turntable.js是一个简单的转盘抽奖特效

207 |
208 | 209 |
210 |
211 | 212 | 213 | 214 | 215 |  216 |
217 |
218 | 跳转到三级页面 219 |
220 |
221 | 222 |  223 |
224 |
225 | 三级页面内容 226 |
227 |
228 | 229 | 230 |
231 | 232 |

233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 |

242 | 243 |
244 | 245 | 246 | 247 |  248 | 263 | 264 | 265 |
266 | 267 | 268 | 269 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | -------------------------------------------------------------------------------- /example/dist/img/0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soneway/jq/74ac0a9f0711e825b2abcb289b96d51d5e4601cc/example/dist/img/0.jpg -------------------------------------------------------------------------------- /example/dist/img/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soneway/jq/74ac0a9f0711e825b2abcb289b96d51d5e4601cc/example/dist/img/1.jpg -------------------------------------------------------------------------------- /example/dist/img/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soneway/jq/74ac0a9f0711e825b2abcb289b96d51d5e4601cc/example/dist/img/2.jpg -------------------------------------------------------------------------------- /example/dist/img/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soneway/jq/74ac0a9f0711e825b2abcb289b96d51d5e4601cc/example/dist/img/3.jpg -------------------------------------------------------------------------------- /example/dist/img/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soneway/jq/74ac0a9f0711e825b2abcb289b96d51d5e4601cc/example/dist/img/4.jpg -------------------------------------------------------------------------------- /example/dist/img/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soneway/jq/74ac0a9f0711e825b2abcb289b96d51d5e4601cc/example/dist/img/5.jpg -------------------------------------------------------------------------------- /example/dist/img/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soneway/jq/74ac0a9f0711e825b2abcb289b96d51d5e4601cc/example/dist/img/bg.png -------------------------------------------------------------------------------- /example/dist/img/icon_login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soneway/jq/74ac0a9f0711e825b2abcb289b96d51d5e4601cc/example/dist/img/icon_login.png -------------------------------------------------------------------------------- /example/dist/img/icon_share.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soneway/jq/74ac0a9f0711e825b2abcb289b96d51d5e4601cc/example/dist/img/icon_share.png -------------------------------------------------------------------------------- /example/dist/img/pointer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soneway/jq/74ac0a9f0711e825b2abcb289b96d51d5e4601cc/example/dist/img/pointer.png -------------------------------------------------------------------------------- /example/dist/img/sohulogo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soneway/jq/74ac0a9f0711e825b2abcb289b96d51d5e4601cc/example/dist/img/sohulogo.jpg -------------------------------------------------------------------------------- /example/dist/img/start.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soneway/jq/74ac0a9f0711e825b2abcb289b96d51d5e4601cc/example/dist/img/start.png -------------------------------------------------------------------------------- /example/dist/index.html: -------------------------------------------------------------------------------- 1 | 模板页面

jq.js是适用于现代浏览器的简化版jQuery,体积比zepto小(是其1/4),效率比zepto高(是其2倍左右),兼容jquery语法,实现大多常用api.

ui.js是一个ui框架,包含页面切换,边栏,弹出框,导航栏等功能

flip.js插件适合有限张图片3d切换展示,除了图片,还适用于普通html容器

横向切换

竖向切换

picpager.js插件适合无限张图片切换展示,可动态添加图片数据

裁剪

scroll.js用于模拟页面滚动效果,本DEMO中的可滚动的导航栏就是用该插件实现

竖向滚动

今年夏季,海鲜品类的持续走红,给很多餐饮企业在产品研发方面提供了新思路。以重油重辣炒料加工的海鲜类拼锅成为消费者和餐饮企业热捧的新宠。然而,日前发生在金掌勺东北菜广渠门店的消费者食用海鲜拼锅后患肠胃炎的事件为今夏食品安全敲响了警钟。有业内人士分析认为,海鲜类爆品固然能为餐厅带来可观的收益,但同时,海鲜类时令性较强且新鲜度要求较高,也是食品安全的隐患所在。 事件起因 一家五口疑似被“海鲜大咖”放倒 6月13日傍晚,网友梦幻少女有人爱发微博称其一家7口在金掌勺东北菜广渠门店食用过店内的“海鲜大咖”后,有5人出现上吐下泻的症状,经医院诊断,5人均患上急性肠胃炎,疑似食物中毒。同时发出当日食用的“海鲜大咖”照片、医院诊断说明,以及与商家负责人后期沟通过程中的照片。 北京商报记者随即联系到当事人消费者崔女士,崔女士表示,他们一行7人于6月11日晚间在金掌勺东北菜广渠门店进行家庭聚会,并于到店2天前预定了金掌勺家售价为499元的“海鲜大咖”,在用餐过程中还加点了店内的其他少量特色菜品,以及酸梅汤、啤酒等饮品。 次日清晨,崔女士感到肠胃不适,并出现呕吐和腹泻、腹痛的症状,在联系前日共同进餐的家人后得知,崔女士一行7人,除了2位没有食用“海鲜大咖”的消费者外,剩下5人均出现了类似情况,崔女士随即与家人前往宣武医院就诊,被主治医生诊断为急性肠胃炎,经过输液等相关治疗后,崔女士一行人的症状有所缓解。 记者调查 双方各执一词协商未果 根据崔女士提供的线索,北京商报记者随即电话联系到金掌勺广渠门店,该店负责人表示,“海鲜大咖”是金掌勺于去年夏天推出的海鲜拼锅产品,根据用料及分量差异分为299元、499元以及799元三档,其中价格499元的“海鲜大咖”销量最高。据该负责人介绍,“海鲜大咖”自上线以来颇受消费者欢迎,其中499元的“海鲜大咖”中包括:螃蟹、鲍鱼、扇贝、蚬子、烤鱼等多种海鲜类产品,经过加工处理后做成海鲜拼锅。该负责人回忆,崔女士一行人到店消费时,店内有超过200位消费者在用餐,当天售出的“海鲜大咖”超过20份。由于崔女士一行人还点了酸梅汤、啤酒等饮品,店内相关服务人员还提醒过崔女士在食用海鲜后应慎重食用含有VC的食物或刺激性饮料。此外,除了崔女士一行人出现了在食用“海鲜大咖”后引发急性肠胃炎的情况,并没有收到当天其他消费者的类似投诉。 但在北京商报记者向崔女士核实金掌勺广渠门店负责人所述信息时,崔女士却表示,当日一同用餐后出现肠胃不适的5人中有2人因开车并未饮用啤酒,此外,在点餐后,也没有服务人员提示他们不能在食用海鲜的同时饮用含有VC的酸梅汤。她同时表示,在她发出微博并被网友转发后,还有2位自称是当天到店食用过“海鲜大咖”的消费者向崔女士表示也出现了肠胃不适的症状,并提供了当天到店的消费证明。 截至北京商报记者发稿前,双方仍在就该事件进行协商处理,金掌勺也于6月14日在其微博上发布声明,称已成立了相关调查小组对该事件进行调查,愿意承担崔女士一家人因此而产生的医疗及检查费用。崔女士则表示,希望能够通过相关渠道维护自身利益。 事件总结 海鲜品类是把双刃剑 对此有业内人士认为,夏季是海鲜等产品的销售旺季,尤其是近两年,餐饮行业向大众化转型的过程中破除了海鲜类产品曾经的高端定位壁垒,将海鲜类以多样的形式呈献给大众消费人群。但是,海鲜类产品对于食材的新鲜度要求更高,餐饮企业应当在采购海鲜类食材的过程中更加注重食材的质量,并根据销量调整采购数量,以防出现食材积压的情况。此外,海鲜的走红已然让供应链成为商家的必争之地,但就目前而言,海鲜的供应链仍存在不完善的地方,餐饮企业在选择供应商的时候应更加慎重。 另据一位不愿透露姓名的餐厅负责人介绍,相比蔬菜、粮油,海鲜类产品的供应链更加冗长复杂,不够透明,这就为食品安全埋下了隐患,商家为迎合消费者的口味喜好,通常加工海鲜类产品时会加上重油重辣的辅料,遮盖了食材本身的味道,消费者在食用过程中也不易察觉所食用的海鲜是否新鲜。 中国烹饪协会在日前公布今年5月全国餐饮收入数据时表示,随着入夏温度升高,消费者对于餐饮服务的种类选择也发生一定变化。餐饮企业应避免夏季食品安全问题发生,及时调整菜品结构,对风险食品、风险环节采取预防措施,以优质服务迎合消费需求。 今年夏季,海鲜品类的持续走红,给很多餐饮企业在产品研发方面提供了新思路。以重油重辣炒料加工的海鲜类拼锅成为消费者和餐饮企业热捧的新宠。然而,日前发生在金掌勺东北菜广渠门店的消费者食用海鲜拼锅后患肠胃炎的事件为今夏食品安全敲响了警钟。有业内人士分析认为,海鲜类爆品固然能为餐厅带来可观的收益,但同时,海鲜类时令性较强且新鲜度要求较高,也是食品安全的隐患所在。 事件起因 一家五口疑似被“海鲜大咖”放倒 6月13日傍晚,网友梦幻少女有人爱发微博称其一家7口在金掌勺东北菜广渠门店食用过店内的“海鲜大咖”后,有5人出现上吐下泻的症状,经医院诊断,5人均患上急性肠胃炎,疑似食物中毒。同时发出当日食用的“海鲜大咖”照片、医院诊断说明,以及与商家负责人后期沟通过程中的照片。 北京商报记者随即联系到当事人消费者崔女士,崔女士表示,他们一行7人于6月11日晚间在金掌勺东北菜广渠门店进行家庭聚会,并于到店2天前预定了金掌勺家售价为499元的“海鲜大咖”,在用餐过程中还加点了店内的其他少量特色菜品,以及酸梅汤、啤酒等饮品。 次日清晨,崔女士感到肠胃不适,并出现呕吐和腹泻、腹痛的症状,在联系前日共同进餐的家人后得知,崔女士一行7人,除了2位没有食用“海鲜大咖”的消费者外,剩下5人均出现了类似情况,崔女士随即与家人前往宣武医院就诊,被主治医生诊断为急性肠胃炎,经过输液等相关治疗后,崔女士一行人的症状有所缓解。 记者调查 双方各执一词协商未果 根据崔女士提供的线索,北京商报记者随即电话联系到金掌勺广渠门店,该店负责人表示,“海鲜大咖”是金掌勺于去年夏天推出的海鲜拼锅产品,根据用料及分量差异分为299元、499元以及799元三档,其中价格499元的“海鲜大咖”销量最高。据该负责人介绍,“海鲜大咖”自上线以来颇受消费者欢迎,其中499元的“海鲜大咖”中包括:螃蟹、鲍鱼、扇贝、蚬子、烤鱼等多种海鲜类产品,经过加工处理后做成海鲜拼锅。该负责人回忆,崔女士一行人到店消费时,店内有超过200位消费者在用餐,当天售出的“海鲜大咖”超过20份。由于崔女士一行人还点了酸梅汤、啤酒等饮品,店内相关服务人员还提醒过崔女士在食用海鲜后应慎重食用含有VC的食物或刺激性饮料。此外,除了崔女士一行人出现了在食用“海鲜大咖”后引发急性肠胃炎的情况,并没有收到当天其他消费者的类似投诉。 但在北京商报记者向崔女士核实金掌勺广渠门店负责人所述信息时,崔女士却表示,当日一同用餐后出现肠胃不适的5人中有2人因开车并未饮用啤酒,此外,在点餐后,也没有服务人员提示他们不能在食用海鲜的同时饮用含有VC的酸梅汤。她同时表示,在她发出微博并被网友转发后,还有2位自称是当天到店食用过“海鲜大咖”的消费者向崔女士表示也出现了肠胃不适的症状,并提供了当天到店的消费证明。 截至北京商报记者发稿前,双方仍在就该事件进行协商处理,金掌勺也于6月14日在其微博上发布声明,称已成立了相关调查小组对该事件进行调查,愿意承担崔女士一家人因此而产生的医疗及检查费用。崔女士则表示,希望能够通过相关渠道维护自身利益。 事件总结 海鲜品类是把双刃剑 对此有业内人士认为,夏季是海鲜等产品的销售旺季,尤其是近两年,餐饮行业向大众化转型的过程中破除了海鲜类产品曾经的高端定位壁垒,将海鲜类以多样的形式呈献给大众消费人群。但是,海鲜类产品对于食材的新鲜度要求更高,餐饮企业应当在采购海鲜类食材的过程中更加注重食材的质量,并根据销量调整采购数量,以防出现食材积压的情况。此外,海鲜的走红已然让供应链成为商家的必争之地,但就目前而言,海鲜的供应链仍存在不完善的地方,餐饮企业在选择供应商的时候应更加慎重。 另据一位不愿透露姓名的餐厅负责人介绍,相比蔬菜、粮油,海鲜类产品的供应链更加冗长复杂,不够透明,这就为食品安全埋下了隐患,商家为迎合消费者的口味喜好,通常加工海鲜类产品时会加上重油重辣的辅料,遮盖了食材本身的味道,消费者在食用过程中也不易察觉所食用的海鲜是否新鲜。 中国烹饪协会在日前公布今年5月全国餐饮收入数据时表示,随着入夏温度升高,消费者对于餐饮服务的种类选择也发生一定变化。餐饮企业应避免夏季食品安全问题发生,及时调整菜品结构,对风险食品、风险环节采取预防措施,以优质服务迎合消费需求。

横向滚动

turntable.js是一个简单的转盘抽奖特效

三级页面内容

-------------------------------------------------------------------------------- /example/dist/perf.html: -------------------------------------------------------------------------------- 1 |

正在加载...

活动规则:

活动时间:

即日起-2014年5月19日

参与方式:

一、 许愿有奖

1. 登录本专题;
2. 在活动页面选择/填写个人梦想;
3. 选择一位圆梦大使
4. 提交作品并分享;
5. 参加转盘抽奖。
● 全新凯美瑞环游团,将从所有征集到的愿望中随机选取有意思的愿望,在环游世界的旅途中,在异国他乡尽其所能地为您实现梦想!
● 提交梦想后,别忘了在补填资料中留下您的梦想明细哦,比如TA的联系方式~;您的愿望一旦被选中,这些信息将帮助我们的圆梦大使为您实现梦想;主办方会为您严格保密此部分信息。
● “为可能 尽所能”跟搜狐自媒体人环游世界86天 【了解详情】

二、 分享有奖

1. 登录本专题;
2. 分享梦想作品;
3. 参加转盘抽奖。

三、有奖试驾

1. 除了提交愿望或者分享愿望作品,您还可以在“补填资料“或“有奖试驾”对话框中预约试驾全新凯美瑞,完成试驾信息填写的用户,均可参加试驾豪礼大抽奖。
2. 主办方将于5月21日进行抽奖,并在5月25日前公布获奖名单。
3. 每个手机号只能预约一次试驾,试驾信息提交后不能修改,请注意填写正确信息哦!

四、抽奖规则:

1、 用户只有在登录状态下参与互动,才能获得抽奖机会;
2、 上传一个愿望,获得3次转盘抽奖机会;单独分享愿望作品一次,获得1次转盘抽奖机会;每个账号每天最高获得15次转盘抽奖机会;
3、 活动奖品:
奖品类别奖品设置奖品数量
试驾豪礼iPadmini 31
500元京东电子购物卡10
转盘抽奖100元手机充值话费30
50元手机充值话费30
小狐狸公仔一只50
活动定制T恤一件50
(1)、所有奖品将于活动结束后统一派发。
(2)、中奖信息会以网站公告的方式告知,请活动参与者密切关注活动网站。请获奖用户填写完整的个人信息,以确保奖品能准确送达;个人信息一旦提交,不可修改;若因用户资料填写不全或不正确,而导致奖品无法成功送达,视为自动放弃获奖机会,主办方不再补发礼品。
(3)、100元及以上价值礼品,需凭身份证复印件(或扫描件/电子照片)领奖,身份证信息需与登记的个人信息吻合,否则视为自动放弃获奖机会。
(4)、电子购物卡及手机话费充值等奖品,若在采购过程中遇到缺货等情况,将采用同类等值礼品替代。

活动声明:

1、本活动的主办方为 广汽丰田汽车有限公司(以下统一简称活动“主办方”),搜狐网为本活动的主办合作媒体。
2、主办方及搜狐网保留对本次活动所有作品(文字、照片、视频等)的出版权,用于印刷,广播,电子媒体或其他媒体,而不需要经过参赛者的许可,或支付参赛者任何费用。
3、主办方有权取消和删除任何违反规则、条例或侵犯版权的个人作品。
4、主办方将不承担任何由参赛者引起的侵犯版权或其它法律纠纷,并有权在需要时修改活动阶段,奖品及其规则,恕不另行通知。
5、所有用户参与活动时不得发布危害国家安全、泄露国家秘密的言论,不得侵犯国家、社会、集体和公民的合法权益,不得发布国家法律法规明令禁止的内容,如因留言导致任何法律纠纷,主办方及搜狐网均不承担责任。
6、主办方有权力在不通知用户的前提下删除违反、侵权、诽谤、不道德的言论。
7、如发现用户在活动中使用任何不正当手段参与活动,主办方有权不通知用户直接取消用户任何获奖资格。
8、所有活动参赛者视为接受上述规则和条例。
9、在法律允许的范围内,主办方对本次活动拥有最终解释权和决策权。

1.选择你的愿望

2.选择你的圆梦大使

确定提交

即日起-5月19日,登记试驾信息,
有机会赢取iPadmini3 及 电商购物卡哦!
(活动详情请见 首页 [活动规则])

*姓名
*手机
*省份
*城市
*经销商
确定提交

我的抽奖次数:loading...

*姓名
*手机
备注

一旦提交,将不能更改,此信息关乎您中奖后派发奖品途径,请谨慎填写,确保无误!

完善以下试驾信息,
有机会赢取iPadmini3 及 电商购物卡哦!
(活动详情请见 首页 [活动规则])

试驾全新凯美瑞

省份
城市
经销商
确定提交

-------------------------------------------------------------------------------- /example/src/_lib/js/share.js: -------------------------------------------------------------------------------- 1 | (function (window) { 2 | 3 | var share = (function () { 4 | return function (url, txt, pic, provider, isGetUrl) { 5 | if (!provider) return; 6 | 7 | var toUrl; 8 | url = encodeURIComponent(url || ''); 9 | txt = encodeURIComponent(txt || ''); 10 | pic = encodeURIComponent(pic || ''); 11 | 12 | switch (provider) { 13 | case 'weibosohu': 14 | { 15 | toUrl = 'http://t.sohu.com/third/post.jsp?url=' + url + '&title=' + txt + '&pic=' + pic; 16 | break; 17 | } 18 | case 'weibosina': 19 | { 20 | toUrl = 'http://service.t.sina.com.cn/share/share.php?title=' + txt + url + '&pic=' + pic + '&searchPic=false'; 21 | break; 22 | } 23 | case 'qq': 24 | { 25 | toUrl = 'http://sns.qzone.qq.com/cgi-bin/qzshare/cgi_qzshare_onekey?url=' + url + '&title=' + txt + '&desc=' + txt + '&summary=' + pic; 26 | break; 27 | } 28 | case 'tqq': 29 | { 30 | toUrl = 'http://v.t.qq.com/share/share.php?url=' + url + '&title=' + txt + '&pic=' + pic; 31 | break; 32 | } 33 | case 'renren': 34 | { 35 | toUrl = 'http://widget.renren.com/dialog/share?resourceUrl=' + pic + '&srcUrl=' + url + '&title=' + txt + '&description=' + txt; 36 | break; 37 | } 38 | case 'baishehui': 39 | { 40 | toUrl = 'http://bai.sohu.com/share/blank/addbutton.do?link=' + url + '&title=' + txt + '&pic=' + pic; 41 | break; 42 | } 43 | case 'douban': 44 | { 45 | toUrl = 'http://shuo.douban.com/!service/share?href=' + url + '&name=' + txt; 46 | break; 47 | } 48 | case 'kaixin001': 49 | { 50 | toUrl = 'http://www.kaixin001.com/rest/records.php?url=' + url + '&style=11&content=' + txt; 51 | break; 52 | } 53 | case '163': 54 | { 55 | toUrl = 'http://t.163.com/article/user/checkLogin.do?info=' + txt + url; 56 | break; 57 | } 58 | case '51': 59 | { 60 | toUrl = 'http://share.51.com/share/share.php?vaddr=' + url + '&title=' + txt + '&type=8&pic=' + pic; 61 | break; 62 | } 63 | case 'txpengyou': 64 | { 65 | toUrl = 'http://sns.qzone.qq.com/cgi-bin/qzshare/cgi_qzshare_onekey?to=pengyou&url=' + url + '&title=' + txt + '&desc=' + txt + '&summary=' + pic; 66 | break; 67 | } 68 | case 'tieba': 69 | { 70 | toUrl = 'http://tieba.baidu.com/f/commit/share/openShareApi?url=' + url + '&title=' + txt + '&desc=' + txt; 71 | break; 72 | } 73 | } 74 | 75 | return isGetUrl ? toUrl : window.open(toUrl); 76 | }; 77 | })(); 78 | 79 | 80 | //CommonJS 81 | if (typeof exports === 'object') { 82 | module.exports = share; 83 | return; 84 | } 85 | 86 | //添加到全局 87 | window.share = share; 88 | 89 | })(window); -------------------------------------------------------------------------------- /example/src/_lib/scss/ani/ani_circle.scss: -------------------------------------------------------------------------------- 1 | /* 2 | scss/ani_circle 3 | 旋转动画 4 | */ 5 | 6 | @keyframes ani_circle 7 | { 8 | 0% 9 | { 10 | transform: rotateZ(0deg); 11 | } 12 | 13 | 100% 14 | { 15 | transform: rotateZ(360deg); 16 | } 17 | } -------------------------------------------------------------------------------- /example/src/_lib/scss/ani/ani_loading.scss: -------------------------------------------------------------------------------- 1 | /* 2 | scss/ani_loading 3 | loading动画样式 4 | */ 5 | //引入 6 | @import 'ani_circle'; 7 | 8 | //ani_loading函数 9 | //$cw 容器尺寸 10 | //$lw loading圆环宽度 11 | //$lc loading圆环颜色 12 | @mixin ani_loading($cw: 0.8rem, $lw: 0.06rem, $lc: $color) { 13 | &:before 14 | { 15 | content: ''; 16 | @include mx_plt($left: 50%, $top: 50%); 17 | width: $cw; 18 | height: $cw; 19 | margin-left: -$cw / 2; 20 | margin-top: -$cw / 2; 21 | border-radius: $cw; 22 | /*如.loading元素中还有transform,:before内容将挡不住*/ 23 | z-index: -1; 24 | /*圆环用border生成*/ 25 | border-top: $lw solid rgba($lc, 0.2); 26 | border-right: $lw solid rgba($lc, 0.2); 27 | border-bottom: $lw solid rgba($lc, 0.2); 28 | border-left: $lw solid rgba($lc, 1); 29 | /*动画*/ 30 | animation: ani_circle 0.8s linear infinite; 31 | } 32 | } 33 | 34 | 35 | /*loading动画类*/ 36 | .ani_loading 37 | { 38 | @include ani_loading; 39 | } -------------------------------------------------------------------------------- /example/src/_lib/scss/ani/ani_spinner.scss: -------------------------------------------------------------------------------- 1 | /* 2 | scss/ani_spinner 3 | spinner动画类 4 | */ 5 | //引入 6 | @import 'ani_circle'; 7 | 8 | //ani_spinner函数 9 | //$cw 容器尺寸 10 | //$dw 点尺寸 11 | //$dc 点颜色 12 | @mixin ani_spinner($cw: 0.8rem, $dw: 0.14rem, $dc: $color) { 13 | &:before 14 | { 15 | /*负数*/ 16 | $neg: ($cw - $dw) / 2; 17 | /*负数1*/ 18 | $neg1: $neg * 0.7; 19 | 20 | content: ''; 21 | @include mx_plt($left: 50%, $top: 50%); 22 | width: $dw; 23 | height: $dw; 24 | margin-left: -$dw / 2; 25 | margin-top: -$dw / 2; 26 | border-radius: $dw; 27 | /*如.ani_spinner元素中有transform,:before内容将不能被背景图挡住*/ 28 | z-index: -1; 29 | /*8个圆点用阴影生成*/ 30 | box-shadow: 0 (-$neg) 0 rgba($dc, 1), 31 | (-$neg1) (-$neg1) 0 rgba($dc, 0.875), 32 | (-$neg) 0 0 rgba($dc, 0.75), 33 | (-$neg1) $neg1 0 rgba($dc, 0.625), 34 | 0 $neg 0 rgba($dc, 0.5), 35 | $neg1 $neg1 0 rgba($dc, 0.375), 36 | $neg 0 0 rgba($dc, 0.25), 37 | $neg1 (-$neg1) 0 rgba($dc, 0.125); 38 | /*动画*/ 39 | animation: ani_circle 1s ease infinite; 40 | } 41 | } 42 | 43 | 44 | /*spinner动画类*/ 45 | .ani_spinner 46 | { 47 | @include ani_spinner; 48 | } -------------------------------------------------------------------------------- /example/src/css/base/base.scss: -------------------------------------------------------------------------------- 1 | /*项目基础样式*/ 2 | //变量 3 | $border-color: rgba(#000, 0.1); 4 | 5 | /*表单输入元素*/ 6 | input, select, textarea 7 | { 8 | border-radius: 0; 9 | border: 1px solid $border-color; 10 | background-color: rgba(0, 0, 0, 0.1); 11 | 12 | &[disabled] 13 | { 14 | opacity: 0.5; 15 | } 16 | } 17 | 18 | 19 | /*placeholder的颜色*/ 20 | ::-webkit-input-placeholder 21 | { 22 | color: #888; 23 | } 24 | 25 | 26 | textarea 27 | { 28 | height: 1rem; 29 | } 30 | 31 | 32 | /*导航*/ 33 | .navlist 34 | { 35 | a 36 | { 37 | padding: 0 0.5em; 38 | 39 | &.selected 40 | { 41 | border-bottom: 2px solid $color-focus; 42 | color: $color-focus; 43 | } 44 | } 45 | 46 | } 47 | 48 | 49 | /*说明*/ 50 | .info 51 | { 52 | padding: 0.2rem 0.2rem 0 4em; 53 | position: relative; 54 | 55 | &:before 56 | { 57 | content: '说明:'; 58 | @include mx_plt($left: 0.2rem, $top: 0.2rem); 59 | font-weight: bold; 60 | } 61 | } 62 | 63 | 64 | /*列表*/ 65 | .list 66 | { 67 | padding: 0.2rem; 68 | 69 | a 70 | { 71 | display: block; 72 | padding: 0.2rem 0.1rem; 73 | position: relative; 74 | border-bottom: 1px solid $border-color; 75 | 76 | p 77 | { 78 | color: #888; 79 | padding-left: 2em; 80 | } 81 | 82 | &.title 83 | { 84 | background: #eee; 85 | font-weight: bold; 86 | } 87 | 88 | &:first-of-type 89 | { 90 | border-top: 1px solid $border-color; 91 | } 92 | } 93 | } 94 | 95 | 96 | h3.center 97 | { 98 | position: relative; 99 | margin-top: 0.2rem; 100 | border-top: 1px solid $border-color; 101 | } 102 | 103 | 104 | html 105 | { 106 | //font-size:60px; 107 | } -------------------------------------------------------------------------------- /example/src/css/index.scss: -------------------------------------------------------------------------------- 1 | //变量 2 | //$duration: 5s; 3 | 4 | //引入 5 | @import "jq/ui/base"; 6 | @import "jq/ui/ui"; 7 | //@import "jq/ui/body_scroll"; 8 | //@import "jq/plugin/customalert"; 9 | 10 | //引入基础样式 11 | @import "./base/base"; 12 | 13 | //引入面板样式 14 | @import "./index/ui"; 15 | @import "./index/carousel"; 16 | @import "./index/picpager"; 17 | @import "./index/piccut"; 18 | @import "./index/flip"; 19 | @import "./index/scroll"; 20 | @import "./index/scratchcard"; 21 | @import "./index/turntable"; 22 | @import "./index/share"; 23 | @import "./index/sidebox"; -------------------------------------------------------------------------------- /example/src/css/index/carousel.scss: -------------------------------------------------------------------------------- 1 | /*焦点图 panel*/ 2 | //引入 3 | @import "jq/plugin/carousel"; 4 | 5 | 6 | #carousel 7 | { 8 | .carousel 9 | { 10 | width: 90%; 11 | min-width: 6rem; 12 | height: 6rem; 13 | margin: 0 auto; 14 | 15 | img 16 | { 17 | height: 6rem; 18 | } 19 | 20 | &.vertical 21 | { 22 | img 23 | { 24 | width: 100%; 25 | } 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /example/src/css/index/flip.scss: -------------------------------------------------------------------------------- 1 | /*3d旋转切换 panel*/ 2 | //引入 3 | @import "jq/plugin/flip"; 4 | 5 | 6 | #flip 7 | { 8 | .flip 9 | { 10 | width: 90%; 11 | min-width: 6rem; 12 | height: 6rem; 13 | margin: 0 auto; 14 | 15 | p 16 | { 17 | @extend %ph_full; 18 | @extend .ani_loading; 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /example/src/css/index/piccut.scss: -------------------------------------------------------------------------------- 1 | /*图片裁切 panel*/ 2 | //引入 3 | @import "jq/plugin/piccut"; 4 | 5 | 6 | #piccut 7 | { 8 | .avator_up 9 | { 10 | width: 6.4rem; 11 | height: 6.4rem; 12 | margin: 10px auto; 13 | } 14 | 15 | @at-root 16 | { 17 | #file 18 | { 19 | width: 2rem; 20 | } 21 | 22 | 23 | #shower 24 | { 25 | max-width: 6.4rem; 26 | display: block; 27 | margin: 0.1rem auto; 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /example/src/css/index/picpager.scss: -------------------------------------------------------------------------------- 1 | /*相册 panel*/ 2 | //引入 3 | @import "jq/plugin/picpager"; 4 | 5 | 6 | #picpager 7 | { 8 | height: 100%; 9 | overflow: hidden; 10 | 11 | .info 12 | { 13 | @extend %ph_palt; 14 | top: $head-height; 15 | width: 100%; 16 | background: rgba(0, 0, 0, 0.5); 17 | z-index: 1; 18 | color: #fff; 19 | padding-bottom: 0.1rem; 20 | } 21 | 22 | .picpager 23 | { 24 | @extend %ph_full; 25 | } 26 | } -------------------------------------------------------------------------------- /example/src/css/index/scratchcard.scss: -------------------------------------------------------------------------------- 1 | /*刮刮卡 panel*/ 2 | #scratchcard 3 | { 4 | height: 100%; 5 | 6 | .scratchcard 7 | { 8 | @extend %ph_full; 9 | } 10 | } -------------------------------------------------------------------------------- /example/src/css/index/scroll.scss: -------------------------------------------------------------------------------- 1 | /*自定义滚动 panel*/ 2 | #scroll 3 | { 4 | .scroll 5 | { 6 | 7 | width: 90%; 8 | min-width: 6rem; 9 | height: 6rem; 10 | margin: 0 auto; 11 | overflow: hidden; 12 | 13 | div 14 | { 15 | transition-duration: 0.4s; 16 | } 17 | 18 | &:nth-of-type(1) > div 19 | { 20 | width: 100%; 21 | } 22 | 23 | &:nth-of-type(2) > div 24 | { 25 | width: 900%; 26 | height: 100%; 27 | background: url(../img/1.jpg); 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /example/src/css/index/share.scss: -------------------------------------------------------------------------------- 1 | /*分享 panel*/ 2 | 3 | /*分享图标*/ 4 | .icon_share 5 | { 6 | text-align: center; 7 | /*a标签间隔为0*/ 8 | font-size: 0; 9 | 10 | $height: 1rem; 11 | a 12 | { 13 | display: inline-block; 14 | width: $height; 15 | height: $height; 16 | vertical-align: middle; 17 | border-radius: 20%; 18 | margin: 0.16rem; 19 | position: relative; 20 | 21 | &:after 22 | { 23 | content: ''; 24 | @extend %ph_pafull; 25 | background: url(../img/icon_share.png); 26 | background-size: auto 100%; 27 | border-radius: 20%; 28 | } 29 | 30 | &.focus 31 | { 32 | background: #000; 33 | 34 | &:after 35 | { 36 | opacity: 0.5; 37 | } 38 | } 39 | } 40 | 41 | $providers: weibosina, qq, renren, tieba, tqq, douban, kaixin001, netease; 42 | @each $provider in $providers 43 | { 44 | .#{$provider}:after 45 | { 46 | background-position: #{ -$height * (index($providers, $provider) - 1)} 0; 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /example/src/css/index/sidebox.scss: -------------------------------------------------------------------------------- 1 | /*sidebox panel*/ 2 | 3 | #sidebox 4 | { 5 | .content 6 | { 7 | @include mx_maxwidth($width: 210px, $target-width: 250px); 8 | } 9 | } 10 | 11 | 12 | /*第三方登陆图标*/ 13 | .icon_login 14 | { 15 | @extend .center; 16 | /*a标签间隔为0*/ 17 | font-size: 0; 18 | 19 | $height: 0.6rem; 20 | a 21 | { 22 | display: inline-block; 23 | width: $height; 24 | height: $height; 25 | vertical-align: middle; 26 | border-radius: 20%; 27 | margin-left: 0.15rem; 28 | position: relative; 29 | box-shadow: 0 0 2px rgba(#000, 0.3); 30 | 31 | &:first-of-type 32 | { 33 | margin-left: 0; 34 | } 35 | 36 | &:after 37 | { 38 | content: ''; 39 | @extend %ph_pafull; 40 | background: url(../img/icon_login.png); 41 | background-size: auto 100%; 42 | border-radius: 20%; 43 | } 44 | 45 | &.focus 46 | { 47 | background: #000; 48 | 49 | &:after 50 | { 51 | opacity: 0.5; 52 | } 53 | } 54 | } 55 | 56 | $providers: qq, sina, renren, baidu, taobao; 57 | @each $provider in $providers 58 | { 59 | .#{$provider}:after 60 | { 61 | background-position: #{ -$height * (index($providers, $provider) - 1)} 0; 62 | } 63 | } 64 | } 65 | 66 | 67 | /*用户名密码图标*/ 68 | @font-face 69 | { 70 | font-family: icon_login; 71 | src: url(data:application/x-font-woff;charset=utf-8;base64,AAEAAAALAIAAAwAwT1MvMg8SAysAAAC8AAAAYGNtYXAaVcxYAAABHAAAAExnYXNwAAAAEAAAAWgAAAAIZ2x5ZqSu3LgAAAFwAAAC9GhlYWQF10jfAAAEZAAAADZoaGVhCD0ERwAABJwAAAAkaG10eAoAAAUAAATAAAAAGGxvY2EBogD2AAAE2AAAAA5tYXhwABEAjAAABOgAAAAgbmFtZVcZpu4AAAUIAAABRXBvc3QAAwAAAAAGUAAAACAAAwQAAZAABQAAApkCzAAAAI8CmQLMAAAB6wAzAQkAAAAAAAAAAAAAAAAAAAABEAAAAAAAAAAAAAAAAAAAAABAAADmAQPA/8AAQAPAAEAAAAABAAAAAAAAAAAAAAAgAAAAAAACAAAAAwAAABQAAwABAAAAFAAEADgAAAAKAAgAAgACAAEAIOYB//3//wAAAAAAIOYA//3//wAB/+MaBAADAAEAAAAAAAAAAAAAAAEAAf//AA8AAQAAAAAAAAAAAAIAADc5AQAAAAABAAAAAAAAAAAAAgAANzkBAAAAAAEAAAAAAAAAAAACAAA3OQEAAAAAAQAF/8AEewPAAIkAABcWNjc+Azc+ATc+ATc0JicuASc0JicuATU0Njc+ATU+AzMwMjEeAxcUFhceARUUBgcOAQcOAQcOARUeARceARceAxceATM6ATc+AScuAycuAScuASc+ATc+ATU0JicuAycjIg4CBw4BFRQWFx4BFw4BBw4BBw4DBwYWFxAGDAIMOkdMHg8XCEQ3BwIEIzsTAgEZGwoLBAQDLEdeNgM2XkcqAgMDBwcUEgEBARNCKQMDBzdECBkQHkpHOQwCCQUBAgEGBwIOQU5RHg4XBi02CilDFBUWCgoDME9pPAU6aE8yBA8PHhwUOiQJNy0GFQ4eUk9BDgIHBj8CBgcuPSYWBwMGBB1WIwQIAx5aNQEDARw3Fw0TBwIHBD1qTy4BL1BtPgMGAgcQCxMuGAEDAT1nIQIJBCNVHgMGBAYUJTstBQcBAQwGNUQpFgcDBQMTOycjaj4bNxgQGwpDdVczATFVc0ILHxMdQR81WyEnOxQCBgMHGCxFNQYMAQAAAAAKAAD/wAOAA8AAHQA0AD4AQwBIAE0AUgBXAGIAbQAAASIOAh0BIyIGFREUFjMhMjY1ETQmKwE1NC4CIwE0PgIzMh4CHQEjNTQmIyIGHQEjNQUhNTQ2MzIWHQEDByM3MzMHIzczMwcjNzMzFSM3MwUjNTMHBSEiJj0BIRUUBiMTFSE1NDYzITIWFQHAQnVXMjAhLy8hAuAhLy8hMDJXdUL+4C1PaDw8aE8tYHFPT3FgAcD+wF5CQl7XoJKgksCgkqCSwKCSoJJXyaAp/MkJqaADB/0gFBwDQBwUMPzAHBQC4BQcA8AyV3VCYC8h/kAhLy8hAcAhL2BCdVcy/sA8aE8tLU9oPGBgT3FxT2BgYGBCXl5CYP8AoKCgoKCgoKCgoKCgHBRQUBQcAfCQkBQcHBQAAQAAAAAAAMBAyKpfDzz1AAsEAAAAAADRHwIxAAAAANEfAjEAAP/ABHsDwAAAAAgAAgAAAAAAAAABAAADwP/AAAAEgAAAAAAEewABAAAAAAAAAAAAAAAAAAAABgAAAAAAAAAAAAAAAAIAAAAEgAAFA4AAAAAAAAAACgAUAB4A4gF6AAAAAQAAAAYAigAKAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAA4ArgABAAAAAAABAA4AAAABAAAAAAACAA4ARwABAAAAAAADAA4AJAABAAAAAAAEAA4AVQABAAAAAAAFABYADgABAAAAAAAGAAcAMgABAAAAAAAKADQAYwADAAEECQABAA4AAAADAAEECQACAA4ARwADAAEECQADAA4AJAADAAEECQAEAA4AVQADAAEECQAFABYADgADAAEECQAGAA4AOQADAAEECQAKADQAYwBpAGMAbwBtAG8AbwBuAFYAZQByAHMAaQBvAG4AIAAxAC4AMABpAGMAbwBtAG8AbwBuaWNvbW9vbgBpAGMAbwBtAG8AbwBuAFIAZQBnAHUAbABhAHIAaQBjAG8AbQBvAG8AbgBGAG8AbgB0ACAAZwBlAG4AZQByAGEAdABlAGQAIABiAHkAIABJAGMAbwBNAG8AbwBuAC4AAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==) format('truetype'); 72 | font-weight: normal; 73 | font-style: normal; 74 | } 75 | 76 | 77 | .loginbox 78 | { 79 | .icon_userid, .icon_password 80 | { 81 | &:before 82 | { 83 | width: 0.6rem; 84 | font-family: icon_login; 85 | -webkit-font-smoothing: antialiased; 86 | font-size: 0.4rem; 87 | vertical-align: middle; 88 | display: inline-block; 89 | } 90 | } 91 | 92 | .icon_userid:before 93 | { 94 | content: '\e600'; 95 | } 96 | 97 | .icon_password:before 98 | { 99 | content: '\e601'; 100 | } 101 | 102 | & > * 103 | { 104 | margin-top: 0.3rem; 105 | } 106 | 107 | /*搜狐logo*/ 108 | .sohulogo 109 | { 110 | $h: 2.2rem; 111 | display: inline-block; 112 | width: $h; 113 | height: $h; 114 | border-radius: $h; 115 | box-shadow: 0 0 3px rgba(0, 0, 0, 0.3); 116 | position: relative; 117 | 118 | &:after 119 | { 120 | content: ''; 121 | @extend %ph_palt; 122 | @extend %ph_full; 123 | background: url(../img/sohulogo.jpg); 124 | background-size: cover; 125 | border-radius: $h; 126 | } 127 | 128 | &.focus 129 | { 130 | background: #000; 131 | 132 | &:after 133 | { 134 | opacity: 0.5; 135 | } 136 | } 137 | } 138 | 139 | input 140 | { 141 | width: 85%; 142 | background: none; 143 | border: none; 144 | border-bottom: 1px solid $border-color; 145 | } 146 | 147 | /*登陆按钮*/ 148 | .btn-login 149 | { 150 | width: 100%; 151 | } 152 | 153 | /*第三方登陆*/ 154 | .other_login 155 | { 156 | margin-bottom: 0.3rem; 157 | 158 | p 159 | { 160 | padding-bottom: 0.2rem; 161 | text-align: left; 162 | } 163 | } 164 | } -------------------------------------------------------------------------------- /example/src/css/index/turntable.scss: -------------------------------------------------------------------------------- 1 | /*转盘抽奖 panel*/ 2 | //引入 3 | @import "jq/plugin/turntable"; 4 | 5 | 6 | #turntable 7 | { 8 | .turntable 9 | { 10 | width: 6.4rem; 11 | height: 6.4rem; 12 | margin: 10px auto; 13 | background-image: url(../img/bg.png); 14 | 15 | .pi-pointer 16 | { 17 | background-image: url(../img/pointer.png); 18 | } 19 | } 20 | 21 | .btn_start 22 | { 23 | $w: 1.3rem; 24 | $h: 1.3rem; 25 | 26 | @include mx_plt($left: 50%, $top: 50%); 27 | width: $w; 28 | height: $h; 29 | margin-left: -$w / 2; 30 | margin-top: -$h / 2; 31 | background: url(../img/start.png) center center; 32 | background-size: cover; 33 | z-index: 1; 34 | 35 | &.focus 36 | { 37 | opacity: 0.85; 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /example/src/css/index/ui.scss: -------------------------------------------------------------------------------- 1 | @import "jq/plugin/alert"; 2 | 3 | /*ui panel*/ 4 | #ui 5 | { 6 | h3 7 | { 8 | text-indent: 0.2rem; 9 | } 10 | 11 | .list > div 12 | { 13 | display: inline-block; 14 | width: 2rem; 15 | height: 2rem; 16 | position: relative; 17 | border: 1px solid $border-color; 18 | margin: 0.1rem; 19 | 20 | &:after 21 | { 22 | content: attr(class); 23 | display: block; 24 | @extend .center; 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /example/src/gulpfile.js: -------------------------------------------------------------------------------- 1 | //开发代码路径 2 | var dev = '../dev/', 3 | //打包生成代码的路径 4 | dist = '../dist/', 5 | //第三方资源库路径 6 | libDir = './_lib/', 7 | //是否PC端 8 | isPC = 0; 9 | 10 | //任务配置 11 | var config = { 12 | img : { 13 | //源文件 14 | src : ['./img/**'], 15 | //监听文件 16 | watch: ['./img/**'], 17 | //开发输出文件夹 18 | dev : dev + 'img', 19 | //打包输出文件夹 20 | dist : dist + 'img' 21 | }, 22 | css : { 23 | src : ['./css/*.scss'], 24 | watch: ['./css/**'], 25 | dev : dev + 'css', 26 | dist : dist + 'css', 27 | opts : { 28 | //sass 29 | includePaths: [libDir, '../../../'], 30 | 31 | //autoprefixer 32 | browsers: isPC ? ['ie 6', 'chrome 31'] : ['ios 7', 'android 4'], 33 | 34 | //base64 35 | //排除匹配的 36 | exclude : [/^http:\/\/.+$/i], 37 | //小于该设定K数的文件就编码 38 | maxImageSize: isPC ? 5 * 1024 : 5 * 1024 39 | } 40 | }, 41 | js : { 42 | src : ['./js/*.js'], 43 | watch: ['./js/**'], 44 | dev : dev + 'js', 45 | dist : dist + 'js', 46 | opts : { 47 | //browserify 48 | paths: [libDir] 49 | } 50 | }, 51 | html: { 52 | src : ['./*.html'], 53 | watch: ['./*.html', './html/**'], 54 | dev : dev, 55 | dist : dist, 56 | opts : { 57 | //include 58 | prefix : '@', 59 | basepath: './html/', 60 | 61 | //htmlmin 62 | collapseWhitespace: true, 63 | removeComments : true, 64 | minifyJS : true, 65 | minifyCSS : true, 66 | processScripts : ['text/html'] 67 | } 68 | } 69 | }; 70 | 71 | 72 | //gulp 73 | var gulp = require('gulp'); 74 | 75 | 76 | //出错处理函数(避免任务停止) 77 | function errorHandler(e) { 78 | console.log('ERROR IN ' + e.plugin + ': ' + e.message); 79 | } 80 | 81 | //出错处理对象 82 | var plumber = require('gulp-plumber'); 83 | 84 | 85 | //img任务 86 | (function () { 87 | var conf = config.img; 88 | var imgmin = require('gulp-imagemin'); 89 | 90 | //图片压缩 91 | gulp.task('img', function () { 92 | gulp.src(conf.src) 93 | .pipe(plumber({ 94 | errorHandler: errorHandler 95 | })) 96 | //压缩 97 | .pipe(imgmin()) 98 | .pipe(gulp.dest(conf.dev)) 99 | .pipe(gulp.dest(conf.dist)); 100 | }); 101 | })(); 102 | 103 | 104 | //css任务 105 | (function () { 106 | var conf = config.css; 107 | var sass = require('gulp-sass'); 108 | var autoprefixer = require('gulp-autoprefixer'); 109 | var cssmin = require('gulp-clean-css'); 110 | var base64 = require('gulp-base64'); 111 | 112 | //编译sass,压缩css 113 | gulp.task('css', function () { 114 | gulp.src(conf.src) 115 | .pipe(plumber({ 116 | errorHandler: errorHandler 117 | })) 118 | //编译 119 | .pipe(sass(conf.opts)) 120 | .pipe(autoprefixer(conf.opts)) 121 | .pipe(gulp.dest(conf.dev)) 122 | //压缩 123 | .pipe(cssmin()) 124 | .pipe(base64(conf.opts)) 125 | .pipe(gulp.dest(conf.dist)); 126 | }); 127 | })(); 128 | 129 | 130 | //js任务 131 | (function () { 132 | var conf = config.js; 133 | var browserify = require('gulp-browserify'); 134 | var jsmin = require('gulp-uglify'); 135 | 136 | //browserify编译合并,压缩文件js 137 | gulp.task('js', function () { 138 | gulp.src(conf.src) 139 | .pipe(plumber({ 140 | errorHandler: errorHandler 141 | })) 142 | //编译合并 143 | .pipe(browserify(conf.opts)) 144 | .pipe(gulp.dest(conf.dev)) 145 | //压缩 146 | .pipe(jsmin()) 147 | .pipe(gulp.dest(conf.dist)); 148 | }); 149 | })(); 150 | 151 | 152 | //html任务 153 | (function () { 154 | var conf = config.html; 155 | var include = require('gulp-file-include'); 156 | var htmlmin = require('gulp-htmlmin'); 157 | 158 | //html编译和压缩 159 | gulp.task('html', function () { 160 | gulp.src(conf.src) 161 | .pipe(plumber({ 162 | errorHandler: errorHandler 163 | })) 164 | //include编译 165 | .pipe(include(conf.opts)) 166 | .pipe(gulp.dest(conf.dev)) 167 | //压缩 168 | .pipe(htmlmin(conf.opts)) 169 | .pipe(gulp.dest(conf.dist)); 170 | }); 171 | })(); 172 | 173 | 174 | //监听任务 175 | gulp.task('watch', function () { 176 | //监听文件变化 177 | gulp.watch(config.css.watch, ['css']); 178 | gulp.watch(config.js.watch, ['js']); 179 | gulp.watch(config.img.watch, ['img']); 180 | gulp.watch(config.html.watch, ['html']); 181 | }); 182 | 183 | //默认任务 184 | gulp.task('default', ['watch', 'img', 'css', 'js', 'html']); -------------------------------------------------------------------------------- /example/src/html/base/header.html: -------------------------------------------------------------------------------- 1 |  2 | 21 | -------------------------------------------------------------------------------- /example/src/html/base/navbar.html: -------------------------------------------------------------------------------- 1 |  2 | 17 | -------------------------------------------------------------------------------- /example/src/html/index/carousel.html: -------------------------------------------------------------------------------- 1 |  2 | 13 | -------------------------------------------------------------------------------- /example/src/html/index/flip.html: -------------------------------------------------------------------------------- 1 |  2 |
3 |

flip.js插件适合有限张图片3d切换展示,除了图片,还适用于普通html容器

4 |

横向切换

5 |
6 |
7 |

竖向切换

8 |
9 |
10 |
11 | -------------------------------------------------------------------------------- /example/src/html/index/home.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |

jq.js是适用于现代浏览器的简化版jQuery,体积比zepto小(是其1/4),效率比zepto高(是其2倍左右),兼容jquery语法,实现大多常用api.

4 |
5 | 访问GitHub 6 | 下载源代码 7 | 查看与zepto性能对比(请打开console) 8 | 实现以下API 9 |
10 |
11 | -------------------------------------------------------------------------------- /example/src/html/index/piccut.html: -------------------------------------------------------------------------------- 1 |  2 |
3 |
4 |
5 | 6 | 裁剪 7 | 8 |
9 | -------------------------------------------------------------------------------- /example/src/html/index/picpager.html: -------------------------------------------------------------------------------- 1 |  2 |
3 |

picpager.js插件适合无限张图片切换展示,可动态添加图片数据

4 |
5 |
6 |
7 | -------------------------------------------------------------------------------- /example/src/html/index/scratchcard.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 |
5 | -------------------------------------------------------------------------------- /example/src/html/index/scroll.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |

scroll.js用于模拟页面滚动效果,本DEMO中的可滚动的导航栏就是用该插件实现

4 |

竖向滚动

5 |
6 |
7 | 今年夏季,海鲜品类的持续走红,给很多餐饮企业在产品研发方面提供了新思路。以重油重辣炒料加工的海鲜类拼锅成为消费者和餐饮企业热捧的新宠。然而,日前发生在金掌勺东北菜广渠门店的消费者食用海鲜拼锅后患肠胃炎的事件为今夏食品安全敲响了警钟。有业内人士分析认为,海鲜类爆品固然能为餐厅带来可观的收益,但同时,海鲜类时令性较强且新鲜度要求较高,也是食品安全的隐患所在。 8 | 9 | 事件起因 10 | 11 | 一家五口疑似被“海鲜大咖”放倒 12 | 13 | 6月13日傍晚,网友梦幻少女有人爱发微博称其一家7口在金掌勺东北菜广渠门店食用过店内的“海鲜大咖”后,有5人出现上吐下泻的症状,经医院诊断,5人均患上急性肠胃炎,疑似食物中毒。同时发出当日食用的“海鲜大咖”照片、医院诊断说明,以及与商家负责人后期沟通过程中的照片。 14 | 15 | 北京商报记者随即联系到当事人消费者崔女士,崔女士表示,他们一行7人于6月11日晚间在金掌勺东北菜广渠门店进行家庭聚会,并于到店2天前预定了金掌勺家售价为499元的“海鲜大咖”,在用餐过程中还加点了店内的其他少量特色菜品,以及酸梅汤、啤酒等饮品。 16 | 17 | 次日清晨,崔女士感到肠胃不适,并出现呕吐和腹泻、腹痛的症状,在联系前日共同进餐的家人后得知,崔女士一行7人,除了2位没有食用“海鲜大咖”的消费者外,剩下5人均出现了类似情况,崔女士随即与家人前往宣武医院就诊,被主治医生诊断为急性肠胃炎,经过输液等相关治疗后,崔女士一行人的症状有所缓解。 18 | 19 | 记者调查 20 | 21 | 双方各执一词协商未果 22 | 23 | 根据崔女士提供的线索,北京商报记者随即电话联系到金掌勺广渠门店,该店负责人表示,“海鲜大咖”是金掌勺于去年夏天推出的海鲜拼锅产品,根据用料及分量差异分为299元、499元以及799元三档,其中价格499元的“海鲜大咖”销量最高。据该负责人介绍,“海鲜大咖”自上线以来颇受消费者欢迎,其中499元的“海鲜大咖”中包括:螃蟹、鲍鱼、扇贝、蚬子、烤鱼等多种海鲜类产品,经过加工处理后做成海鲜拼锅。该负责人回忆,崔女士一行人到店消费时,店内有超过200位消费者在用餐,当天售出的“海鲜大咖”超过20份。由于崔女士一行人还点了酸梅汤、啤酒等饮品,店内相关服务人员还提醒过崔女士在食用海鲜后应慎重食用含有VC的食物或刺激性饮料。此外,除了崔女士一行人出现了在食用“海鲜大咖”后引发急性肠胃炎的情况,并没有收到当天其他消费者的类似投诉。 24 | 25 | 但在北京商报记者向崔女士核实金掌勺广渠门店负责人所述信息时,崔女士却表示,当日一同用餐后出现肠胃不适的5人中有2人因开车并未饮用啤酒,此外,在点餐后,也没有服务人员提示他们不能在食用海鲜的同时饮用含有VC的酸梅汤。她同时表示,在她发出微博并被网友转发后,还有2位自称是当天到店食用过“海鲜大咖”的消费者向崔女士表示也出现了肠胃不适的症状,并提供了当天到店的消费证明。 26 | 27 | 截至北京商报记者发稿前,双方仍在就该事件进行协商处理,金掌勺也于6月14日在其微博上发布声明,称已成立了相关调查小组对该事件进行调查,愿意承担崔女士一家人因此而产生的医疗及检查费用。崔女士则表示,希望能够通过相关渠道维护自身利益。 28 | 29 | 事件总结 30 | 31 | 海鲜品类是把双刃剑 32 | 33 | 对此有业内人士认为,夏季是海鲜等产品的销售旺季,尤其是近两年,餐饮行业向大众化转型的过程中破除了海鲜类产品曾经的高端定位壁垒,将海鲜类以多样的形式呈献给大众消费人群。但是,海鲜类产品对于食材的新鲜度要求更高,餐饮企业应当在采购海鲜类食材的过程中更加注重食材的质量,并根据销量调整采购数量,以防出现食材积压的情况。此外,海鲜的走红已然让供应链成为商家的必争之地,但就目前而言,海鲜的供应链仍存在不完善的地方,餐饮企业在选择供应商的时候应更加慎重。 34 | 35 | 另据一位不愿透露姓名的餐厅负责人介绍,相比蔬菜、粮油,海鲜类产品的供应链更加冗长复杂,不够透明,这就为食品安全埋下了隐患,商家为迎合消费者的口味喜好,通常加工海鲜类产品时会加上重油重辣的辅料,遮盖了食材本身的味道,消费者在食用过程中也不易察觉所食用的海鲜是否新鲜。 36 | 37 | 中国烹饪协会在日前公布今年5月全国餐饮收入数据时表示,随着入夏温度升高,消费者对于餐饮服务的种类选择也发生一定变化。餐饮企业应避免夏季食品安全问题发生,及时调整菜品结构,对风险食品、风险环节采取预防措施,以优质服务迎合消费需求。 38 | 今年夏季,海鲜品类的持续走红,给很多餐饮企业在产品研发方面提供了新思路。以重油重辣炒料加工的海鲜类拼锅成为消费者和餐饮企业热捧的新宠。然而,日前发生在金掌勺东北菜广渠门店的消费者食用海鲜拼锅后患肠胃炎的事件为今夏食品安全敲响了警钟。有业内人士分析认为,海鲜类爆品固然能为餐厅带来可观的收益,但同时,海鲜类时令性较强且新鲜度要求较高,也是食品安全的隐患所在。 39 | 40 | 事件起因 41 | 42 | 一家五口疑似被“海鲜大咖”放倒 43 | 44 | 6月13日傍晚,网友梦幻少女有人爱发微博称其一家7口在金掌勺东北菜广渠门店食用过店内的“海鲜大咖”后,有5人出现上吐下泻的症状,经医院诊断,5人均患上急性肠胃炎,疑似食物中毒。同时发出当日食用的“海鲜大咖”照片、医院诊断说明,以及与商家负责人后期沟通过程中的照片。 45 | 46 | 北京商报记者随即联系到当事人消费者崔女士,崔女士表示,他们一行7人于6月11日晚间在金掌勺东北菜广渠门店进行家庭聚会,并于到店2天前预定了金掌勺家售价为499元的“海鲜大咖”,在用餐过程中还加点了店内的其他少量特色菜品,以及酸梅汤、啤酒等饮品。 47 | 48 | 次日清晨,崔女士感到肠胃不适,并出现呕吐和腹泻、腹痛的症状,在联系前日共同进餐的家人后得知,崔女士一行7人,除了2位没有食用“海鲜大咖”的消费者外,剩下5人均出现了类似情况,崔女士随即与家人前往宣武医院就诊,被主治医生诊断为急性肠胃炎,经过输液等相关治疗后,崔女士一行人的症状有所缓解。 49 | 50 | 记者调查 51 | 52 | 双方各执一词协商未果 53 | 54 | 根据崔女士提供的线索,北京商报记者随即电话联系到金掌勺广渠门店,该店负责人表示,“海鲜大咖”是金掌勺于去年夏天推出的海鲜拼锅产品,根据用料及分量差异分为299元、499元以及799元三档,其中价格499元的“海鲜大咖”销量最高。据该负责人介绍,“海鲜大咖”自上线以来颇受消费者欢迎,其中499元的“海鲜大咖”中包括:螃蟹、鲍鱼、扇贝、蚬子、烤鱼等多种海鲜类产品,经过加工处理后做成海鲜拼锅。该负责人回忆,崔女士一行人到店消费时,店内有超过200位消费者在用餐,当天售出的“海鲜大咖”超过20份。由于崔女士一行人还点了酸梅汤、啤酒等饮品,店内相关服务人员还提醒过崔女士在食用海鲜后应慎重食用含有VC的食物或刺激性饮料。此外,除了崔女士一行人出现了在食用“海鲜大咖”后引发急性肠胃炎的情况,并没有收到当天其他消费者的类似投诉。 55 | 56 | 但在北京商报记者向崔女士核实金掌勺广渠门店负责人所述信息时,崔女士却表示,当日一同用餐后出现肠胃不适的5人中有2人因开车并未饮用啤酒,此外,在点餐后,也没有服务人员提示他们不能在食用海鲜的同时饮用含有VC的酸梅汤。她同时表示,在她发出微博并被网友转发后,还有2位自称是当天到店食用过“海鲜大咖”的消费者向崔女士表示也出现了肠胃不适的症状,并提供了当天到店的消费证明。 57 | 58 | 截至北京商报记者发稿前,双方仍在就该事件进行协商处理,金掌勺也于6月14日在其微博上发布声明,称已成立了相关调查小组对该事件进行调查,愿意承担崔女士一家人因此而产生的医疗及检查费用。崔女士则表示,希望能够通过相关渠道维护自身利益。 59 | 60 | 事件总结 61 | 62 | 海鲜品类是把双刃剑 63 | 64 | 对此有业内人士认为,夏季是海鲜等产品的销售旺季,尤其是近两年,餐饮行业向大众化转型的过程中破除了海鲜类产品曾经的高端定位壁垒,将海鲜类以多样的形式呈献给大众消费人群。但是,海鲜类产品对于食材的新鲜度要求更高,餐饮企业应当在采购海鲜类食材的过程中更加注重食材的质量,并根据销量调整采购数量,以防出现食材积压的情况。此外,海鲜的走红已然让供应链成为商家的必争之地,但就目前而言,海鲜的供应链仍存在不完善的地方,餐饮企业在选择供应商的时候应更加慎重。 65 | 66 | 另据一位不愿透露姓名的餐厅负责人介绍,相比蔬菜、粮油,海鲜类产品的供应链更加冗长复杂,不够透明,这就为食品安全埋下了隐患,商家为迎合消费者的口味喜好,通常加工海鲜类产品时会加上重油重辣的辅料,遮盖了食材本身的味道,消费者在食用过程中也不易察觉所食用的海鲜是否新鲜。 67 | 68 | 中国烹饪协会在日前公布今年5月全国餐饮收入数据时表示,随着入夏温度升高,消费者对于餐饮服务的种类选择也发生一定变化。餐饮企业应避免夏季食品安全问题发生,及时调整菜品结构,对风险食品、风险环节采取预防措施,以优质服务迎合消费需求。 69 |
70 |
71 |

横向滚动

72 |
73 |
74 |
75 |
76 | -------------------------------------------------------------------------------- /example/src/html/index/share.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 |

5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |

14 | 15 |
16 | -------------------------------------------------------------------------------- /example/src/html/index/sidebox.html: -------------------------------------------------------------------------------- 1 | 2 | 38 | -------------------------------------------------------------------------------- /example/src/html/index/sub.html: -------------------------------------------------------------------------------- 1 |  2 |
3 |
4 | 跳转到三级页面 5 |
6 |
7 | -------------------------------------------------------------------------------- /example/src/html/index/sub2.html: -------------------------------------------------------------------------------- 1 |  2 |
3 |
4 | 三级页面内容 5 |
6 |
7 | -------------------------------------------------------------------------------- /example/src/html/index/turntable.html: -------------------------------------------------------------------------------- 1 |  2 |
3 |

turntable.js是一个简单的转盘抽奖特效

4 |
5 | 6 |
7 |
8 | -------------------------------------------------------------------------------- /example/src/html/index/ui.html: -------------------------------------------------------------------------------- 1 |  2 |
3 |

ui.js是一个ui框架,包含页面切换,边栏,弹出框,导航栏等功能

4 |
5 | 跳转到二级页面 6 | 跳转到sohu 7 |

有data-href属性的链接将不会跳出页面,以iframe显示

8 |
9 | $.loadPanel('#sub2') 10 |

data-role="root"的panel为一级页面,除此之外为二级页面

11 |
12 | $.toggleHeader(0) 13 | $.toggleHeader(1) 14 | $.toggleNavbar(0) 15 | $.toggleNavbar(1) 16 | $.toggleMask(1) 17 | $.toggleSidebox(1) 18 | confirm弹框 19 | alert弹框 20 | loading样式 21 |
22 |
23 |
24 |
25 | -------------------------------------------------------------------------------- /example/src/img/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soneway/jq/74ac0a9f0711e825b2abcb289b96d51d5e4601cc/example/src/img/1.jpg -------------------------------------------------------------------------------- /example/src/img/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soneway/jq/74ac0a9f0711e825b2abcb289b96d51d5e4601cc/example/src/img/2.jpg -------------------------------------------------------------------------------- /example/src/img/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soneway/jq/74ac0a9f0711e825b2abcb289b96d51d5e4601cc/example/src/img/3.jpg -------------------------------------------------------------------------------- /example/src/img/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soneway/jq/74ac0a9f0711e825b2abcb289b96d51d5e4601cc/example/src/img/4.jpg -------------------------------------------------------------------------------- /example/src/img/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soneway/jq/74ac0a9f0711e825b2abcb289b96d51d5e4601cc/example/src/img/5.jpg -------------------------------------------------------------------------------- /example/src/img/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soneway/jq/74ac0a9f0711e825b2abcb289b96d51d5e4601cc/example/src/img/bg.png -------------------------------------------------------------------------------- /example/src/img/icon_login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soneway/jq/74ac0a9f0711e825b2abcb289b96d51d5e4601cc/example/src/img/icon_login.png -------------------------------------------------------------------------------- /example/src/img/icon_share.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soneway/jq/74ac0a9f0711e825b2abcb289b96d51d5e4601cc/example/src/img/icon_share.png -------------------------------------------------------------------------------- /example/src/img/pointer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soneway/jq/74ac0a9f0711e825b2abcb289b96d51d5e4601cc/example/src/img/pointer.png -------------------------------------------------------------------------------- /example/src/img/sohulogo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soneway/jq/74ac0a9f0711e825b2abcb289b96d51d5e4601cc/example/src/img/sohulogo.jpg -------------------------------------------------------------------------------- /example/src/img/start.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soneway/jq/74ac0a9f0711e825b2abcb289b96d51d5e4601cc/example/src/img/start.png -------------------------------------------------------------------------------- /example/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 模板页面 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 |
22 | 23 | 24 | @include('./base/header.html") 25 | 26 | 27 | @include('./index/home.html") 28 | @include('./index/ui.html") 29 | @include('./index/carousel.html") 30 | @include('./index/flip.html") 31 | @include('./index/picpager.html") 32 | @include('./index/piccut.html") 33 | @include('./index/scroll.html") 34 | @include('./index/scratchcard.html") 35 | @include('./index/turntable.html") 36 | 37 | 38 | 39 | @include('./index/sub.html") 40 | @include('./index/sub2.html") 41 | @include('./index/share.html") 42 | 43 | 44 | @include('./base/navbar.html") 45 | 46 |
47 | 48 | 49 | @include('./index/sidebox.html") 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /example/src/js/index.js: -------------------------------------------------------------------------------- 1 | //index.js 2 | 3 | var $ = window.$ = require('jq'); 4 | require('base'); 5 | require('ui'); 6 | require('scroll'); 7 | 8 | 9 | //页面模块加载对象 10 | var loader = { 11 | home : require('./index/home'), 12 | ui : require('./index/ui'), 13 | carousel : require('./index/carousel'), 14 | flip : require('./index/flip'), 15 | picpager : require('./index/picpager'), 16 | piccut : require('./index/piccut'), 17 | scroll : require('./index/scroll'), 18 | scratchcard: require('./index/scratchcard'), 19 | turntable : require('./index/turntable'), 20 | share : require('./index/share') 21 | }; 22 | 23 | 24 | //面板显示回调函数 25 | $.panelLoaded = function ($this, isInit) { 26 | var load = (loader[$this.attr('id')] || {}).load; 27 | typeof load === 'function' && load($this, isInit); 28 | }; 29 | //面板隐藏回调函数 30 | $.panelUnloaded = function ($this) { 31 | var unload = (loader[$this.attr('id')] || {}).unload; 32 | typeof unload === 'function' && unload($this); 33 | }; -------------------------------------------------------------------------------- /example/src/js/index/carousel.js: -------------------------------------------------------------------------------- 1 | //焦点图 2 | 3 | require('carousel'); 4 | 5 | //加载时执行 6 | exports.load = function ($this, isInit) { 7 | if (isInit) { 8 | var html = ''; 9 | for (var i = 1, len = 6; i < len; i++) { 10 | html += ''; 11 | } 12 | 13 | $('.carousel').each(function () { 14 | $(this).html(html).carousel({ 15 | isVertical: this.getAttribute('data-isvertical') === '1', 16 | isAutoPlay: true, 17 | isLoop: true 18 | }); 19 | }); 20 | } 21 | }; -------------------------------------------------------------------------------- /example/src/js/index/flip.js: -------------------------------------------------------------------------------- 1 | //3d旋转切换 2 | 3 | require('flip'); 4 | 5 | 6 | //加载时执行 7 | exports.load = function ($this, isInit) { 8 | if (isInit) { 9 | $('.flip').each(function () { 10 | var len = this.getAttribute('data-len'), 11 | html = ''; 12 | 13 | for (var i = 0; i < len; i++) { 14 | html += '

'; 15 | } 16 | 17 | $(this).html(html).flip({ 18 | isVertical: this.getAttribute('data-isvertical') === '1' 19 | }); 20 | }); 21 | } 22 | }; -------------------------------------------------------------------------------- /example/src/js/index/home.js: -------------------------------------------------------------------------------- 1 | //首页 2 | exports.load = function ($this, isInit) { 3 | if (isInit) { 4 | var $list = $this.find('.list'), 5 | html = ''; 6 | for (var p in $.fn) { 7 | html += '' + p + ''; 8 | } 9 | $list.append(html); 10 | } 11 | }; -------------------------------------------------------------------------------- /example/src/js/index/piccut.js: -------------------------------------------------------------------------------- 1 | //图片剪切 2 | 3 | require('piccut'); 4 | 5 | var $doc = $(document); 6 | 7 | 8 | //加载时执行 9 | exports.load = function ($this, isInit) { 10 | if (isInit) { 11 | var upEl = $('.avator_up').piccut({ 12 | fileEl: document.getElementById('file') 13 | //, isKeepScale: false 14 | //, cutHeight: 200 15 | //, isMinLimit: false 16 | //, cutX: 0 17 | })[0]; 18 | 19 | var showerEl = document.getElementById('shower'); 20 | $doc.on('click', '#btn_cut', function () { 21 | showerEl.src = upEl.getDataURL(); 22 | }); 23 | } 24 | }; -------------------------------------------------------------------------------- /example/src/js/index/picpager.js: -------------------------------------------------------------------------------- 1 | //相册功能 2 | 3 | require('picpager'); 4 | 5 | 6 | //加载时执行 7 | exports.load = function ($this, isInit) { 8 | if (isInit) { 9 | var page = 1; 10 | $.getScript('https://app.gd.sohu.com/minisite/xtep/20140530/get.php?vname=rs&act=list&page=' + page + '&code=aa1c9153608a7755b7c20e97c0eade27', function () { 11 | var $picpager = $('.picpager').picpager({ 12 | imgData: rs.data.detail.map(function (item) { 13 | return item.image; 14 | }), 15 | imgAttrName: 'image', 16 | slideCallback: function (index) { 17 | index + 1 === page * 10 && $.getScript('https://app.gd.sohu.com/minisite/xtep/20140530/get.php?vname=rs&act=list&page=' + ++page + '&code=aa1c9153608a7755b7c20e97c0eade27', function () { 18 | $picpager[0].addItem(rs.data.detail.map(function (item) { 19 | return item.image; 20 | })); 21 | }); 22 | } 23 | }); 24 | }); 25 | } 26 | }; -------------------------------------------------------------------------------- /example/src/js/index/scratchcard.js: -------------------------------------------------------------------------------- 1 | //刮刮卡 2 | 3 | require('scratchcard'); 4 | 5 | 6 | //加载时执行 7 | exports.load = function ($this, isInit) { 8 | if (isInit) { 9 | $('.scratchcard').each(function () { 10 | $(this).scratchcard({ 11 | text : '刮开有奖', 12 | imgSrc: 'img/4.jpg' 13 | }); 14 | }); 15 | } 16 | }; -------------------------------------------------------------------------------- /example/src/js/index/scroll.js: -------------------------------------------------------------------------------- 1 | //自定义滚动 2 | 3 | require('scroll'); 4 | 5 | 6 | //加载时执行 7 | exports.load = function load($this, isInit) { 8 | if (isInit) { 9 | $('.scroll').each(function () { 10 | $(this).scroll({ 11 | isVertical: this.getAttribute('data-isvertical') === '1' 12 | }); 13 | }); 14 | } 15 | }; -------------------------------------------------------------------------------- /example/src/js/index/share.js: -------------------------------------------------------------------------------- 1 | //分享 2 | 3 | var $doc = $(document), 4 | share = require('share'); 5 | 6 | var txtShare = document.title, 7 | picShare = 'http://www.sohu.com/upload/images20140108/sohulogo.png', 8 | urlShare = location.href; 9 | 10 | //分享按钮点击 11 | $doc.on('click', '.icon_share a', function () { 12 | share(urlShare, txtShare, picShare, this.getAttribute('data-provider')); 13 | }); -------------------------------------------------------------------------------- /example/src/js/index/turntable.js: -------------------------------------------------------------------------------- 1 | //转盘抽奖 2 | 3 | require('turntable'); 4 | 5 | //文档jq对象 6 | var $doc = $(document); 7 | 8 | exports.load = function ($this, isInit) { 9 | if (isInit) { 10 | var turntableEl = $('.turntable').turntable({ 11 | count: 10 12 | })[0]; 13 | 14 | $doc.on('click', '.turntable .btn_start', function () { 15 | var index = parseInt(Math.random() * 10); 16 | turntableEl.turnToIndex(index, function () { 17 | alert(index + 1); 18 | }); 19 | }); 20 | } 21 | }; -------------------------------------------------------------------------------- /example/src/js/index/ui.js: -------------------------------------------------------------------------------- 1 | //ui页 2 | 3 | //alert方法 4 | $.extend(window, require('alert')); -------------------------------------------------------------------------------- /example/src/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jq", 3 | "version": "0.0.0", 4 | 5 | "devDependencies": { 6 | "gulp": "^3.9.1", 7 | "gulp-plumber": "^1.1.0", 8 | "gulp-imagemin": "^3.2.0", 9 | "gulp-sass": "^3.1.0", 10 | "gulp-autoprefixer": "^3.1.1", 11 | "gulp-clean-css": "^3.0.4", 12 | "gulp-base64": "^0.1.3", 13 | "gulp-browserify": "^0.5.1", 14 | "gulp-uglify": "^2.1.2", 15 | "gulp-htmlmin": "^3.0.0", 16 | "gulp-file-include": "^1.1.0" 17 | }, 18 | 19 | "browser": { 20 | "artmpl": "./_lib/js/artmpl.js", 21 | "share": "./_lib/js/share.js", 22 | 23 | "jq": "../../jq.js", 24 | "base": "../../ui/base.js", 25 | "ui": "../../ui/ui.js", 26 | "alert": "../../plugin/alert.js", 27 | "dialog": "../../plugin/dialog.js", 28 | "carousel": "../../plugin/carousel.js", 29 | "customalert": "../../plugin/customalert.js", 30 | "flip": "../../plugin/flip.js", 31 | "piccut": "../../plugin/piccut.js", 32 | "picpager": "../../plugin/picpager.js", 33 | "scratchcard": "../../plugin/scratchcard.js", 34 | "scroll": "../../plugin/scroll.js", 35 | "scrollto": "../../plugin/scrollto.js", 36 | "swatchbook": "../../plugin/swatchbook.js", 37 | "turntable": "../../plugin/turntable.js" 38 | } 39 | } -------------------------------------------------------------------------------- /jqlite.js: -------------------------------------------------------------------------------- 1 | //jqlite.js 2 | (function (window, undefined) { 3 | 4 | /** 5 | * 选择器函数,兼容jQuery语法,实现jQuery大部分api 6 | * @param {Node|NodeList|string} sel 选择器 7 | * @returns {$init} 选择到的$对象 8 | */ 9 | var $ = function (sel) { 10 | return new $init(sel); 11 | }; 12 | 13 | var document = window.document, 14 | Node = window.Node, 15 | getComputedStyle = window.getComputedStyle, 16 | toString = {}.toString, 17 | tmpArray = [], 18 | slice = tmpArray.slice, 19 | indexOf = tmpArray.indexOf, 20 | cssPrefix = '-webkit-', 21 | classRegCache = {}, 22 | RegExp = window.RegExp, 23 | bodyEl = document.body, 24 | computedStyleCache = {}; 25 | 26 | /** 27 | * 选择器构造函数 28 | * @param {Node|NodeList|string} sel 选择器 29 | * @returns {$init} 选择到的$对象 30 | * @ignore 31 | */ 32 | function $init(sel) { 33 | this.length = 0; 34 | 35 | //字符选择器或html 36 | if (typeof sel === 'string') { 37 | //如果是html 38 | if (sel[0] === '<' && sel[sel.length - 1] === '>') { 39 | var tmpEl = document.createElement('div'); 40 | tmpEl.innerHTML = sel; 41 | //不用children,须保留文本节点 42 | return nodesToThis(tmpEl.childNodes, this); 43 | } 44 | 45 | //其他选择器 46 | return nodesToThis(document.querySelectorAll(sel), this); 47 | } 48 | 49 | //Node或window 50 | if (sel instanceof Node || sel === window) { 51 | this[this.length++] = sel; 52 | return this; 53 | } 54 | 55 | //NodeList 56 | if (sel && sel.length > 0) { 57 | return nodesToThis(sel, this); 58 | } 59 | } 60 | 61 | 62 | /** 63 | * 将node添加到this函数 64 | * @param {NodeList} nodes 被添加到$对象的node对象 65 | * @param {Object} obj 待添加node对象的$对象 66 | * @returns {Object} 添加了node对象的$对象 67 | * @ignore 68 | */ 69 | function nodesToThis(nodes, obj) { 70 | //nodes为null时 71 | if (!nodes) { 72 | return obj; 73 | } 74 | 75 | //NodeList 76 | forEach(nodes, function (item) { 77 | obj[obj.length++] = item; 78 | }); 79 | return obj; 80 | } 81 | 82 | /** 83 | * 生成class正式表达式函数 84 | * @param {String} name css类名 85 | * @returns {RegExp} css类名正式表达式 86 | * @ignore 87 | */ 88 | function classReg(name) { 89 | return classRegCache[name] || (classRegCache[name] = new RegExp('(^|\\s)' + name + '(\\s|$)')); 90 | } 91 | 92 | /** 93 | * 数组遍历函数 94 | * @param {Array} array 待遍历的数组 95 | * @param {Function} fn 回调函数 96 | * @ignore 97 | */ 98 | function forEach(array, fn) { 99 | for (var i = 0, len = array.length; i < len; i++) { 100 | fn(array[i]); 101 | } 102 | } 103 | 104 | /** 105 | * matchesSelector函数 106 | * @ignore 107 | */ 108 | var elProto = Element.prototype; 109 | elProto.matchesSelector || (elProto.matchesSelector = elProto.webkitMatchesSelector); 110 | 111 | /** 112 | * 返回元素默认样式值函数 113 | * @param {string} tagName 元素名 114 | * @param {string} key 样式key 115 | * @returns {string} 初始样式值 116 | * @ignore 117 | */ 118 | function getInitialStyle(tagName, key) { 119 | var prop = tagName + '-' + key; 120 | if (!computedStyleCache[prop]) { 121 | var tmpEl = document.createElement(tagName); 122 | bodyEl.appendChild(tmpEl); 123 | computedStyleCache[prop] = getComputedStyle(tmpEl)[key]; 124 | bodyEl.removeChild(tmpEl); 125 | } 126 | return computedStyleCache[prop]; 127 | } 128 | 129 | 130 | //判断是否为某种类型函数 131 | forEach(['Object', 'Array', 'Function'], function (item) { 132 | $['is' + item] = function (obj) { 133 | return toString.call(obj) === '[object ' + item + ']'; 134 | }; 135 | }); 136 | 137 | 138 | /** 139 | * 扩展函数 140 | * @param {Object} obj 扩展参数 141 | * @returns {Object} 返回扩展属性后的对象 142 | */ 143 | $.extend = function (obj) { 144 | if (obj === undefined) { 145 | return this; 146 | } 147 | 148 | //$.extend(obj) 149 | if (arguments.length === 1) { 150 | for (var p in obj) { 151 | this[p] = obj[p]; 152 | } 153 | return this; 154 | } 155 | 156 | //$.extend({}, defaults[, obj]) 157 | forEach(slice.call(arguments, 1), function (item) { 158 | for (var p in item) { 159 | obj[p] = item[p]; 160 | } 161 | }); 162 | return obj; 163 | }; 164 | 165 | 166 | //原型属性 167 | $.fn = $init.prototype = { 168 | constructor: $init, 169 | 170 | /** 171 | * 遍历元素(效率更高,但回调函数中this不指向元素,第一个参数指向元素) 172 | * @param {Function} fn 遍历回调函数 173 | * @returns {$init} $对象本身 174 | */ 175 | forEach: function (fn) { 176 | for (var i = 0, len = this.length; i < len; i++) { 177 | fn(this[i], i); 178 | } 179 | return this; 180 | }, 181 | 182 | /** 183 | * 取第i个元素 184 | * @param {number} i 索引值 185 | * @returns {$init} 选择后的$对象 186 | */ 187 | eq: function (i) { 188 | return $(this[i]); 189 | }, 190 | 191 | /** 192 | * 取子孙元素 193 | * @param {string} sel 选择器 194 | * @returns {$init} 选择后的$对象 195 | */ 196 | find: function (sel) { 197 | var els = []; 198 | this.forEach(function (el) { 199 | //根据当前元素查找符合sel的元素 200 | forEach(el.querySelectorAll(sel), function (item) { 201 | els.indexOf(item) < 0 && els.push(item); 202 | }); 203 | }); 204 | return $(els); 205 | }, 206 | 207 | /** 208 | * 取最近元素 209 | * @param {string} sel 选择器 210 | * @param {Node|NodeList|$init} context 选择范围 211 | * @returns {$init} 选择后的$对象 212 | */ 213 | closest: function (sel, context) { 214 | var curEl = this[0]; 215 | while (curEl && !curEl.matchesSelector(sel)) { 216 | //document没有matchesSelector 217 | var parentNode = curEl.parentNode; 218 | curEl = parentNode === document ? null : (curEl !== context && parentNode); 219 | } 220 | return $(curEl); 221 | }, 222 | 223 | /** 224 | * 取元素索引 225 | * @returns {number} 索引值 226 | */ 227 | index: function () { 228 | return indexOf.call(this[0].parentNode.children, this[0]); 229 | }, 230 | 231 | /** 232 | * 元素html取值/赋值 233 | * @param {string} html html值 234 | * @returns {$init|string} $对象本身|html值 235 | */ 236 | html: function (html) { 237 | return this.prop('innerHTML', html); 238 | }, 239 | 240 | /** 241 | * 元素text取值/赋值(textContent比innerText要好) 242 | * @param {string} text text值 243 | * @returns {$init|string} $对象本身|text值 244 | */ 245 | text: function (text) { 246 | return this.prop('textContent', text); 247 | }, 248 | 249 | /** 250 | * 元素取值/赋值 251 | * @param {string} val 待赋的值 252 | * @returns {$init|string} $对象本身|获取的值 253 | */ 254 | val: function (val) { 255 | return this.prop('value', val); 256 | }, 257 | 258 | /** 259 | * 元素属性取值/赋值 260 | * @param {Object|string} key 属性|属性对象 261 | * @param {string} val 属性值 262 | * @returns {$init|string} $对象本身|属性值 263 | */ 264 | attr: function (key, val) { 265 | return this.prop(key, val, true); 266 | }, 267 | 268 | /** 269 | * 元素对象属性取值/赋值 270 | * @param {Object|string} key 属性|属性对象 271 | * @param {string} val 属性值 272 | * @param {boolean} isAttr 属性值 273 | * @returns {$init|string} $对象本身|属性值 274 | */ 275 | prop: function (key, val, isAttr) { 276 | //$().prop(key) 277 | if (typeof key === 'string' && val === undefined) { 278 | return isAttr ? this[0].getAttribute(key) : this[0][key]; 279 | } 280 | return this.forEach(function (el) { 281 | //$().prop(obj) 282 | if ($.isObject(key)) { 283 | for (var p in key) { 284 | isAttr ? el.setAttribute(p, key[p]) : el[p] = key[p]; 285 | } 286 | return; 287 | } 288 | //$().prop(key,val) 289 | isAttr ? el.setAttribute(key, val) : el[key] = val; 290 | }); 291 | }, 292 | 293 | /** 294 | * 元素移除属性 295 | * @param {string} key 待移除的属性 296 | * @returns {$init} $对象本身 297 | */ 298 | removeAttr: function (key) { 299 | return this.forEach(function (el) { 300 | el.removeAttribute(key); 301 | }); 302 | }, 303 | 304 | /** 305 | * 元素css样式属性取值/赋值 306 | * @param {Object|string} key css属性|css对象 307 | * @param {string} val css属性值 308 | * @returns {$init|string} $对象本身|css属性值 309 | */ 310 | css: function (key, val) { 311 | //$().css(key) 312 | if (typeof key === 'string' && val === undefined) { 313 | //必须是node 314 | if (this[0] instanceof Node) { 315 | //计算样式 316 | var style = getComputedStyle(this[0]); 317 | return style[key] || style[cssPrefix + key]; 318 | } 319 | return; 320 | } 321 | return this.forEach(function (el) { 322 | var style = el.style; 323 | //$().css(obj) 324 | if ($.isObject(key)) { 325 | for (var p in key) { 326 | style[p] = style[cssPrefix + p] = key[p]; 327 | } 328 | return; 329 | } 330 | //$().css(key,val) 331 | style[key] = style[cssPrefix + key] = val; 332 | }); 333 | }, 334 | 335 | /** 336 | * 元素显示 337 | * @returns {$init} $对象本身 338 | */ 339 | show: function () { 340 | return this.forEach(function (el) { 341 | var style = el.style; 342 | if (style.display === 'none') { 343 | return style.display = null; 344 | } 345 | style.display = getInitialStyle(el.tagName, 'display'); 346 | }); 347 | }, 348 | 349 | /** 350 | * 元素隐藏 351 | * @returns {$init} $对象本身 352 | */ 353 | hide: function () { 354 | return this.css('display', 'none'); 355 | }, 356 | 357 | /** 358 | * 元素后置添加 359 | * @param {Node|NodeList|string|$init} el 添加的内容 360 | * @param {boolean} isBefore 是否前置添加 361 | * @returns {$init} $对象本身 362 | */ 363 | append: function (el, isBefore) { 364 | var $el = el instanceof $init ? el : $(el); 365 | return this.forEach(function (me) { 366 | $el.forEach(function (el) { 367 | isBefore ? me.insertBefore(el, me.firstChild) : me.appendChild(el); 368 | }); 369 | }); 370 | }, 371 | 372 | /** 373 | * 元素后置添加到 374 | * @param {Node|NodeList|string|$init} el 内容添加到的元素 375 | * @param {boolean} isBefore 是否前置添加 376 | * @returns {$init} $对象本身 377 | */ 378 | appendTo: function (el, isBefore) { 379 | var $el = el instanceof $init ? el : $(el); 380 | $el.append(this, isBefore); 381 | return this; 382 | }, 383 | 384 | /** 385 | * 元素添加class 386 | * @param {string} name css类名 387 | * @returns {$init} $对象本身 388 | */ 389 | addClass: function (name) { 390 | return this.forEach(function (el) { 391 | var oldClass = el.className; 392 | !classReg(name).test(oldClass) && (el.className += (oldClass ? ' ' : '') + name); 393 | }); 394 | }, 395 | 396 | /** 397 | * 元素移除class 398 | * @param {string} name css类名 399 | * @returns {$init} 返回$对象本身 400 | */ 401 | removeClass: function (name) { 402 | return this.forEach(function (el) { 403 | el.className = name === undefined ? '' : el.className.replace(classReg(name), ' ').trim(); 404 | }); 405 | }, 406 | 407 | /** 408 | * 元素判断是否有class 409 | * @param {string} name css类名 410 | * @returns {boolean} 是否有class 411 | */ 412 | hasClass: function (name) { 413 | return classReg(name).test(this[0].className); 414 | } 415 | 416 | }; 417 | 418 | /** 419 | * $实例属性扩展函数 420 | * @param {Object} obj 属性对象 421 | */ 422 | $.fn.extend = function (obj) { 423 | $.extend.call(this, obj); 424 | }; 425 | 426 | 427 | /** 428 | * 添加事件函数 429 | * @param {Node} el 绑定事件的元素 430 | * @param {string} type 事件类型 431 | * @param {Function} fn 事件响应函数 432 | * @param {string} sel 选择器 433 | * @ignore 434 | */ 435 | function addEvent(el, type, fn, sel) { 436 | el.addEventListener(type, sel === undefined ? fn : function (evt) { 437 | var matchEl = $(evt.target).closest(sel, el)[0]; 438 | matchEl && fn.call(matchEl, evt); 439 | }, false); 440 | } 441 | 442 | /** 443 | * 移除事件函数 444 | * @param {Node} el 解绑事件的元素 445 | * @param {string} type 事件类型 446 | * @param {Function} fn 事件响应函数 447 | * @ignore 448 | */ 449 | function removeEvent(el, type, fn) { 450 | el.removeEventListener(type, fn, false); 451 | } 452 | 453 | /** 454 | * 创建事件函数 455 | * @param {string} type 事件类型 456 | * @returns {Event} 事件 457 | * @ignore 458 | */ 459 | function createEvent(type) { 460 | var event = document.createEvent('Events'); 461 | //第二个参数:是否冒泡,第三个参数:是否可以preventDefault阻止事件 462 | event.initEvent(type, true, true); 463 | return event; 464 | } 465 | 466 | //扩展事件相关 467 | $.fn.extend({ 468 | 469 | /** 470 | * 元素绑定事件 471 | * @param {string} type 事件类型 472 | * @param {string} sel 选择器 473 | * @param {Function} fn 事件响应函数 474 | * @returns {$init} $对象本身 475 | */ 476 | on: function (type, sel, fn) { 477 | return this.forEach(function (el) { 478 | typeof sel === 'function' ? addEvent(el, type, sel) : addEvent(el, type, fn, sel); 479 | }); 480 | }, 481 | 482 | /** 483 | * 元素解绑事件 484 | * @param {string} type 事件类型 485 | * @param {Function} fn 事件响应函数 486 | * @returns {$init} $对象本身 487 | */ 488 | off: function (type, fn) { 489 | return this.forEach(function (el) { 490 | removeEvent(el, type, fn); 491 | }); 492 | }, 493 | 494 | /** 495 | * 元素事件触发 496 | * @param {string} type 事件类型 497 | * @returns {$init} $对象本身 498 | */ 499 | trigger: function (type) { 500 | type = createEvent(type); 501 | return this.forEach(function (el) { 502 | el.dispatchEvent(type); 503 | }); 504 | } 505 | }); 506 | 507 | 508 | //CommonJS 509 | if (typeof exports === 'object') { 510 | return module.exports = $; 511 | } 512 | 513 | //添加到全局变量 514 | window.jqlite = window.$ = $; 515 | 516 | })(window); -------------------------------------------------------------------------------- /plugin/alert.js: -------------------------------------------------------------------------------- 1 | /*通用弹框*/ 2 | (function ($) { 3 | 4 | //初始化html 5 | var html = '

' + 6 | '

' + 7 | '
'; 8 | $(document.body).append(html); 9 | 10 | 11 | //alert方法 12 | var alert = (function () { 13 | var $alert = $('#pi-alert'), 14 | $head = $alert.find('.pi-head'), 15 | $msg = $alert.find('.pi-msg'), 16 | $btnOk = $alert.find('.pi-btn-ok'), opts; 17 | 18 | //打开 19 | function open() { 20 | //打开窗口 21 | $alert.addClass('visible'); 22 | 23 | //响应事件 24 | var onOpen = opts.onOpen; 25 | typeof onOpen === 'function' && onOpen(); 26 | } 27 | 28 | //关闭 29 | function close() { 30 | //关闭窗口 31 | $alert.removeClass('visible'); 32 | 33 | //响应事件 34 | var onClose = opts.onClose; 35 | typeof onClose === 'function' && onClose(); 36 | } 37 | 38 | //确定按钮点击 39 | $alert.on('click', '.pi-btn-ok', function () { 40 | //disabled时,不响应 41 | if ($btnOk.hasClass('disabled')) { 42 | return; 43 | } 44 | 45 | //关闭 46 | close(); 47 | 48 | //响应事件放在靠后 49 | var btnOkClick = opts.btnOkClick; 50 | typeof btnOkClick === 'function' && btnOkClick(); 51 | }).on('click', function (evt) { 52 | //点击背景时关闭窗口 53 | opts.isHideOnBgClick && $(evt.target).closest('.pi-box').length === 0 && close(); 54 | }); 55 | 56 | return function (options) { 57 | //配置项 58 | typeof options !== 'object' && (options = {msg: options}); 59 | opts = $.extend({}, alert.defaults, options); 60 | 61 | //显示内容 62 | $head.html(opts.head); 63 | $msg.html(opts.msg); 64 | $btnOk.text(opts.okTxt); 65 | 66 | //打开 67 | open(); 68 | }; 69 | })(); 70 | alert.defaults = { 71 | head: '提示', 72 | msg: '内容', 73 | okTxt: '确定', 74 | //是否在点击背景时隐藏 75 | isHideOnBgClick: false 76 | }; 77 | 78 | 79 | //confirm方法 80 | var confirm = (function () { 81 | var $confirm = $('#pi-confirm'), 82 | $head = $confirm.find('.pi-head'), 83 | $msg = $confirm.find('.pi-msg'), 84 | $btnOk = $confirm.find('.pi-btn-ok'), 85 | $btnCancel = $confirm.find('.pi-btn-cancel'), opts; 86 | 87 | //打开 88 | function open() { 89 | //打开窗口 90 | $confirm.addClass('visible'); 91 | 92 | //响应事件 93 | var onOpen = opts.onOpen; 94 | typeof onOpen === 'function' && onOpen(); 95 | } 96 | 97 | //关闭 98 | function close() { 99 | //关闭窗口 100 | $confirm.removeClass('visible'); 101 | 102 | //响应事件 103 | var onClose = opts.onClose; 104 | typeof onClose === 'function' && onClose(); 105 | } 106 | 107 | //确定和取消按钮点击 108 | $confirm.on('click', '.pi-btn-ok', function () { 109 | //disabled时,不响应 110 | if ($btnOk.hasClass('disabled')) { 111 | return; 112 | } 113 | 114 | //关闭 115 | close(); 116 | 117 | //响应事件放在靠后 118 | var btnOkClick = opts.btnOkClick; 119 | typeof btnOkClick === 'function' && btnOkClick(); 120 | }).on('click', '.pi-btn-cancel', function () { 121 | //关闭 122 | close(); 123 | 124 | //响应事件放在靠后 125 | var btnCancelClick = opts.btnCancelClick; 126 | typeof btnCancelClick === 'function' && btnCancelClick(); 127 | }).on('click', function (evt) { 128 | //点击背景时关闭窗口 129 | opts.isHideOnBgClick && $(evt.target).closest('.pi-box').length === 0 && close(); 130 | }); 131 | 132 | return function (options) { 133 | //配置项 134 | typeof options !== 'object' && (options = {msg: options}); 135 | //配置项 136 | opts = $.extend({}, confirm.defaults, options); 137 | 138 | //设置内容 139 | $head.html(opts.head); 140 | $msg.html(opts.msg); 141 | $btnOk.text(opts.okTxt); 142 | $btnCancel.text(opts.cancelTxt); 143 | 144 | //打开 145 | open(); 146 | }; 147 | })(); 148 | confirm.defaults = $.extend({}, alert.defaults, { 149 | cancelTxt: '取消' 150 | }); 151 | 152 | 153 | //tooltip方法 154 | var tooltip = (function () { 155 | var $tooltip = $('#pi-tooltip'), 156 | timeout; 157 | 158 | return function (msg, isOk, time) { 159 | $tooltip.html(msg).addClass('visible'); 160 | 161 | //ok状态 162 | isOk ? $tooltip.addClass('ok') : $tooltip.removeClass('ok'); 163 | 164 | //定时隐藏 165 | clearTimeout(timeout); 166 | timeout = setTimeout(function () { 167 | $tooltip.removeClass('visible'); 168 | }, time || 2000); 169 | }; 170 | })(); 171 | 172 | 173 | //导出对象 174 | var out = { 175 | alert: alert, 176 | confirm: confirm, 177 | tooltip: tooltip 178 | }; 179 | 180 | //CommonJS 181 | if (typeof exports === 'object') { 182 | return module.exports = out; 183 | } 184 | 185 | $.extend(window, out); 186 | 187 | })($); -------------------------------------------------------------------------------- /plugin/alert.scss: -------------------------------------------------------------------------------- 1 | /*通用弹框样式*/ 2 | 3 | //变量 4 | $alert-box-width: 5.6rem !default; 5 | $tooltip-width: 5rem !default; 6 | 7 | /*弹框*/ 8 | #pi-alert, #pi-confirm { 9 | @extend %ph_pffull; 10 | background: rgba(#000, 0.7); 11 | z-index: 999; 12 | /*不能跟着base走,要有自己的颜色,以名base设置为白色时,颜色看不见了*/ 13 | color: #333; 14 | /*内容居中*/ 15 | @extend %ph_center; 16 | //动画 17 | @extend .transition; 18 | @extend %ph_hidden; 19 | 20 | /*显示弹出框*/ 21 | &.visible { 22 | @extend %ph_visible; 23 | 24 | .pi-box { 25 | transform: none; 26 | } 27 | } 28 | 29 | /*弹框容器*/ 30 | .pi-box { 31 | width: $alert-box-width; 32 | @extend .center; 33 | padding-bottom: 0.3rem; 34 | border-radius: 0.16rem; 35 | background: #fff; 36 | overflow: hidden; 37 | //动画 38 | @extend .transform; 39 | transform: scale3d(1.2, 1.2, 1); 40 | } 41 | 42 | /*标题*/ 43 | .pi-head { 44 | line-height: 2.8; 45 | background: #f1f1f1; 46 | box-shadow: 0 0 2px rgba(#000, 0.5); 47 | } 48 | 49 | /*信息*/ 50 | .pi-msg { 51 | padding: 0.3rem 0.4rem; 52 | } 53 | 54 | /*按钮*/ 55 | [class^="pi-btn"] { 56 | @extend .btn; 57 | width: 40%; 58 | margin: 0 0.1rem; 59 | } 60 | } 61 | 62 | /*alert提示框*/ 63 | #pi-alert { 64 | .pi-btn-ok { 65 | width: 85%; 66 | } 67 | } 68 | 69 | /*信息提示*/ 70 | #pi-tooltip { 71 | @extend %ph_fixed; 72 | top: 45%; 73 | left: 50%; 74 | padding: 0.2rem; 75 | width: $tooltip-width; 76 | background-color: #ef8f00; 77 | color: #fff; 78 | @extend .center; 79 | box-shadow: 1px 1px 3px rgba(#000, 0.5); 80 | z-index: 999; 81 | //动画 82 | @extend .transition; 83 | @extend %ph_hidden; 84 | transform: translate3d(-50%, -0.4rem, 0); 85 | 86 | &.ok { 87 | background-color: #68af02; 88 | } 89 | 90 | &.visible { 91 | @extend %ph_visible; 92 | transform: translate3d(-50%, 0, 0); 93 | } 94 | } -------------------------------------------------------------------------------- /plugin/carousel.js: -------------------------------------------------------------------------------- 1 | /* 2 | * carousel.js 3 | * 焦点图js 4 | */ 5 | (function (window, $) { 6 | 7 | $.fn.carousel = function (options) { 8 | 9 | // 每个元素执行 10 | return this.each(function () { 11 | var opts = $.extend({}, $.fn.carousel.defaults, options); 12 | 13 | // 配置项 14 | var isVertical = opts.isVertical, 15 | swipThreshold = opts.swipThreshold, 16 | swipSpanThreshold = opts.swipSpanThreshold, 17 | isAutoPlay = opts.isAutoPlay, 18 | autoPlayInter = opts.autoPlayInter, 19 | slideCallback = opts.slideCallback, 20 | isShowTitle = opts.isShowTitle, 21 | isShowPager = opts.isShowPager, 22 | inited = opts.inited, 23 | initIndex = opts.initIndex, 24 | pullRatio = opts.pullRatio, 25 | isLoop = opts.isLoop; 26 | 27 | // 变量 28 | var $this = $(this), 29 | me = this, 30 | $wrap, wrapElStyle, 31 | $items, itemCount, 32 | $allItems, allItemCount, 33 | $title, $pagers, 34 | duration; 35 | 36 | // 初始化函数 37 | function init() { 38 | // items 39 | $items = $this.children('*'); 40 | itemCount = $items.length; 41 | 42 | // html 43 | $this.addClass('pi-carousel' + (isVertical ? ' vertical' : '')) 44 | .html('
'); 45 | 46 | // wrap 47 | $wrap = $this.find('.pi-wrap').append($items); 48 | wrapElStyle = $wrap[0].style; 49 | duration = parseFloat($wrap.css('transition-duration')) * 1000; 50 | 51 | // 如果需要循环滚动,需要多添加两个元素 52 | isLoop && $wrap 53 | // 在最后添加第一个元素 54 | .append($items[0].outerHTML) 55 | // 在最前添加最后一个元素 56 | .prepend($items[itemCount - 1].outerHTML); 57 | 58 | // allItems 59 | $allItems = $wrap.children('*'); 60 | allItemCount = $allItems.length; 61 | 62 | // title 63 | isShowTitle && $this.append($title = $('
')); 64 | 65 | // pager 66 | if (isShowPager) { 67 | var spanHtml = ''; 68 | for (var i = 0; i < itemCount; i++) { 69 | spanHtml += ''; 70 | } 71 | var pagerHtml = '
' + spanHtml + '
'; 72 | $this.append(pagerHtml); 73 | $pagers = $this.find('.pi-pager>span'); 74 | } 75 | 76 | // html初始化完成回调 77 | typeof inited === 'function' && inited($items); 78 | 79 | // 初始化事件 80 | initEvent(); 81 | } 82 | 83 | // 初始化事件函数 84 | function initEvent() { 85 | var width, height, inter, index = initIndex, 86 | startX, startY, 87 | swipSpan, isMoving; 88 | 89 | // 设置尺寸函数 90 | function setSize() { 91 | width = $this.width(); 92 | height = $this.height(); 93 | 94 | // 水平方向滚动 95 | if (!isVertical) { 96 | // 如果是循环滚动 97 | isLoop && (wrapElStyle.marginLeft = -width + 'px'); 98 | wrapElStyle.width = width * allItemCount + 'px'; 99 | $allItems.css('width', width + 'px'); 100 | } 101 | // 竖直方向滚动 102 | else { 103 | // 如果是循环滚动 104 | isLoop && (wrapElStyle.marginTop = -height + 'px'); 105 | wrapElStyle.height = height * allItemCount + 'px'; 106 | $allItems.css('height', height + 'px'); 107 | } 108 | // 显示 109 | wrapElStyle.visibility = 'visible'; 110 | } 111 | 112 | // 设置inter函数 113 | function setInter() { 114 | isAutoPlay && (inter = setInterval(function () { 115 | ++index; 116 | !isLoop && index === itemCount && (index = 0); 117 | 118 | // 加上动画 119 | $wrap.removeClass('notrans'); 120 | slide(); 121 | }, autoPlayInter)); 122 | } 123 | 124 | // 移动到函数 125 | function slide(swipSpan) { 126 | var translate = -index * (isVertical ? height : width), 127 | transform; 128 | 129 | // touchmove跟手指滚动 130 | if (typeof swipSpan === 'number') { 131 | if (!isLoop) { 132 | // 起点或者终点 133 | if (index === 0 && swipSpan > 0 || index === itemCount - 1 && swipSpan < 0) { 134 | // 模拟拉不动的操作体验 135 | swipSpan /= pullRatio; 136 | } 137 | } 138 | translate += swipSpan; 139 | } 140 | // touchend时滚动动画 141 | else { 142 | var $item = $items.eq(index); 143 | // item存在 144 | if ($item.length) { 145 | // 滚动回调函数 146 | typeof slideCallback === 'function' && slideCallback.call($items, index); 147 | 148 | // 添加当前类 149 | $items.removeClass('current').eq(index).addClass('current'); 150 | 151 | // title 152 | isShowTitle && $title.html($item.attr('data-title')); 153 | 154 | // pager 155 | isShowPager && $pagers.removeClass('selected').eq(index).addClass('selected'); 156 | } 157 | 158 | // 如果是循环滚动 159 | isLoop && setTimeout(function () { 160 | // 第一帧滑到最后一帧 161 | index < 0 && me.slideToIndex(itemCount - 1, 1); 162 | // 最后一帧滑到第一帧 163 | index === itemCount && me.slideToIndex(0, 1); 164 | }, duration); 165 | } 166 | 167 | transform = 'translate3d(' + (isVertical ? '0,' + translate + 'px,0' : translate + 'px,0,0') + ')'; 168 | // 作动画 169 | $wrap.css('transform', transform); 170 | } 171 | 172 | 173 | // 初始化 174 | // 设置尺寸 175 | setSize(); 176 | 177 | // 暴露slideToIndex方法 178 | me.slideToIndex = function (i, isNoAni) { 179 | if (typeof i !== 'number') { 180 | return console.log('index应为数字'); 181 | } 182 | 183 | // 是否没有动画 184 | isNoAni ? $wrap.addClass('notrans') : $wrap.removeClass('notrans'); 185 | 186 | index = i; 187 | slide(); 188 | }; 189 | 190 | // 暴露prev方法 191 | me.prev = function () { 192 | --index; 193 | !isLoop && index < 0 && (index = itemCount - 1); 194 | slide(); 195 | }; 196 | 197 | // 暴露next方法 198 | me.next = function () { 199 | ++index; 200 | !isLoop && index === itemCount && (index = 0); 201 | slide(); 202 | }; 203 | 204 | 205 | // 触摸开始事件 206 | $this.on('touchstart', function (evt) { 207 | var touch = evt.targetTouches ? evt.targetTouches[0] : evt; 208 | 209 | // 记录触摸开始位置 210 | startX = touch.pageX; 211 | startY = touch.pageY; 212 | 213 | // 重置swipSpan 214 | swipSpan = 0; 215 | // 重置手指拖拽移动 216 | isMoving = false; 217 | // 取消动画 218 | $wrap.addClass('notrans'); 219 | // 取消自动轮播 220 | isAutoPlay && clearInterval(inter); 221 | }); 222 | 223 | // 触摸移动事件 224 | $this.on('touchmove', function (evt) { 225 | var touch = evt.targetTouches ? evt.targetTouches[0] : evt, 226 | // x轴滑动距离 227 | swipSpanX = touch.pageX - startX, 228 | absX = Math.abs(swipSpanX), 229 | // y轴滑动距离 230 | swipSpanY = touch.pageY - startY, 231 | absY = Math.abs(swipSpanY); 232 | 233 | // 左右 234 | if (!isVertical) { 235 | // x轴滑动距离大于y轴 y轴滑动距离小于阈值,说明的确是左右滑动 236 | if (isMoving || absY < absX || absY < swipSpanThreshold) { 237 | evt.preventDefault(); 238 | evt.stopPropagation(); 239 | slide(swipSpan = swipSpanX); 240 | // 已经满足滚动条件,且正在手指拖动 241 | isMoving = true; 242 | } 243 | } 244 | // 上下 245 | else { 246 | // y轴滑动距离大于x轴 x轴滑动距离小于阈值,说明的确是上下滑动 247 | if (isMoving || absX < absY || absX < swipSpanThreshold) { 248 | evt.preventDefault(); 249 | evt.stopPropagation(); 250 | slide(swipSpan = swipSpanY); 251 | // 已经满足滚动条件,且正在手指拖动 252 | isMoving = true; 253 | } 254 | } 255 | }); 256 | 257 | // 触摸结束事件 258 | $this.on('touchend', function () { 259 | // 向右,下 260 | if (swipSpan > swipThreshold) { 261 | --index; 262 | !isLoop && index < 0 && (index = 0); 263 | } 264 | // 向左,上 265 | else if (swipSpan < -swipThreshold) { 266 | ++index; 267 | !isLoop && index === itemCount && (index = itemCount - 1); 268 | } 269 | 270 | // 加上动画 271 | $wrap.removeClass('notrans'); 272 | // 滚动(swipSpan === undefined时无动画) 273 | swipSpan !== 0 && slide(); 274 | 275 | // 自动轮播 276 | setInter(); 277 | }).trigger('touchend'); 278 | 279 | // pager点击事件 280 | isShowPager && $this.on('click', '.pi-pager>span', function () { 281 | var index = $(this).index(); 282 | me.slideToIndex(index); 283 | }); 284 | 285 | // 屏幕尺寸改变事件 286 | window.addEventListener('resize', function () { 287 | var w = $this.width(); 288 | if (w > 0) { 289 | setSize(); 290 | slide(0); 291 | } 292 | }, false); 293 | 294 | } 295 | 296 | 297 | // 初始化 298 | init(); 299 | 300 | }); 301 | 302 | }; 303 | $.fn.carousel.defaults = { 304 | // 是否竖直方向滚动 305 | isVertical: false, 306 | // 滑动阈值 307 | swipThreshold: 100, 308 | // 滑动距离阈值 309 | swipSpanThreshold: 10, 310 | // 是否自动轮播 311 | isAutoPlay: true, 312 | // 轮播inter 313 | autoPlayInter: 8000, 314 | // 轮播回调函数 315 | slideCallback: null, 316 | // 是否显示title 317 | isShowTitle: true, 318 | // 是否显示pager 319 | isShowPager: true, 320 | // 初始化完成回调函数 321 | inited: null, 322 | // 初始index 323 | initIndex: 0, 324 | // first和last拉不动的比率 325 | pullRatio: 3, 326 | // 是否可以循环切换 327 | isLoop: false 328 | }; 329 | 330 | })(window, $); -------------------------------------------------------------------------------- /plugin/carousel.scss: -------------------------------------------------------------------------------- 1 | /* 2 | plugin/carousel 3 | 焦点图样式 4 | */ 5 | $pi-carousel-pager-radius: 0.08rem !default; 6 | 7 | .pi-carousel 8 | { 9 | overflow: hidden; 10 | /*防止动画过程闪烁*/ 11 | backface-visibility: hidden; 12 | position: relative; 13 | 14 | /*垂直滚动样式*/ 15 | &.vertical 16 | { 17 | & > .pi-wrap > * 18 | { 19 | float: none; 20 | } 21 | 22 | & > .pi-pager > span 23 | { 24 | display: block; 25 | } 26 | } 27 | 28 | /*滚动容器*/ 29 | .pi-wrap 30 | { 31 | @extend .transform; 32 | visibility: hidden; 33 | 34 | & > * 35 | { 36 | display: block; 37 | float: left; 38 | overflow: hidden; 39 | } 40 | } 41 | 42 | /*title*/ 43 | .pi-title 44 | { 45 | @extend %ph_palb; 46 | width: 100%; 47 | line-height: 1.1; 48 | background-color: rgba(#000, 0.5); 49 | color: #fff; 50 | padding: 0.2rem; 51 | text-shadow: 0 0 0.06rem rgba(#000, 0.8); 52 | } 53 | 54 | /*pager*/ 55 | .pi-pager 56 | { 57 | @extend %ph_parb; 58 | line-height: 0; 59 | padding: $pi-carousel-pager-radius; 60 | 61 | & > span 62 | { 63 | display: inline-block; 64 | margin: $pi-carousel-pager-radius; 65 | border: $pi-carousel-pager-radius solid rgba(#fff, 0.5); 66 | border-radius: 50%; 67 | box-shadow: 0 0 0.06rem rgba(#000, 0.5); 68 | cursor: pointer; 69 | 70 | &.selected 71 | { 72 | box-shadow: 0 0 0.06rem rgba(#000, 0.9); 73 | border-color: rgba(#fff, 0.9); 74 | } 75 | } 76 | } 77 | } -------------------------------------------------------------------------------- /plugin/dialog.js: -------------------------------------------------------------------------------- 1 | /*通用弹框*/ 2 | (function (window, $) { 3 | 4 | //初始化html 5 | var html = '
' + 6 | '
'; 7 | $(document.body).append(html); 8 | 9 | 10 | //dialog方法 11 | var dialog = (function () { 12 | var $dialog = $('#pi-dialog'), 13 | $box = $dialog.find('.pi-box'), 14 | $tempbox = $dialog.find('.tempbox'), 15 | htmlEl = document.documentElement, 16 | opts, elCache = {}; 17 | 18 | //关闭按钮点击 19 | $dialog.on('click', '.btn_close', function () { 20 | dialog.close(); 21 | }); 22 | 23 | return function (options) { 24 | //配置项 25 | typeof options !== 'object' && (options = {sel: options}); 26 | opts = $.extend({}, dialog.defaults, options); 27 | 28 | //显示的元素 29 | var sel = opts.sel, 30 | $el = elCache[sel] || (elCache[sel] = $(sel)), 31 | width = $el[0].offsetWidth, 32 | height = $el[0].offsetHeight; 33 | 34 | //高度限定不超过窗口高度 35 | var wHeight = htmlEl.clientHeight; 36 | height > wHeight && (height = wHeight); 37 | 38 | //设置位置尺寸 39 | $box.css({ 40 | width : width + 'px', 41 | height : height + 'px', 42 | 'margin-left': -width / 2 + 'px', 43 | 'margin-top' : -height / 2 + 'px' 44 | }).append($el); 45 | 46 | //打开窗口 47 | $dialog.addClass('visible'); 48 | 49 | //关闭函数 50 | dialog.close = function () { 51 | var onClose = opts.onClose; 52 | typeof onClose === 'function' && onClose(); 53 | 54 | //关闭窗口 55 | $dialog.removeClass('visible'); 56 | 57 | //重置内容 58 | setTimeout(function () { 59 | $el.appendTo($tempbox); 60 | }, parseFloat($dialog.css('transition-duration')) * 1000); 61 | }; 62 | }; 63 | })(); 64 | dialog.defaults = {}; 65 | 66 | 67 | //modal方法 68 | var modal = (function () { 69 | var $modal = $('#pi-modal'), 70 | $box = $modal.find('.pi-box'), 71 | $iframe = $modal.find('iframe'), 72 | htmlEl = document.documentElement, opts; 73 | 74 | //关闭按钮点击 75 | $modal.on('click', '.btn_close', function () { 76 | modal.close(); 77 | }); 78 | 79 | return function (options) { 80 | //配置项 81 | typeof options !== 'object' && (options = {href: options}); 82 | opts = $.extend({}, modal.defaults, options); 83 | 84 | //高度限定不超过窗口高度 85 | var wHeight = htmlEl.clientHeight; 86 | opts.height > wHeight && (opts.height = wHeight); 87 | 88 | //设置页面 89 | $iframe.attr({ 90 | width : opts.width, 91 | height: opts.height, 92 | src : opts.href 93 | }); 94 | 95 | //设置位置尺寸 96 | $box.css({ 97 | 'margin-left': -opts.width / 2 + 'px', 98 | 'margin-top' : -opts.height / 2 + 'px' 99 | }); 100 | 101 | //打开窗口 102 | $modal.addClass('visible'); 103 | 104 | //关闭函数 105 | modal.close = function () { 106 | var onClose = opts.onClose; 107 | typeof onClose === 'function' && onClose(); 108 | 109 | //关闭窗口 110 | $modal.removeClass('visible'); 111 | 112 | //重置页面 113 | setTimeout(function () { 114 | $iframe.attr('src', ''); 115 | }, parseFloat($modal.css('transition-duration')) * 1000); 116 | }; 117 | }; 118 | })(); 119 | modal.defaults = { 120 | width : window.innerWidth, 121 | height: window.innerHeight 122 | }; 123 | 124 | 125 | //导出对象 126 | var exports = { 127 | dialog: dialog, 128 | modal : modal 129 | }; 130 | 131 | //CommonJS 132 | if (typeof exports === 'object') { 133 | return module.exports = exports; 134 | } 135 | 136 | $.extend(window, exports); 137 | 138 | })(window, $); -------------------------------------------------------------------------------- /plugin/dialog.scss: -------------------------------------------------------------------------------- 1 | /*通用弹窗样式*/ 2 | 3 | /*弹窗*/ 4 | .pi-dialog 5 | { 6 | @extend %ph_pffull; 7 | background: rgba(#000, 0.7); 8 | z-index: 999; 9 | //动画 10 | @extend .transition; 11 | @extend %ph_hidden; 12 | 13 | /*显示弹出框*/ 14 | &.visible 15 | { 16 | @extend %ph_visible; 17 | 18 | .pi-box 19 | { 20 | transform: none; 21 | } 22 | } 23 | 24 | /*弹窗容器*/ 25 | .pi-box 26 | { 27 | @extend %ph_absolute; 28 | left: 50%; 29 | top: 50%; 30 | overflow: hidden; 31 | background: #fff; 32 | //动画 33 | @extend .transform; 34 | transform: scale3d(0.8, 0.8, 1); 35 | } 36 | 37 | /*关闭弹窗按钮*/ 38 | .btn_close 39 | { 40 | color: #fff; 41 | @extend %ph_absolute; 42 | right: 4px; 43 | top: 4px; 44 | font-size: 0.6rem; 45 | border-radius: 50%; 46 | background: #393a3c; 47 | width: 1em; 48 | line-height: 1; 49 | @extend .center; 50 | overflow: hidden; 51 | z-index: 9; 52 | 53 | &:hover 54 | { 55 | background: #e42601; 56 | transform: rotateZ(90deg); 57 | } 58 | } 59 | } 60 | 61 | /*弹出页面和弹出窗口*/ 62 | #pi-dialog, #pi-modal 63 | { 64 | @extend .pi-dialog; 65 | } 66 | 67 | /*弹出窗口*/ 68 | #pi-dialog 69 | { 70 | .pi-box 71 | { 72 | & > * 73 | { 74 | @extend %ph_visible; 75 | } 76 | } 77 | 78 | .tempbox 79 | { 80 | @extend %ph_hidden; 81 | } 82 | } 83 | 84 | /*弹出页面*/ 85 | #pi-modal 86 | { 87 | .pi-box 88 | { 89 | line-height: 0; 90 | } 91 | } -------------------------------------------------------------------------------- /plugin/flip.js: -------------------------------------------------------------------------------- 1 | /* 2 | * flip.js 3 | * 3d翻转效果js 4 | */ 5 | (function(window, $) { 6 | 7 | $.fn.flip = function(options) { 8 | 9 | //每个元素执行 10 | return this.each(function() { 11 | var opts = $.extend({}, $.fn.flip.defaults, options); 12 | 13 | //配置项 14 | var isVertical = opts.isVertical, 15 | swipThreshold = opts.swipThreshold, 16 | swipSpanThreshold = opts.swipSpanThreshold, 17 | rate = opts.rate, 18 | slideCallback = opts.slideCallback; 19 | 20 | //变量 21 | var $this = $(this), 22 | $items = $this.children('*'); 23 | 24 | //初始化函数 25 | function init() { 26 | $this.addClass('pi-flip'); 27 | 28 | //初始化第一个item显示 29 | $items.eq(0).addClass('visible'); 30 | //滚动回调函数 31 | typeof slideCallback === 'function' && slideCallback(0); 32 | 33 | //初始化事件 34 | initEvent(); 35 | } 36 | 37 | //初始化事件函数 38 | function initEvent() { 39 | var itemCount = $items.length, 40 | index = 0, 41 | duration = parseFloat($items.css('transition-duration')) * 1000, 42 | startX, startY, 43 | swipSpan, isAnimating, 44 | width = $this.width(); 45 | 46 | //复位函数 47 | function reset(me) { 48 | me.style.cssText = ''; 49 | } 50 | 51 | //旋转到函数 52 | function rotate(swipSpan) { 53 | var transform; 54 | 55 | if (typeof swipSpan === 'number') { 56 | var deg = Math.sqrt(Math.abs(swipSpan) / width) * 130; 57 | if (swipSpan < 0) { 58 | deg = -deg; 59 | } 60 | $items.each(function(i) { 61 | var $this = $(this); 62 | if (i === index) { 63 | transform = isVertical ? 'rotate3d(1,0,0,' + -deg + 'deg)' : 'rotate3d(0,1,0,' + deg + 'deg)'; 64 | $this.css({ 65 | 'transform': transform 66 | }); 67 | } 68 | else { 69 | transform = isVertical ? 'rotate3d(1,0,0,' + (180 - deg) + 'deg)' : 'rotate3d(0,1,0,' + -(180 - deg) + 'deg)'; 70 | $this.css({ 71 | 'transform': transform 72 | }); 73 | } 74 | }); 75 | } 76 | else { 77 | isAnimating = true; 78 | //滚动回调函数 79 | $.isFunction(slideCallback) && slideCallback(index); 80 | 81 | $items.each(function(i) { 82 | var $this = $(this); 83 | if (i === index) { 84 | transform = isVertical ? 'rotate3d(1,0,0,' + -(swipSpan ? 0 : -360) + 'deg)' : 'rotate3d(0,1,0,' + (swipSpan ? 0 : -360) + 'deg)'; 85 | $this.addClass('visible').css({ 86 | 'transform': transform 87 | }); 88 | } 89 | else { 90 | transform = isVertical ? 'rotate3d(1,0,0,' + -(swipSpan ? 180 : -180) + 'deg)' : 'rotate3d(0,1,0,' + (swipSpan ? 180 : -180) + 'deg)'; 91 | $this.removeClass('visible').css({ 92 | 'transform': transform 93 | }); 94 | } 95 | }); 96 | 97 | //延迟复位 98 | setTimeout(function() { 99 | //加上动画 100 | $items.addClass('notrans').each(function() { 101 | reset(this); 102 | }); 103 | isAnimating = false; 104 | }, duration); 105 | } 106 | } 107 | 108 | //触摸开始事件 109 | $this.on('touchstart', function(evt) { 110 | var touch = evt.targetTouches ? evt.targetTouches[0] : evt; 111 | 112 | //记录触摸开始位置 113 | startX = touch.pageX; 114 | startY = touch.pageY; 115 | //重置swipSpan 116 | swipSpan = 0; 117 | 118 | //去掉动画 119 | $items.addClass('notrans'); 120 | }); 121 | 122 | //触摸移动事件 123 | $this.on('touchmove', function(evt) { 124 | var touch = evt.targetTouches ? evt.targetTouches[0] : evt, 125 | // x轴滑动距离 126 | swipSpanX = touch.pageX - startX, 127 | absX = Math.abs(swipSpanX), 128 | // y轴滑动距离 129 | swipSpanY = touch.pageY - startY, 130 | absY = Math.abs(swipSpanY); 131 | 132 | //上下 133 | if (isVertical) { 134 | //x轴滑动距离小于阈值,或y轴滑动距离大于x轴,说明的确是上下滑动 135 | if (absX < swipSpanThreshold || absX < absY) { 136 | evt.preventDefault(); 137 | evt.stopPropagation(); 138 | !isAnimating && rotate(swipSpan = swipSpanY / rate); 139 | } 140 | } 141 | //左右 142 | else { 143 | //y轴滑动距离小于阈值,或x轴滑动距离大于y轴,说明的确是左右滑动 144 | if (absY < swipSpanThreshold || absY < absX) { 145 | evt.preventDefault(); 146 | evt.stopPropagation(); 147 | !isAnimating && rotate(swipSpan = swipSpanX / rate); 148 | } 149 | } 150 | }); 151 | 152 | //触摸结束事件 153 | $this.on('touchend', function() { 154 | if (!isAnimating) { 155 | //达到滚动阈值 156 | if (Math.abs(swipSpan) > swipThreshold) { 157 | // 向右,下 158 | if (swipSpan > 0 && --index === -1) { 159 | index = itemCount - 1; 160 | } 161 | // 向左,上 162 | else if (swipSpan < 0 && ++index === itemCount) { 163 | index = 0; 164 | } 165 | 166 | //加上动画 167 | $items.removeClass('notrans'); 168 | rotate(swipSpan > 0); 169 | } 170 | else if (swipSpan !== 0) { 171 | //加上动画 172 | $items.eq(index).removeClass('notrans'); 173 | reset($items[index]); 174 | } 175 | } 176 | }); 177 | } 178 | 179 | 180 | //初始化 181 | init(); 182 | 183 | }); 184 | 185 | }; 186 | $.fn.flip.defaults = { 187 | //是否竖直方向滚动 188 | isVertical: false, 189 | //滑动阈值 190 | swipThreshold: 60, 191 | // 滑动距离阈值 192 | swipSpanThreshold: 10, 193 | //比率 194 | rate: 1.3, 195 | //轮播回调函数 196 | slideCallback: null 197 | }; 198 | 199 | })(window, $); -------------------------------------------------------------------------------- /plugin/flip.scss: -------------------------------------------------------------------------------- 1 | /* 2 | plugin/flip 3 | 3d翻转效果样式 4 | */ 5 | .pi-flip 6 | { 7 | position: relative; 8 | perspective: 1000; 9 | 10 | & > * 11 | { 12 | @extend %ph_pafull; 13 | @extend .transition; 14 | opacity: 0; 15 | 16 | &.visible 17 | { 18 | opacity: 1; 19 | z-index: 1; 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /plugin/piccut.js: -------------------------------------------------------------------------------- 1 | /* 2 | * piccut.js 3 | * 图片裁切功能js 4 | */ 5 | (function (window, $) { 6 | 7 | $.fn.piccut = function (options) { 8 | 9 | var URL = window.URL || window.webkitURL; 10 | 11 | //每个元素执行 12 | return this.each(function () { 13 | var opts = $.extend({}, $.fn.piccut.defaults, options); 14 | 15 | //配置项 16 | var cutX = opts.cutX, 17 | cutY = opts.cutY, 18 | cutWidth = opts.cutWidth, 19 | cutHeight = opts.cutHeight, 20 | fileEl = opts.fileEl, 21 | layerStyle = opts.layerStyle, 22 | isContain = opts.isContain, 23 | isKeepScale = opts.isKeepScale, 24 | isMinLimit = opts.isMinLimit, 25 | scale = opts.scale; 26 | 27 | //变量 28 | var me = this, 29 | $this = $(me), 30 | meWidth = me.offsetWidth, 31 | meHeight = me.offsetHeight, 32 | canvasEl, context, 33 | canvasWidth = meWidth * scale, 34 | canvasHeight = meHeight * scale, 35 | maskEl, maskContext, 36 | cutterEl, $cutter, 37 | $resizer, 38 | cutRatio = cutWidth / cutHeight; 39 | 40 | //默认裁切起点 41 | cutX === undefined && (cutX = opts.cutX = (meWidth - cutWidth) / 2); 42 | cutY === undefined && (cutY = opts.cutY = (meHeight - cutHeight) / 2); 43 | 44 | //初始化函数 45 | function init() { 46 | $this.addClass('pi-piccut') 47 | .html('' + 48 | '' + 49 | '

' + 50 | '' + 51 | '

'); 52 | 53 | //画布canvas 54 | canvasEl = me.getElementsByClassName('pi-piccut-canvas')[0]; 55 | context = canvasEl.getContext('2d'); 56 | 57 | //遮罩canvas 58 | maskEl = me.getElementsByClassName('pi-piccut-mask')[0]; 59 | maskContext = maskEl.getContext('2d'); 60 | 61 | //cutter 62 | cutterEl = me.getElementsByClassName('pi-piccut-cutter')[0]; 63 | $cutter = $(cutterEl); 64 | //resizer 65 | $resizer = $(me.getElementsByClassName('pi-piccut-resizer')[0]); 66 | 67 | //初始化事件 68 | initEvent(); 69 | } 70 | 71 | //初始化事件函数 72 | function initEvent() { 73 | var startX, startY, 74 | //是否形变 75 | isResing, 76 | //记录touchmove时的位置 77 | cutCurX = cutX, cutCurY = cutY, 78 | //记录touchmove时的尺寸 79 | cutCurWidth = cutWidth, cutCurHeight = cutHeight; 80 | 81 | //刷新遮罩函数 82 | function refreshMask() { 83 | //cutter的位置和尺寸 84 | $cutter.css({ 85 | transform: 'translate3d(' + cutCurX + 'px, ' + cutCurY + 'px, 0)', 86 | width : cutCurWidth + 'px', 87 | height : cutCurHeight + 'px' 88 | }); 89 | //cutterEl.style.cssText = 'width:' + cutCurWidth + 'px; height:' + cutCurHeight + 'px; left:' + cutCurX + 'px; top:' + cutCurY + 'px;'; 90 | 91 | //清理画布 92 | maskContext.clearRect(0, 0, canvasWidth, canvasHeight); 93 | 94 | //画layer层 95 | maskContext.globalCompositeOperation = 'source-over'; 96 | maskContext.fillStyle = layerStyle; 97 | maskContext.fillRect(0, 0, canvasWidth, canvasHeight); 98 | 99 | //画mask层 100 | maskContext.globalCompositeOperation = 'destination-out'; 101 | maskContext.fillStyle = '#fff'; 102 | maskContext.fillRect(cutCurX * scale, cutCurY * scale, cutCurWidth * scale, cutCurHeight * scale); 103 | } 104 | 105 | 106 | //文件选择事件 107 | fileEl.onchange = function () { 108 | var file = fileEl.files[0], 109 | url = URL.createObjectURL(file); 110 | 111 | //重置剪裁参数 112 | cutX = opts.cutX; 113 | cutY = opts.cutY; 114 | cutWidth = opts.cutWidth; 115 | cutHeight = opts.cutHeight; 116 | 117 | //绘制图片 118 | var img = new Image(); 119 | img.src = url; 120 | img.onload = function () { 121 | var imgWidth = img.width, 122 | imgHeight = img.height; 123 | 124 | //是否如背景图的background-size:contain;那样 125 | if (isContain) { 126 | var ratio = imgWidth / imgHeight; 127 | if (ratio > canvasWidth / canvasHeight) { 128 | if (imgWidth > canvasWidth) { 129 | imgWidth = canvasWidth; 130 | imgHeight = imgWidth / ratio; 131 | } 132 | } 133 | else { 134 | if (imgHeight > canvasHeight) { 135 | imgHeight = canvasHeight; 136 | imgWidth = imgHeight * ratio; 137 | } 138 | } 139 | } 140 | 141 | //清理画布 142 | context.clearRect(0, 0, canvasWidth, canvasHeight); 143 | 144 | //画图片层 145 | context.drawImage(img, (canvasWidth - imgWidth) / 2, (canvasHeight - imgHeight) / 2, imgWidth, imgHeight); 146 | 147 | //刷新遮罩(加个延迟,以避免安卓4.2后面的绘图功能不生效) 148 | setTimeout(function () { 149 | refreshMask(); 150 | }, 0); 151 | 152 | //显示裁切相关元素 153 | $this.addClass('on'); 154 | }; 155 | }; 156 | 157 | 158 | //暴露getDataURL函数 159 | me.getDataURL = function () { 160 | if (!fileEl.value) { 161 | alert('请选择图片'); 162 | return; 163 | } 164 | 165 | //临时canvas导出图片数据 166 | var data = context.getImageData(cutX * scale, cutY * scale, cutWidth * scale, cutHeight * scale), 167 | tmp = document.createElement('canvas'); 168 | 169 | tmp.width = cutWidth * scale; 170 | tmp.height = cutHeight * scale; 171 | tmp.getContext('2d').putImageData(data, 0, 0); 172 | 173 | return tmp.toDataURL('image/png'); 174 | }; 175 | 176 | 177 | //$this的事件 178 | $this.on('touchstart', function (evt) { 179 | var touch = evt.targetTouches[0]; 180 | //记录触摸开始位置 181 | startX = touch.pageX; 182 | startY = touch.pageY; 183 | }); 184 | 185 | //在容器上touchmove时,作形变操作 186 | $this.on('touchmove', function (evt) { 187 | //正在形变 188 | if (isResing) { 189 | evt.preventDefault(); 190 | evt.stopPropagation(); 191 | 192 | //计算位移 193 | var touch = evt.targetTouches[0], 194 | swipSpanX = touch.pageX - startX, 195 | swipSpanY = touch.pageY - startY; 196 | 197 | //宽度 198 | cutCurWidth = cutWidth + swipSpanX; 199 | //高度 200 | cutCurHeight = cutHeight + swipSpanY; 201 | 202 | //保持比例 203 | if (isKeepScale) { 204 | //计算出按比例的宽度,高度 205 | cutWidth / cutCurHeight > cutRatio ? (cutCurHeight = cutCurWidth / cutRatio) : (cutCurWidth = cutCurHeight * cutRatio); 206 | 207 | //不能超出范围内 208 | if (cutCurY + cutCurHeight > meHeight) { 209 | cutCurHeight = meHeight - cutCurY; 210 | cutCurWidth = cutCurHeight * cutRatio; 211 | } 212 | if (cutCurX + cutCurWidth > meWidth) { 213 | cutCurWidth = meWidth - cutCurX; 214 | cutCurHeight = cutCurWidth / cutRatio; 215 | } 216 | } 217 | else { 218 | //不能超出范围内 219 | cutCurY + cutCurHeight > meHeight && (cutCurHeight = meHeight - cutCurY); 220 | cutCurX + cutCurWidth > meWidth && (cutCurWidth = meWidth - cutCurX); 221 | } 222 | 223 | //有最小限制时,将不能小于配置项中的裁切尺寸 224 | isMinLimit && cutCurHeight < opts.cutHeight && (cutCurHeight = opts.cutHeight); 225 | isMinLimit && cutCurWidth < opts.cutWidth && (cutCurWidth = opts.cutWidth); 226 | 227 | //刷新遮罩 228 | refreshMask(); 229 | } 230 | }); 231 | 232 | //cutter上touchmove时,移动遮罩 233 | $cutter.on('touchmove', function (evt) { 234 | //不是形变 235 | if (!isResing) { 236 | evt.preventDefault(); 237 | evt.stopPropagation(); 238 | 239 | //计算位移 240 | var touch = evt.targetTouches[0], 241 | swipSpanX = touch.pageX - startX, 242 | swipSpanY = touch.pageY - startY; 243 | 244 | //X轴 245 | cutCurX = cutX + swipSpanX; 246 | //不能超出范围内 247 | cutCurX < 0 && (cutCurX = 0); 248 | cutCurX + cutCurWidth > meWidth && (cutCurX = meWidth - cutCurWidth); 249 | 250 | //Y轴 251 | cutCurY = cutY + swipSpanY; 252 | //不能超出范围内 253 | cutCurY < 0 && (cutCurY = 0); 254 | cutCurY + cutCurHeight > meHeight && (cutCurY = meHeight - cutCurHeight); 255 | 256 | //刷新遮罩 257 | refreshMask(); 258 | } 259 | }); 260 | 261 | $this.on('touchend', function () { 262 | //保存位置 263 | cutX = cutCurX; 264 | cutY = cutCurY; 265 | //保存尺寸 266 | cutWidth = cutCurWidth; 267 | cutHeight = cutCurHeight; 268 | }); 269 | 270 | 271 | //resizer的事件 272 | $resizer.on('touchstart', function () { 273 | //标识正在作形变 274 | isResing = true; 275 | }); 276 | 277 | $resizer.on('touchend', function () { 278 | isResing = false; 279 | }); 280 | 281 | } 282 | 283 | 284 | //初始化 285 | init(); 286 | 287 | }); 288 | 289 | }; 290 | $.fn.piccut.defaults = { 291 | //裁切起点x值 292 | cutX : undefined, 293 | //裁切起点y值 294 | cutY : undefined, 295 | //裁切宽度 296 | cutWidth : 320, 297 | //裁切高度 298 | cutHeight : 320, 299 | //file元素 300 | fileEl : null, 301 | //遮罩样式 302 | layerStyle : 'rgba(128,128,128,0.7)', 303 | //是否如背景图的background-size:contain; 304 | isContain : true, 305 | //截图是否保持比例 306 | isKeepScale: true, 307 | //是否有最小限制(默认限制为裁切宽度和裁切高度) 308 | isMinLimit : true, 309 | //缩放比例 310 | scale : 1 311 | }; 312 | 313 | })(window, $); -------------------------------------------------------------------------------- /plugin/piccut.scss: -------------------------------------------------------------------------------- 1 | /* 2 | plugin/piccut 3 | 图片裁切插件样式 4 | */ 5 | .pi-piccut 6 | { 7 | position: relative; 8 | 9 | * 10 | { 11 | visibility: hidden; 12 | } 13 | 14 | &.on 15 | { 16 | * 17 | { 18 | visibility: visible; 19 | } 20 | } 21 | 22 | @at-root 23 | { 24 | .pi-piccut-mask 25 | { 26 | @extend %ph_palt; 27 | } 28 | 29 | 30 | .pi-piccut-cutter 31 | { 32 | @extend %ph_palt; 33 | cursor: move; 34 | box-shadow: 0 0 2px #000; 35 | transform-origin: left top; 36 | } 37 | 38 | 39 | .pi-piccut-resizer 40 | { 41 | $w: 0.2rem; 42 | 43 | position: absolute; 44 | border: $w solid #fff; 45 | border-radius: 50%; 46 | right: -$w; 47 | bottom: -$w; 48 | cursor: se-resize; 49 | box-shadow: 0 0 2px #000; 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /plugin/picpager.js: -------------------------------------------------------------------------------- 1 | /* 2 | * picpager.js 3 | * 相册js 4 | */ 5 | (function(window, $) { 6 | 7 | $.fn.picpager = function(options) { 8 | 9 | // 每个元素执行 10 | return this.each(function() { 11 | var opts = $.extend({}, $.fn.picpager.defaults, options); 12 | 13 | // 配置项 14 | var imgData = opts.imgData, 15 | swipThreshold = opts.swipThreshold, 16 | swipSpanThreshold = opts.swipSpanThreshold, 17 | slideCallback = opts.slideCallback, 18 | pullRatio = opts.pullRatio, 19 | contentFormate = opts.contentFormate; 20 | 21 | // 变量 22 | var $this = $(this), 23 | me = this, 24 | $pics, $wrap, 25 | itemCount = imgData.length; 26 | 27 | // 初始化函数 28 | function init() { 29 | $this.addClass('pi-picpager').html('
'); 30 | $wrap = $this.find('.pi-wrap'); 31 | $pics = $this.find('.pi-pic').each(function(i) { 32 | // 初始化内容 33 | $(this).html(contentFormate(imgData[i - 1])); 34 | }); 35 | 36 | // 初始化事件 37 | initEvent(); 38 | } 39 | 40 | // 初始化事件函数 41 | function initEvent() { 42 | var width = $this.width(), 43 | index = 0, 44 | startX, startY, 45 | swipSpan, isAnimating, isMoving, 46 | duration = parseFloat($wrap.css('transition-duration')) * 1000; 47 | 48 | // 移动到函数 49 | function slide(direction) { 50 | // 判断滚动方向 51 | switch (direction) { 52 | // 向右 53 | case 1: 54 | // 向左 55 | case -1: { 56 | // 动画 57 | isAnimating = true; 58 | // 作动画 59 | translate(width * direction); 60 | 61 | // 复位操作,更新内容 62 | setTimeout(function() { 63 | // 去掉动画 64 | $wrap.addClass('notrans'); 65 | // 复位 66 | translate(0); 67 | // 更新内容 68 | $pics.each(function(i) { 69 | $(this).html(contentFormate(imgData[index + i - 1])); 70 | }); 71 | // 重置isAnimating 72 | isAnimating = false; 73 | }, duration); 74 | break; 75 | } 76 | default: { 77 | translate(0); 78 | } 79 | } 80 | 81 | // 滚动回调函数 82 | typeof slideCallback === 'function' && slideCallback.call($pics, index, direction); 83 | } 84 | 85 | // 移动函数 86 | function translate(x) { 87 | typeof x === 'number' && (x += 'px'); 88 | $wrap.css('transform', 'translate3d(' + x + ',0,0)'); 89 | } 90 | 91 | 92 | // 暴露slideToIndex方法 93 | me.slideToIndex = function(i, isNoAni) { 94 | var direction; 95 | // 如不为数字或者超出范围 96 | if (typeof i !== 'number' || i < 0 || i >= itemCount || i === index) { 97 | return; 98 | } 99 | 100 | // 向左 101 | if (i > index) { 102 | direction = -1; 103 | $pics.eq(2).html(contentFormate(imgData[i])); 104 | } 105 | // 向右 106 | else { 107 | direction = 1; 108 | $pics.eq(0).html(contentFormate(imgData[i])); 109 | } 110 | 111 | index = i; 112 | // 是否无动画 113 | isNoAni ? $wrap.addClass('notrans') : $wrap.removeClass('notrans'); 114 | // 滚动 115 | slide(direction); 116 | }; 117 | 118 | // 暴露addItem方法 119 | me.addItem = function(item) { 120 | imgData = imgData.concat(item); 121 | itemCount = imgData.length; 122 | }; 123 | 124 | 125 | // 触摸开始事件 126 | $this.on('touchstart', function(evt) { 127 | // 如果正在作动画,不作响应 128 | if (isAnimating) { 129 | return; 130 | } 131 | 132 | var touch = evt.targetTouches ? evt.targetTouches[0] : evt; 133 | 134 | // 记录触摸开始位置 135 | startX = touch.pageX; 136 | startY = touch.pageY; 137 | 138 | // 重置swipSpan 139 | swipSpan = 0; 140 | // 重置手指拖拽移动 141 | isMoving = false; 142 | // 取消动画 143 | $wrap.addClass('notrans'); 144 | }); 145 | 146 | // 触摸移动事件 147 | $this.on('touchmove', function(evt) { 148 | // 如果正在作动画,不作响应 149 | if (isAnimating) { 150 | evt.preventDefault(); 151 | evt.stopPropagation(); 152 | return; 153 | } 154 | 155 | var touch = evt.targetTouches ? evt.targetTouches[0] : evt, 156 | // x轴滑动距离 157 | swipSpanX = touch.pageX - startX, 158 | absX = Math.abs(swipSpanX), 159 | // y轴滑动距离 160 | swipSpanY = touch.pageY - startY, 161 | absY = Math.abs(swipSpanY); 162 | 163 | // x轴滑动距离大于y轴 y轴滑动距离小于阈值, 说明的确是左右滑动 164 | if (isMoving || absY < absX || absY < swipSpanThreshold) { 165 | evt.preventDefault(); 166 | evt.stopPropagation(); 167 | 168 | // 第一张图或最后一张图 169 | if (index === 0 && swipSpanX > 0 || index === itemCount - 1 && swipSpanX < 0) { 170 | // 模拟拉不动操作体验 171 | swipSpanX /= pullRatio; 172 | } 173 | 174 | // 位移 175 | translate(swipSpan = swipSpanX); 176 | // 已经满足滚动条件,且正在手指拖动 177 | isMoving = true; 178 | } 179 | }); 180 | 181 | // 触摸结束事件 182 | $this.on('touchend', function() { 183 | // 如果正在作动画,不作响应 184 | if (isAnimating) { 185 | return; 186 | } 187 | 188 | var direction; 189 | // 向左 190 | if (swipSpan < -swipThreshold) { 191 | ++index === itemCount ? index = itemCount - 1 : direction = -1; 192 | } 193 | // 向右 194 | else if (swipSpan > swipThreshold) { 195 | --index < 0 ? index = 0 : direction = 1; 196 | } 197 | 198 | // 加上动画 199 | $wrap.removeClass('notrans'); 200 | // 滚动 201 | swipSpan !== 0 && slide(direction); 202 | }).trigger('touchend'); 203 | 204 | // 屏幕尺寸改变事件 205 | window.addEventListener('resize', function() { 206 | var w = $this.width(); 207 | w > 0 && (width = w); 208 | }, false); 209 | 210 | } 211 | 212 | 213 | // 初始化 214 | init(); 215 | 216 | }); 217 | 218 | }; 219 | $.fn.picpager.defaults = { 220 | // 图片数据 221 | imgData: null, 222 | // 滑动阈值 223 | swipThreshold: 100, 224 | // 滑动距离阈值 225 | swipSpanThreshold: 5, 226 | // 轮播回调函数 227 | slideCallback: null, 228 | // first和last拉不动的比率 229 | pullRatio: 3, 230 | // 返回内容函数 231 | contentFormate: function(itemData) { 232 | return itemData ? '
' : ''; 233 | } 234 | }; 235 | 236 | })(window, $); -------------------------------------------------------------------------------- /plugin/picpager.scss: -------------------------------------------------------------------------------- 1 | /* 2 | plugin/picpager 3 | 相册样式 4 | */ 5 | //引入 6 | @import "scss/ani/ani_loading"; 7 | 8 | .pi-picpager { 9 | overflow: hidden; 10 | 11 | .pi-wrap { 12 | width: 300%; 13 | height: 100%; 14 | margin-left: -100%; 15 | display: flex; 16 | flex-direction: row; 17 | @extend .transform; 18 | } 19 | 20 | .pi-pic { 21 | flex: 1; 22 | height: 100%; 23 | @extend .ani_loading; 24 | } 25 | } -------------------------------------------------------------------------------- /plugin/scratchcard.js: -------------------------------------------------------------------------------- 1 | /* 2 | * scratchcard.js 3 | * 刮刮卡js 4 | */ 5 | (function (window, $) { 6 | 7 | $.fn.scratchcard = function (options) { 8 | 9 | //每个元素执行 10 | return this.each(function () { 11 | var opts = $.extend({}, $.fn.scratchcard.deflunt, options); 12 | 13 | //配置项 14 | var fineness = opts.fineness, 15 | paintStyle = opts.paintStyle, 16 | text = opts.text, 17 | fontColor = opts.fontColor, 18 | font = opts.font, 19 | imgSrc = opts.imgSrc, 20 | scale = opts.scale; 21 | 22 | //变量 23 | var $this = $(this), 24 | width = $this.width() * scale, 25 | height = $this.height() * scale, 26 | //绘画元素 27 | $canvas, 28 | //容器offsetLeft 29 | offsetLeft, 30 | //容器offsetTop 31 | offsetTop, 32 | //上下文 33 | context; 34 | 35 | //初始化函数 36 | function init() { 37 | var html = ''; 38 | $this.css({ 39 | 'position': 'relative', 40 | 'background-image': 'url(' + imgSrc + ')', 41 | 'background-size': '100% auto' 42 | }).html(html); 43 | 44 | //canvas 45 | $canvas = $this.find('canvas'); 46 | $canvas.css({ 47 | 'position': 'absolute', 48 | 'top': 0, 49 | 'left': 0 50 | }); 51 | 52 | //上下文 53 | context = $this.children('canvas')[0].getContext('2d'); 54 | 55 | drawLayer(); 56 | 57 | initEvents(); 58 | } 59 | 60 | //画覆盖物 61 | function drawLayer() { 62 | context.fillStyle = paintStyle; 63 | context.fillRect(0, 0, width, height); 64 | if (text) { 65 | context.fillStyle = fontColor; 66 | if (font) { 67 | context.font = font; 68 | } 69 | var textWidth = context.measureText(text).width; 70 | context.fillText(text, opts.left || (width - textWidth) / 2, opts.top || height / 2 + 20, width); 71 | } 72 | } 73 | 74 | //事件绑定 75 | function initEvents() { 76 | $canvas.on('touchstart', function (e) { 77 | //计算offset 78 | var offset = $this.offset(); 79 | offsetLeft = offset.left; 80 | offsetTop = offset.top; 81 | //设置画画参数 82 | context.fillStyle = '#fff'; 83 | context.globalCompositeOperation = 'destination-out'; 84 | context.beginPath(); 85 | //画画操作 86 | draw(e); 87 | }); 88 | $canvas.on('touchmove', function (e) { 89 | e.preventDefault(); 90 | e.stopPropagation(); 91 | //画画操作 92 | draw(e); 93 | }); 94 | $canvas.on('touchend', function (e) { 95 | context.globalCompositeOperation = 'source-over'; 96 | }); 97 | } 98 | 99 | //画画函数 100 | function draw(e) { 101 | var touch = e.targetTouches[0]; 102 | context.arc((touch.pageX - offsetLeft) * scale, (touch.pageY - offsetTop) * scale, fineness * scale, 0, Math.PI * 2, true); 103 | context.closePath(); 104 | context.fill(); 105 | } 106 | 107 | 108 | //初始化 109 | init(); 110 | 111 | }); 112 | }; 113 | $.fn.scratchcard.deflunt = { 114 | //画笔大小 115 | fineness: 30, 116 | //覆盖层颜色 117 | paintStyle: '#ccc', 118 | //文字 119 | text: '', 120 | //字体颜色 121 | fontColor: '#f00', 122 | //字体相关 123 | font: 'bold 60px sans-serif', 124 | //图片地址 125 | imgSrc: '', 126 | //缩放比例 127 | scale: 1 128 | }; 129 | 130 | })(window, $); -------------------------------------------------------------------------------- /plugin/scroll.js: -------------------------------------------------------------------------------- 1 | /* 2 | * scroll.js 3 | * 自定义滚动js 4 | */ 5 | (function (window, $) { 6 | 7 | $.fn.scroll = function (options) { 8 | 9 | var Math = window.Math; 10 | 11 | //计算校正距离函数 12 | function getReviseSpan(swipSpan, timeSpan, reviseRatio) { 13 | var speed = Math.abs(swipSpan) / timeSpan; 14 | return speed * speed * reviseRatio; 15 | } 16 | 17 | //每个元素执行 18 | return this.each(function () { 19 | var opts = $.extend({}, $.fn.scroll.defaults, options); 20 | 21 | //配置项 22 | var isVertical = opts.isVertical, 23 | timeSpanThreshold = opts.timeSpanThreshold, 24 | swipSpanThreshold = opts.swipSpanThreshold, 25 | maxScroll = opts.maxScroll, 26 | isAdjust = opts.isAdjust, 27 | reviseRatio = opts.reviseRatio, 28 | touchDuration = opts.touchDuration; 29 | 30 | //变量 31 | var $this = $(this), 32 | $items = $this.children('*'); 33 | 34 | 35 | //初始化函数 36 | function init() { 37 | $items.addClass('pi-scroll-item'); 38 | 39 | //初始化事件 40 | initEvent(); 41 | } 42 | 43 | 44 | //初始化事件函数 45 | function initEvent() { 46 | //最后一个touch的信息 47 | var lastTouch = {}, 48 | //touchstart位置 49 | startX, startY, 50 | //作动画translate值 51 | translateVal = 0, 52 | //当前translate值 53 | currentTranslateVal, 54 | //可滚动的值 55 | scrollVal = getScrollVal(); 56 | 57 | //获取可滚动的值函数 58 | function getScrollVal() { 59 | //item包含margin的尺寸 60 | var itemsOuterVal = isVertical ? 61 | $items.height() + parseFloat($items.css('margin-top')) + parseFloat($items.css('margin-bottom')) : 62 | $items.width() + parseFloat($items.css('margin-left')) + parseFloat($items.css('margin-right')), 63 | //this不包含padding的尺寸 64 | thisInnerVal = isVertical ? 65 | $this.height() - parseFloat($this.css('padding-top')) - parseFloat($this.css('padding-bottom')) : 66 | $this.width() - parseFloat($this.css('padding-left')) - parseFloat($this.css('padding-right')); 67 | 68 | //记录可滚动的值 69 | return itemsOuterVal - thisInnerVal; 70 | } 71 | 72 | //移动到函数 73 | function slide(x) { 74 | //起点 75 | if (x > 0) { 76 | x /= 2; 77 | } 78 | //终点 79 | else if (x < -scrollVal) { 80 | x += (-x - scrollVal) / 2; 81 | } 82 | 83 | var transform = 'translate3d(' + (isVertical ? '0,' + (translateVal = x) + 'px,0' : (translateVal = x) + 'px,0,0') + ')'; 84 | $items.css({ 85 | 'transform': transform 86 | }); 87 | } 88 | 89 | //居中函数 90 | function center(me) { 91 | var translateVal = isVertical ? 92 | (me.offsetTop - $items[0].offsetTop) - ($this.height() - me.clientHeight) / 2 : 93 | (me.offsetLeft - $items[0].offsetLeft) - ($this.width() - me.clientWidth) / 2; 94 | 95 | if (translateVal < 0) { 96 | slide(0); 97 | } 98 | else { 99 | translateVal < scrollVal ? slide(-translateVal) : slide(-scrollVal); 100 | } 101 | } 102 | 103 | //暴露居中函数 104 | $this[0].center = center; 105 | 106 | 107 | //触摸开始事件 108 | $this.on('touchstart', function (evt) { 109 | var touch = evt.targetTouches ? evt.targetTouches[0] : evt; 110 | 111 | //记录开始时间 112 | lastTouch.startTime = evt.timeStamp; 113 | //记录触摸开始位置 114 | lastTouch.startX = startX = touch.pageX; 115 | lastTouch.startY = startY = touch.pageY; 116 | //记录当前动画值 117 | currentTranslateVal = translateVal; 118 | 119 | //不作动画 120 | $items.addClass('notrans'); 121 | }); 122 | 123 | //触摸移动事件 124 | $this.on('touchmove', function (evt) { 125 | var touch = evt.targetTouches ? evt.targetTouches[0] : evt, 126 | currentX = touch.pageX, 127 | currentY = touch.pageY, 128 | //x轴滑动距离 129 | swipSpanX = currentX - startX, 130 | absX = Math.abs(swipSpanX), 131 | //y轴滑动距离 132 | swipSpanY = currentY - startY, 133 | absY = Math.abs(swipSpanY), 134 | //事件当前时间 135 | timeStamp = evt.timeStamp; 136 | 137 | //上下 138 | if (isVertical) { 139 | //x轴滑动距离小于阈值,或y轴滑动距离大于x轴,说明的确是上下滑动 140 | if (absX < swipSpanThreshold || absX < absY) { 141 | evt.preventDefault(); 142 | evt.stopPropagation(); 143 | 144 | slide(currentTranslateVal + swipSpanY); 145 | } 146 | } 147 | //左右 148 | else { 149 | //y轴滑动距离小于阈值,或x轴滑动距离大于y轴,说明的确是左右滑动 150 | if (absY < swipSpanThreshold || absY < absX) { 151 | evt.preventDefault(); 152 | evt.stopPropagation(); 153 | 154 | slide(currentTranslateVal + swipSpanX); 155 | } 156 | } 157 | 158 | //如果大于一定时间间隔,重置最后一个touch的信息 159 | if (timeStamp - lastTouch.startTime > touchDuration) { 160 | lastTouch.startTime = timeStamp; 161 | lastTouch.startX = currentX; 162 | lastTouch.startY = currentY; 163 | } 164 | }); 165 | 166 | //触摸结束事件 167 | $this.on('touchend', function (evt) { 168 | var touch = evt.changedTouches ? evt.changedTouches[0] : evt, 169 | //滑动距离 170 | swipSpan = isVertical ? touch.pageY - lastTouch.startY : touch.pageX - lastTouch.startX, 171 | //滑动时间间隔 172 | timeSpan = evt.timeStamp - lastTouch.startTime, 173 | //计算校正值(更加拟物化) 174 | span = timeSpan > timeSpanThreshold ? 0 : getReviseSpan(swipSpan, timeSpan, reviseRatio); 175 | 176 | //设置最大滚动值 177 | span > maxScroll && (span = maxScroll); 178 | 179 | //作动画 180 | $items.removeClass('notrans'); 181 | 182 | if (swipSpan < 0) { 183 | //是否滚动到最后 184 | -(translateVal - span) < scrollVal ? slide(translateVal - span) : slide(-scrollVal); 185 | } 186 | else if (swipSpan > 0) { 187 | //是否滚动到最前 188 | translateVal + span < 0 ? slide(translateVal + span) : slide(0); 189 | } 190 | }); 191 | 192 | //点击事件(如果需要将点击元素定位到居中) 193 | isAdjust && $this.on('click', function (evt) { 194 | center(evt.target); 195 | }); 196 | 197 | //屏幕尺寸改变事件 198 | window.addEventListener('resize', function () { 199 | var w = $this.width(); 200 | //重置可滚动的值 201 | w > 0 && (scrollVal = getScrollVal()); 202 | }, false); 203 | } 204 | 205 | 206 | //初始化 207 | init(); 208 | 209 | }); 210 | 211 | }; 212 | $.fn.scroll.defaults = { 213 | //是否竖直方向滚动 214 | isVertical: false, 215 | //时间间隙阈值 216 | timeSpanThreshold: 300, 217 | //滑动距离阈值 218 | swipSpanThreshold: 10, 219 | //滚动最大值 220 | maxScroll: 800, 221 | //是否调整点击元素居中 222 | isAdjust: false, 223 | //校正系数 224 | reviseRatio: 400, 225 | //默认触摸时长 226 | touchDuration: 300 227 | }; 228 | 229 | })(window, $); -------------------------------------------------------------------------------- /plugin/scroll.scss: -------------------------------------------------------------------------------- 1 | /* 2 | plugin/scroll 3 | 自定义滚动样式 4 | */ 5 | .pi-scroll-item { 6 | @extend .transform; 7 | transition-timing-function: cubic-bezier(0.1, 0.57, 0.1, 1); 8 | } -------------------------------------------------------------------------------- /plugin/scrollto.js: -------------------------------------------------------------------------------- 1 | /* 2 | * scrollto.js 3 | * 滚动到js 4 | */ 5 | (function (window, $) { 6 | 7 | var document = window.document, 8 | bodyEl = document.body; 9 | 10 | /** 11 | * 页面滚动到函数 12 | * @param toScrollTop 滚动到的scrollTop 13 | * @param rate 比率 14 | * @param el 滚动元素 15 | */ 16 | $.scrollTo = function (toScrollTop, rate, el) { 17 | rate || (rate = 20); 18 | el || (el = bodyEl); 19 | //console.log(toScrollTop); 20 | 21 | var scrollTop = el.scrollTop, 22 | scrollSpan = (toScrollTop - scrollTop) / rate; 23 | 24 | function scroll() { 25 | scrollTop += scrollSpan; 26 | el.scrollTop = scrollTop; 27 | //console.log(scrollTop); 28 | scrollSpan > 0 ? (toScrollTop > scrollTop && requestAnimationFrame(scroll)) : (toScrollTop < scrollTop && requestAnimationFrame(scroll)); 29 | } 30 | 31 | //定位滚动 32 | scrollSpan > 0 ? (toScrollTop > scrollTop && requestAnimationFrame(scroll)) : (toScrollTop < scrollTop && requestAnimationFrame(scroll)); 33 | }; 34 | 35 | })(window, $); -------------------------------------------------------------------------------- /plugin/swatchbook.js: -------------------------------------------------------------------------------- 1 | /* 2 | * swatchbook.js 3 | * 扇形特效js 4 | */ 5 | (function (window, $) { 6 | 7 | $.fn.swatchbook = function (options) { 8 | 9 | //每个元素执行 10 | return this.each(function () { 11 | var opts = $.extend({}, $.fn.swatchbook.defaults, options); 12 | 13 | //配置项 14 | var centerIdx = opts.centerIdx, 15 | angleInc = opts.angleInc, 16 | proximity = opts.proximity, 17 | neighbor = opts.neighbor, 18 | initIsClosed = opts.initIsClosed, 19 | closeIdx = opts.closeIdx, 20 | openAt = opts.openAt, 21 | selectCallback = opts.selectCallback, 22 | openDelay = opts.openDelay; 23 | 24 | //变量 25 | var $this = $(this), 26 | $items = $this.addClass('sb-container').children('*'), 27 | itemsCount = $items.length, 28 | currentIdx = -1, 29 | cache = [], 30 | isClosed; 31 | 32 | //初始化函数 33 | function init() { 34 | //兼容安卓2.x 35 | $.isAndroid2 && $this.css({ 36 | 'backface-visibility': 'visible' 37 | }); 38 | 39 | if (!initIsClosed) { 40 | center(centerIdx); 41 | } 42 | else { 43 | isClosed = true; 44 | } 45 | 46 | if (openAt >= 0 && openAt < itemsCount) { 47 | openItem($items.eq(openAt)); 48 | } 49 | 50 | initEvents(); 51 | } 52 | 53 | function center(idx) { 54 | $items.each(function (i) { 55 | var $this = $(this), 56 | transformStr = 'rotateZ(' + (angleInc * (i - idx)) + 'deg)'; 57 | 58 | //设定一定延时,防止计算能力差的浏览器(ucweb)打不开swatchbook 59 | setTimeout(function () { 60 | $this.css({ 61 | 'transform': transformStr 62 | }); 63 | }, i * openDelay); 64 | }); 65 | } 66 | 67 | function openItem($item) { 68 | var itemIdx = $item.index(); 69 | if (itemIdx !== currentIdx) { 70 | $items.removeClass('selected'); 71 | if (closeIdx !== -1 && itemIdx === closeIdx) { 72 | currentIdx = -1; 73 | openClose(); 74 | } 75 | else { 76 | currentIdx = itemIdx; 77 | $item.css({ 78 | 'transform': 'rotateZ(0deg)' 79 | }).addClass('selected'); 80 | rotateSiblings($item, itemIdx); 81 | } 82 | } 83 | else if (itemIdx === currentIdx && typeof selectCallback === 'function') { 84 | selectCallback(itemIdx); 85 | } 86 | } 87 | 88 | function openClose() { 89 | if (isClosed) { 90 | center(centerIdx); 91 | } 92 | else { 93 | $items.css({ 94 | 'transform': 'rotateZ(0deg)' 95 | }); 96 | } 97 | isClosed = !isClosed; 98 | } 99 | 100 | function rotateSiblings($item, itemIdx) { 101 | var $cached = cache[itemIdx], 102 | $siblings; 103 | 104 | if ($cached) { 105 | $siblings = $cached; 106 | } 107 | else { 108 | $siblings = $item.siblings(); 109 | cache[itemIdx] = $siblings; 110 | } 111 | 112 | $siblings.each(function (i) { 113 | var rotateVal = i < itemIdx ? 114 | angleInc * (i - itemIdx) : i - itemIdx === 1 ? 115 | proximity : proximity + (i - itemIdx - 1) * neighbor; 116 | var transformStr = 'rotateZ(' + rotateVal + 'deg)'; 117 | 118 | $(this).css({ 119 | 'transform': transformStr 120 | }); 121 | }); 122 | } 123 | 124 | //初始化事件函数 125 | function initEvents() { 126 | $items.on('click', function () { 127 | openItem($(this)); 128 | }); 129 | } 130 | 131 | 132 | //初始化 133 | init(); 134 | 135 | }); 136 | }; 137 | $.fn.swatchbook.defaults = { 138 | //打开的index 139 | centerIdx: 6, 140 | //item之间的角度(center右边的item) 141 | angleInc: 8, 142 | //打开的item与右边item之间的角度 143 | proximity: 45, 144 | //item之间的角度(center左边的item) 145 | neighbor: 4, 146 | //初始化时是否关闭 147 | initIsClosed: false, 148 | //能打开和关闭的index 149 | closeIdx: -1, 150 | //打开项 151 | openAt: -1, 152 | //点选状态下再点击时触发函数 153 | selectCallback: null, 154 | //打开延迟 155 | openDelay: 25 156 | }; 157 | 158 | })(window, $); -------------------------------------------------------------------------------- /plugin/swatchbook.scss: -------------------------------------------------------------------------------- 1 | /* 2 | plugin/swatchbook 3 | 扇形特效样式 4 | */ 5 | .sb-container 6 | { 7 | position: relative; 8 | width: 1.3rem; 9 | height: 4rem; 10 | /*防止动画过程闪烁*/ 11 | backface-visibility: hidden; 12 | 13 | & > div 14 | { 15 | @extend %ph_pafull; 16 | border-radius: 0.1rem; 17 | transform-origin: 25% 90%; 18 | transition: transform 0.7s ease; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /plugin/turntable.js: -------------------------------------------------------------------------------- 1 | /* 2 | * turntable.js 3 | * 转盘抽奖js 4 | */ 5 | (function (window, $) { 6 | 7 | $.fn.turntable = function (options) { 8 | 9 | //每个元素执行 10 | return this.each(function () { 11 | var opts = $.extend({}, $.fn.turntable.defaults, options); 12 | 13 | //配置项 14 | var count = opts.count, 15 | rotateDeg = opts.rotateDeg, 16 | duration = opts.duration, 17 | timeFx = opts.timeFx, 18 | offset = opts.offset; 19 | 20 | //变量 21 | var $this = $(this), 22 | me = this, 23 | $pointer; 24 | 25 | //初始化函数 26 | function init() { 27 | $pointer = $('
'); 28 | $this.addClass('pi-turntable').prepend($pointer); 29 | 30 | //初始化事件 31 | initEvent(); 32 | } 33 | 34 | //初始化事件函数 35 | function initEvent() { 36 | 37 | var timeout, 38 | isAnimating; 39 | 40 | //转动函数 41 | me.turnToIndex = function (index, fn) { 42 | //不可大于总数 43 | if (index > count) { 44 | return; 45 | } 46 | 47 | //正在转动 48 | if (isAnimating) { 49 | return; 50 | } 51 | 52 | //动画属性 53 | var transition = duration / 1000 + 's ' + timeFx, 54 | endDeg = rotateDeg + (index / count) * 360 + offset + 'deg', 55 | transform = 'rotateZ(' + endDeg + ')';//如用'rotate3d(0, 0, 1, ' + endDeg + ')',ios上动画有bug 56 | 57 | //重置 58 | $pointer[0].style.cssText = ''; 59 | isAnimating = true; 60 | 61 | //设定延迟才会有动画效果 62 | setTimeout(function () { 63 | //动画 64 | $pointer.css({ 65 | 'transform': transform 66 | }); 67 | var pointerEl = $pointer[0]; 68 | pointerEl.style['-webkit-transition'] = '-webkit-transform ' + transition; 69 | pointerEl.style['transition'] = 'transform ' + transition; 70 | 71 | //动画完成后回调 72 | clearTimeout(timeout);//清理上一个timeout 73 | timeout = setTimeout(function () { 74 | typeof fn === 'function' && fn(); 75 | isAnimating = false; 76 | }, duration); 77 | 78 | }, 40); 79 | }; 80 | } 81 | 82 | 83 | //初始化 84 | init(); 85 | 86 | }); 87 | }; 88 | $.fn.turntable.defaults = { 89 | //奖品格数 90 | count : 12, 91 | //旋转度数 92 | rotateDeg: 3600, 93 | //旋转时长 94 | duration : 7000, 95 | //动画fx 96 | timeFx : 'cubic-bezier(0.42,0,0.25,1)', 97 | //校正值 98 | offset : 0 99 | }; 100 | 101 | })(window, $); -------------------------------------------------------------------------------- /plugin/turntable.scss: -------------------------------------------------------------------------------- 1 | /* 2 | plugin/turntable 3 | 转盘抽奖样式 4 | */ 5 | .pi-turntable 6 | { 7 | position: relative; 8 | overflow: hidden; 9 | 10 | &, .pi-pointer 11 | { 12 | background-position: center center; 13 | background-repeat: no-repeat; 14 | background-size: cover; 15 | } 16 | 17 | .pi-pointer 18 | { 19 | @extend %ph_pafull; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /scss/var.scss: -------------------------------------------------------------------------------- 1 | //var 2 | //移动端变量scss 3 | //包含默认变量,常用函数,常用点位符(全是sass运算相关的东西) 4 | //本文件中用//注释,可使生成文件中不包含注释信息 5 | 6 | //混入 7 | //定位 8 | @mixin mx_plt($position: absolute, $left: 0, $top: 0) { 9 | position: $position; 10 | left: $left; 11 | top: $top; 12 | } 13 | 14 | 15 | @mixin mx_plb($position: absolute, $left: 0, $bottom: 0) { 16 | position: $position; 17 | left: $left; 18 | bottom: $bottom; 19 | } 20 | 21 | 22 | @mixin mx_prt($position: absolute, $right: 0, $top: 0) { 23 | position: $position; 24 | right: $right; 25 | top: $top; 26 | } 27 | 28 | 29 | @mixin mx_prb($position: absolute, $right: 0, $bottom: 0) { 30 | position: $position; 31 | right: $right; 32 | bottom: $bottom; 33 | } 34 | 35 | 36 | //margin居中 37 | @mixin mx_margin-center($width: -1, $height: -1) { 38 | left: 50%; 39 | top: 50%; 40 | @if ($width != -1) 41 | { 42 | width: $width; 43 | margin-left: -$width/2; 44 | } 45 | @if ($height != -1) 46 | { 47 | height: $height; 48 | margin-top: -$height/2; 49 | } 50 | } 51 | 52 | 53 | //最大宽度 54 | @mixin mx_maxwidth($width: 300px, $target-width: 320px) { 55 | width: $width / $target-width * 100%; 56 | min-width: $width; 57 | max-width: $width * 2; 58 | margin-left: auto; 59 | margin-right: auto; 60 | } 61 | 62 | 63 | //左边箭头 64 | @mixin mx_left-arrow($width: 14px, $deg: 0deg, $color: #000, $line-width: 1px, $color-focus: 0) { 65 | width: $width; 66 | height: $width; 67 | box-shadow: (-$line-width) (-$line-width) 0 $color; 68 | transform: rotateZ(-45deg + $deg); 69 | 70 | @if ($color-focus != 0) 71 | { 72 | &.focus 73 | { 74 | box-shadow: (-$line-width) (-$line-width) 0 $color-focus; 75 | } 76 | } 77 | } 78 | 79 | 80 | //占位符 81 | 82 | //定位 83 | %ph_palt 84 | { 85 | @include mx_plt; 86 | } 87 | 88 | 89 | %ph_pflt 90 | { 91 | @include mx_plt(fixed); 92 | } 93 | 94 | 95 | %ph_part 96 | { 97 | @include mx_prt; 98 | } 99 | 100 | 101 | %ph_pfrt 102 | { 103 | @include mx_prt(fixed); 104 | } 105 | 106 | 107 | %ph_palb 108 | { 109 | @include mx_plb; 110 | } 111 | 112 | 113 | %ph_pflb 114 | { 115 | @include mx_plb(fixed); 116 | } 117 | 118 | 119 | %ph_parb 120 | { 121 | @include mx_prb; 122 | } 123 | 124 | 125 | %ph_pfrb 126 | { 127 | @include mx_prb(fixed); 128 | } 129 | 130 | 131 | //宽度高度100% 132 | %ph_full 133 | { 134 | width: 100%; 135 | height: 100%; 136 | } 137 | 138 | 139 | //定位方式的宽度高度100% 140 | %ph_pfull 141 | { 142 | left: 0; 143 | top: 0; 144 | bottom: 0; 145 | right: 0; 146 | } 147 | 148 | 149 | //绝对定位 150 | %ph_absolute 151 | { 152 | position: absolute; 153 | } 154 | 155 | 156 | //fixed定位 157 | %ph_fixed 158 | { 159 | position: fixed; 160 | } 161 | 162 | 163 | //绝对定位宽度高度100% 164 | %ph_pafull 165 | { 166 | @extend %ph_absolute; 167 | @extend %ph_pfull; 168 | } 169 | 170 | 171 | //fixed定位宽度高度100% 172 | %ph_pffull 173 | { 174 | @extend %ph_fixed; 175 | @extend %ph_pfull; 176 | } 177 | 178 | 179 | //表格单元格 180 | %ph_td 181 | { 182 | display: table-cell; 183 | vertical-align: middle; 184 | line-height: normal; 185 | } 186 | 187 | 188 | //居中 189 | %ph_center 190 | { 191 | display: flex; 192 | justify-content: center; 193 | align-items: center; 194 | } 195 | 196 | 197 | //可见 198 | %ph_visible 199 | { 200 | visibility: visible; 201 | opacity: 1; 202 | } 203 | 204 | 205 | //不可见 206 | %ph_hidden 207 | { 208 | visibility: hidden; 209 | opacity: 0; 210 | } -------------------------------------------------------------------------------- /ui/base.js: -------------------------------------------------------------------------------- 1 | /* 2 | * base.js 3 | * 移动端基础js,包含pc端二维码,mask,a标签触摸等基础功能 4 | */ 5 | (function (window, $) { 6 | 7 | //文档元素 8 | var document = window.document, 9 | //文档$对象 10 | $doc = $(document), 11 | //body $对象 12 | $body = $(document.body), 13 | //mainbox $对象 14 | $mainbox = $('#mainbox'); 15 | 16 | 17 | /** 18 | * 是否显示二维码(默认为true) 19 | * @type {boolean} 20 | */ 21 | $.isShowQrcode = true; 22 | 23 | 24 | /** 25 | * 是否body滚动 26 | * @type {string} 27 | */ 28 | $.isBodyScroll = $mainbox.css('overflow') !== 'hidden'; 29 | //去掉部分浏览器地址栏(ucweb,qq有效) 30 | if (!$.isBodyScroll) { 31 | $body.addClass('very-high'); 32 | window.scrollTo(0, 1); 33 | $body.removeClass('very-high'); 34 | } 35 | 36 | 37 | var ua = navigator.userAgent; 38 | /** 39 | * 是否为移动端 40 | * @type {boolean} 41 | */ 42 | $.isMobi = /(iPhone|iPod|iPad|android)/i.test(ua); 43 | /** 44 | * 是否为安卓 45 | * @type {boolean} 46 | */ 47 | $.isAndroid = /(android)/i.test(ua); 48 | /** 49 | * 是否为ios 50 | * @type {boolean} 51 | */ 52 | $.isIos = /(iPhone|iPod|iPad)/i.test(ua); 53 | 54 | 55 | /** 56 | * 显示/隐藏mask函数 57 | * @param {boolean} isShow 是否显示 58 | */ 59 | $.toggleMask = function (isShow) { 60 | isShow ? $body.addClass('onmask') : $body.removeClass('onmask'); 61 | }; 62 | 63 | 64 | //文档加载完成 65 | $(function () { 66 | 67 | setTimeout(function () { 68 | //添加class 69 | $body.addClass('loaded'); 70 | }, 100); 71 | 72 | //a标签touch 73 | $doc.on('touchstart', 'a', function () { 74 | $(this).addClass('focus'); 75 | }); 76 | $doc.on('touchend touchmove', 'a', function () { 77 | $(this).removeClass('focus'); 78 | }); 79 | 80 | //pc端二维码 81 | $.isShowQrcode && !$.isMobi && $.getScript('https://soneway.github.io/js/qrcode.js', function () { 82 | var $qrcode = $('#qrcode'); 83 | if ($qrcode.length === 0) { 84 | $qrcode = $('
'); 85 | $body.append($qrcode); 86 | new QRCode($qrcode[0], { 87 | width: $qrcode.width(), 88 | height: $qrcode.height(), 89 | text: location.href 90 | }); 91 | } 92 | $doc.on('click', '#qrcode', function () { 93 | $qrcode.hide(); 94 | }); 95 | } 96 | ); 97 | 98 | //pc端mouse转touch事件 99 | !$.isMobi && $.getScript('https://soneway.github.io/js/desktouch.js'); 100 | 101 | }); 102 | 103 | })(window, $); -------------------------------------------------------------------------------- /ui/base.scss: -------------------------------------------------------------------------------- 1 | /* 2 | ui/base 3 | 移动端基础样式 4 | 包括样式重置,常用类等 5 | */ 6 | 7 | //默认变量 8 | $root-font-size: 100px !default; 9 | $font-size: 0.28rem !default; 10 | $color: #333 !default; 11 | $line-height: 1.5 !default; 12 | $color-focus: #df2221 !default; 13 | //面板背景 14 | $panel-bgcolor: #fff !default; 15 | $duration: 0.3s !default; 16 | 17 | //引入 18 | @import "../scss/var"; 19 | @import "scss/ani/ani_spinner"; 20 | 21 | html 22 | { 23 | font-size: $root-font-size; 24 | } 25 | 26 | 27 | /*元素*/ 28 | *, *:before, *:after 29 | { 30 | margin: 0; 31 | padding: 0; 32 | /*将元素的padding,border也纳入宽度,相当于IE5的盒子模型*/ 33 | box-sizing: border-box; 34 | /*不使用占位符生成css代码,是避免多一次选择器的匹配*/ 35 | } 36 | 37 | 38 | body 39 | { 40 | /*加背景色可减缓页面闪烁*/ 41 | background-color: $panel-bgcolor; 42 | overflow-x: hidden; 43 | /*可继承*/ 44 | color: $color; 45 | line-height: $line-height; 46 | font-size: $font-size; 47 | font-family: arial, helvetica, sans-serif; 48 | -webkit-text-size-adjust: none; 49 | /*禁止选中文本*/ 50 | user-select: none; 51 | /*部分浏览器点选时会有淡蓝色框,这样可以去掉*/ 52 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0); 53 | /*禁止保存图片*/ 54 | -webkit-touch-callout: none; 55 | /*滚动平滑*/ 56 | -webkit-overflow-scrolling: touch; 57 | } 58 | 59 | 60 | input, textarea, select 61 | { 62 | font-size: inherit; 63 | } 64 | 65 | 66 | input, textarea 67 | { 68 | user-select: text; 69 | } 70 | 71 | 72 | input, select 73 | { 74 | height: 0.64rem; 75 | text-indent: 0.1rem; 76 | } 77 | 78 | 79 | textarea 80 | { 81 | padding: 0.1rem; 82 | } 83 | 84 | 85 | img, input 86 | { 87 | vertical-align: middle; 88 | } 89 | 90 | 91 | img 92 | { 93 | border: none; 94 | } 95 | 96 | 97 | a 98 | { 99 | outline: none; 100 | color: inherit; 101 | text-decoration: none; 102 | cursor: pointer; 103 | } 104 | 105 | 106 | a.focus 107 | { 108 | color: $color-focus; 109 | } 110 | 111 | 112 | li 113 | { 114 | list-style: none; 115 | } 116 | 117 | 118 | i 119 | { 120 | font-style: normal; 121 | } 122 | 123 | 124 | /*h类标签*/ 125 | $hx: (h1: 1.45em, h2: 1.3em, h3: 1.15em, h4: 1em); 126 | @each $h, $size in $hx 127 | { 128 | #{$h} 129 | { 130 | font-size: $size; 131 | } 132 | } 133 | 134 | 135 | /*类*/ 136 | /*btn*/ 137 | .btn 138 | { 139 | $c: #333; 140 | 141 | display: inline-block; 142 | font-size: 0.32rem; 143 | line-height: 2; 144 | min-width: 5.5em; 145 | padding: 0 1.25em; 146 | border-radius: 0.4em; 147 | @extend .center; 148 | border: 1px solid rgba(#000, 0.3); 149 | background-color: #f8f8f8; 150 | /*固定颜色*/ 151 | color: $c; 152 | 153 | &.focus 154 | { 155 | background-color: #eee; 156 | } 157 | } 158 | 159 | 160 | /*隐藏*/ 161 | .hide 162 | { 163 | display: none !important; 164 | } 165 | 166 | 167 | /*显示*/ 168 | .show 169 | { 170 | display: block !important; 171 | } 172 | 173 | 174 | .fade-out, .fade-in 175 | { 176 | @extend .transition; 177 | transition-property: opacity, visibility; 178 | } 179 | 180 | 181 | /*渐隐*/ 182 | .fade-out 183 | { 184 | visibility: hidden !important; 185 | opacity: 0 !important; 186 | } 187 | 188 | 189 | /*渐显*/ 190 | .fade-in 191 | { 192 | visibility: visible !important; 193 | opacity: 1 !important; 194 | } 195 | 196 | 197 | /*float*/ 198 | .fl 199 | { 200 | float: left; 201 | } 202 | 203 | 204 | .fr 205 | { 206 | float: right; 207 | } 208 | 209 | 210 | /*居中*/ 211 | .center 212 | { 213 | text-align: center; 214 | } 215 | 216 | 217 | /*动画*/ 218 | .transition 219 | { 220 | transition: all $duration ease; 221 | } 222 | 223 | 224 | .transform 225 | { 226 | transition: transform $duration ease; 227 | } 228 | 229 | 230 | .notrans 231 | { 232 | transition: none !important; 233 | } 234 | 235 | 236 | /*非常高的高度*/ 237 | .very-high 238 | { 239 | height: 9999px; 240 | } 241 | 242 | 243 | /*mainbox*/ 244 | #mainbox 245 | { 246 | @extend %ph_pafull; 247 | overflow: hidden; 248 | } 249 | 250 | 251 | /*loading*/ 252 | #loading 253 | { 254 | @extend %ph_pafull; 255 | background-color: $panel-bgcolor; 256 | z-index: 5; 257 | /*防止点击事件绑定不到(ios8)*/ 258 | cursor: pointer; 259 | @extend .transition; 260 | transition-property: background-color, visibility; 261 | @extend %ph_center; 262 | @extend .ani_spinner; 263 | 264 | .loaded & 265 | { 266 | visibility: hidden; 267 | background-color: transparent; 268 | 269 | &:before, &:after 270 | { 271 | opacity: 0; 272 | } 273 | } 274 | 275 | .onsidebox & 276 | { 277 | visibility: visible; 278 | background-color: rgba(0, 0, 0, 0.7); 279 | } 280 | 281 | &:after 282 | { 283 | display: block; 284 | padding-top: 1.2rem; 285 | content: '拼命加载...'; 286 | font-size: 0.2rem; 287 | } 288 | } 289 | 290 | 291 | /*二维码*/ 292 | #qrcode 293 | { 294 | @include mx_prt(fixed, 10px, 90px); 295 | width: 200px; 296 | height: 200px; 297 | } 298 | 299 | 300 | /*mask*/ 301 | .onmask 302 | { 303 | @include ani_spinner($dc: #fff); 304 | 305 | &:before 306 | { 307 | z-index: 10000; 308 | position: fixed; 309 | } 310 | 311 | &:after 312 | { 313 | content: ''; 314 | @extend %ph_pffull; 315 | background-color: rgba(0, 0, 0, 0.3); 316 | z-index: 9999; 317 | } 318 | } 319 | 320 | 321 | //@media screen and(min-width: 641px) { 322 | // html 323 | // { 324 | // font-size: 50px; 325 | // } 326 | //} -------------------------------------------------------------------------------- /ui/body_scroll.scss: -------------------------------------------------------------------------------- 1 | /* 2 | ui/base 3 | body可滚动页面样式 4 | 复写了overflow:hidden;等样式,使得页面可以body滚动 5 | */ 6 | #mainbox 7 | { 8 | overflow: visible; 9 | 10 | .onsidebox & 11 | { 12 | overflow: hidden; 13 | } 14 | } 15 | 16 | 17 | #header, #navbar 18 | { 19 | @extend %ph_fixed; 20 | } 21 | 22 | 23 | .panel 24 | { 25 | height: auto; 26 | min-height: 100%; 27 | overflow: visible; 28 | background-color: transparent; 29 | box-shadow: none; 30 | 31 | //填充背景 32 | &:before 33 | { 34 | content: ''; 35 | @extend %ph_palt; 36 | @extend %ph_full; 37 | background-color: $panel-bgcolor; 38 | @extend .left-sd; 39 | z-index: -1; 40 | } 41 | 42 | /*避免页面不够高,挡不住隐藏页面以及左边框*/ 43 | .reflow &:before 44 | { 45 | height: 99999px; 46 | } 47 | } -------------------------------------------------------------------------------- /ui/ui.js: -------------------------------------------------------------------------------- 1 | /* 2 | * ui.js 3 | * 移动端界面js,包括面板切换,导航,边栏等功能 4 | */ 5 | (function (window, $) { 6 | 7 | //文档元素 8 | var document = window.document, 9 | //文档$对象 10 | $doc = $(document), 11 | //body对象 12 | bodyEl = document.body, 13 | //body $对象 14 | $body = $(bodyEl), 15 | //mainbox $对象 16 | $mainbox = $('#mainbox'); 17 | 18 | /** 19 | * 首页hash(默认为#home) 20 | * @type {string} 21 | */ 22 | $.homeSelector = '#home'; 23 | 24 | 25 | //body scroll时设置宽度(ios中header宽度的bug) 26 | $.isBodyScroll && $.isIos && $(window).on('resize', (function () { 27 | var $toFix = $('#header,#navbar'); 28 | return function () { 29 | $toFix.css({ 30 | width: bodyEl.offsetWidth + 'px' 31 | }); 32 | }; 33 | })()).trigger('resize'); 34 | 35 | 36 | /** 37 | * 显示/隐藏头部函数 38 | * @param {boolean} isShow 是否显示 39 | */ 40 | $.toggleHeader = function (isShow) { 41 | isShow ? $mainbox.removeClass('offheader') : $mainbox.addClass('offheader'); 42 | }; 43 | 44 | /** 45 | * 显示/隐藏导航条函数 46 | * @param {boolean} isShow 是否显示 47 | */ 48 | $.toggleNavbar = function (isShow) { 49 | isShow ? $mainbox.removeClass('offnavbar') : $mainbox.addClass('offnavbar'); 50 | }; 51 | 52 | /** 53 | * 设置标题函数 54 | * @param {string} title 标题 55 | */ 56 | $.setTitle = (function () { 57 | var $title = $('.roottitle .title'); 58 | return function (title) { 59 | title && $title.html(title); 60 | }; 61 | })(); 62 | 63 | /** 64 | * 设置二级页面标题函数 65 | * @param {string} title 二级页面标题 66 | */ 67 | $.setSubtitle = (function () { 68 | var $title = $('.subtitle .title'); 69 | return function (title) { 70 | title && $title.html(title); 71 | }; 72 | })(); 73 | 74 | 75 | /** 76 | * 加载panel函数 77 | * @param {string} hash panel的hash(如#home) 78 | * @param {boolean} isAnimation 是否动画 79 | */ 80 | $.loadPanel = (function () { 81 | 82 | //导航中的a元素 83 | var $navbarA = $('#navbar a'), 84 | //导航容器元素 85 | navboxEl = document.querySelector('.navbox'), 86 | //面板元素 87 | $panel = $('.panel'), 88 | //panel切换动画duration 89 | duration = parseFloat($panel.css('transition-duration')) * 1000, 90 | //历史记录对象 91 | history = $.history = [], 92 | //header元素 93 | $header = $('#header'); 94 | 95 | /** 96 | * 页面加载是否动画(默认为true) 97 | * @type {boolean} 98 | */ 99 | $.isLoadAnimation = true; 100 | 101 | /** 102 | * scrollTop处理相关 103 | * @param {string} id 元素id 104 | * @param {boolean} isCache 是否是存储scrollTop 105 | * @ignore 106 | */ 107 | var scrollTop = (function () { 108 | var cache = {}; 109 | return function (id, isCache) { 110 | if ($.isBodyScroll) { 111 | //是否是存储scrollTop 112 | isCache ? (cache[id] = bodyEl.scrollTop) : (bodyEl.scrollTop = cache[id] || 0); 113 | } 114 | }; 115 | })(); 116 | 117 | /** 118 | * 显示panel时函数 119 | * @param {$init} $toShow 显示的$对象 120 | * @param {boolean} isNoScroll 是否不恢复scrollTop 121 | * @ignore 122 | */ 123 | var toShowPanel = (function () { 124 | var cache = {}; 125 | return function ($toShow, isNoScroll) { 126 | var id = $toShow[0].id; 127 | 128 | //显示 129 | $toShow.addClass('show opened'); 130 | 131 | //b.设置scrollTop(必须放在显示之后) 132 | setTimeout(function () { 133 | !isNoScroll && scrollTop(id); 134 | }, 0); 135 | 136 | //显示时调用函数 137 | var panelLoaded = $.panelLoaded; 138 | typeof panelLoaded === 'function' && panelLoaded($toShow, !cache[id]); 139 | 140 | //记录panel是否初始化过(放在最后) 141 | cache[id] = true; 142 | }; 143 | })(); 144 | 145 | /** 146 | * 隐藏panel时函数 147 | * @param {$init} $toHide 隐藏的$对象 148 | * @param {boolean} isShow 是否不隐藏元素 149 | * @ignore 150 | */ 151 | function toHidePanel($toHide, isShow) { 152 | //隐藏 153 | !isShow && $toHide.removeClass('show'); 154 | 155 | //如果是打开iframe页面的面板 156 | $toHide[0].id === 'paneliframe' && ($toHide.html('')); 157 | 158 | //隐藏时调用函数 159 | var panelUnloaded = $.panelUnloaded; 160 | typeof panelUnloaded === 'function' && panelUnloaded($toHide); 161 | } 162 | 163 | 164 | /** 165 | * 显示/隐藏边栏函数 166 | * @param {boolean} isShow 是否显示 167 | */ 168 | $.toggleSidebox = (function () { 169 | var $sidebox = $('#sidebox'); 170 | 171 | return function (isShow) { 172 | //相关panel 173 | var $panel = $.history[$.history.length - 1]; 174 | if (isShow) { 175 | $body.addClass('onsidebox'); 176 | //显示时调用函数 177 | toShowPanel($sidebox); 178 | //隐藏原页面 179 | toHidePanel($panel, true); 180 | } 181 | else { 182 | $body.removeClass('onsidebox'); 183 | //隐藏时调用函数 184 | toHidePanel($sidebox); 185 | //显示原页面 186 | toShowPanel($panel, true); 187 | } 188 | }; 189 | })(); 190 | 191 | return function (hash, isAnimation) { 192 | var $toShow, $toHide; 193 | 194 | //没有hash(表示后退) 195 | if (hash === undefined) { 196 | $toHide = history.pop(); 197 | $toShow = history[history.length - 1] || $($.homeSelector); 198 | hash = '#' + $toShow[0].id; 199 | } 200 | else { 201 | $toShow = $(hash); 202 | if ($toShow.length > 0) { 203 | $toHide = history[history.length - 1]; 204 | history.push($toShow); 205 | } 206 | } 207 | 208 | 209 | //如果有显示面板 210 | if ($toShow.length > 0) { 211 | 212 | //navbar选中状态(与面板切换无关的操作) 213 | $navbarA.length > 0 && $navbarA.each(function () { 214 | var array = (this.getAttribute('data-hash') || this.hash).split('|'); 215 | for (var i = 0, len = array.length; i < len; i++) { 216 | if (array[i] === hash) { 217 | $navbarA.removeClass('selected'); 218 | $(this).addClass('selected'); 219 | //居中 220 | navboxEl.center(this); 221 | } 222 | } 223 | }); 224 | 225 | //标题,navbar状态(与面板切换无关的操作) 226 | var showRole = $toShow.attr('data-role'); 227 | if (showRole === 'root') { 228 | //设置标题 229 | $.setTitle($toShow.attr('title')); 230 | 231 | //显示navbar 232 | $.toggleNavbar(true); 233 | 234 | //header内容切换 235 | $header.removeClass('onsubtitle'); 236 | } 237 | else { 238 | //设置二级页面标题 239 | $.setSubtitle($toShow.attr('title')); 240 | 241 | //隐藏navbar 242 | $.toggleNavbar(false); 243 | 244 | //header内容切换 245 | $header.addClass('onsubtitle'); 246 | } 247 | 248 | 249 | //没有隐藏面板的特殊情况(页面第一次加载) 250 | if (!$toHide) { 251 | //显示时调用函数 252 | toShowPanel($toShow); 253 | return; 254 | } 255 | 256 | 257 | //面板切换 258 | if ('#' + $toHide[0].id !== hash) { 259 | var hideRole = $toHide.attr('data-role'); 260 | 261 | //a.记录scrollTop(必须放在隐藏之前) 262 | scrollTop($toHide[0].id, 1); 263 | 264 | 265 | //一级->一级或无动画 266 | var isAni = isAnimation === undefined ? $.isLoadAnimation : isAnimation; 267 | if (!isAni || showRole === 'root' && hideRole === 'root') { 268 | //无动画 269 | $toShow.addClass('notrans'); 270 | $toHide.addClass('notrans'); 271 | 272 | //显示时调用函数(放在靠后) 273 | toShowPanel($toShow); 274 | //隐藏时调用函数(放在靠后) 275 | toHidePanel($toHide); 276 | return; 277 | } 278 | 279 | 280 | //其他切换 281 | //1.显示 282 | $toShow.addClass('show'); 283 | 284 | //切换面板时强制重排一次,以免出现横向滚动条 285 | $mainbox.addClass('reflow'); 286 | 287 | //2.延迟保证显示动画 288 | setTimeout(function () { 289 | //有动画 290 | $toShow.removeClass('notrans'); 291 | $toHide.removeClass('notrans'); 292 | 293 | //二级->一级 294 | if (showRole === 'root') { 295 | $toShow.removeClass('subopened'); 296 | $toHide.removeClass('opened'); 297 | } 298 | //显示二级面板 299 | else { 300 | //一级->二级 301 | if ($toShow.hasClass('subopened')) { 302 | $toShow.removeClass('subopened'); 303 | $toHide.removeClass('opened'); 304 | } 305 | //二级->二级 306 | else { 307 | $toHide.addClass('subopened').removeClass('opened'); 308 | } 309 | } 310 | 311 | //显示时调用函数(放在靠后) 312 | toShowPanel($toShow); 313 | 314 | 315 | //3.延迟保证隐藏动画 316 | setTimeout(function () { 317 | 318 | //延迟重排(延迟100ms+在ios8上才有效果,安卓4.2需要400ms+) 319 | setTimeout(function () { 320 | //切换面板时强制重排一次,以免出现横向滚动条 321 | $mainbox.removeClass('reflow'); 322 | }, 400); 323 | 324 | //隐藏时调用函数(放在靠后) 325 | toHidePanel($toHide); 326 | }, duration); 327 | 328 | }, 10); 329 | } 330 | } 331 | //没有显示面板 332 | else { 333 | console.log(hash + '面板未找到'); 334 | } 335 | 336 | }; 337 | 338 | })(); 339 | 340 | 341 | //文档加载完成 342 | $(function () { 343 | 344 | //btn-onsidebox点击 345 | $doc.on('click', '.btn-onsidebox', function () { 346 | $.toggleSidebox(1); 347 | }); 348 | //btn-offsidebox点击 349 | $doc.on('click', '.btn-offsidebox', function () { 350 | $.toggleSidebox(0); 351 | }); 352 | 353 | //iframe面板 354 | var $iframe = $('#paneliframe'); 355 | if ($iframe.length === 0) { 356 | $iframe = $('
'); 357 | $mainbox.append($iframe); 358 | } 359 | 360 | //a标签点击事件切换panel 361 | $doc.on('click', 'a', function (evt) { 362 | var hash = this.hash; 363 | if (hash) { 364 | evt.preventDefault(); 365 | $.loadPanel(hash); 366 | return; 367 | } 368 | 369 | //不跳出页面加载其他页面(需要a标签有data-href属性) 370 | var href = this.getAttribute('data-href'), 371 | title = this.getAttribute('data-title'); 372 | 373 | if (href) { 374 | evt.preventDefault(); 375 | $iframe.html(''); 376 | $.setSubtitle(title || '详情'); 377 | $.loadPanel('#paneliframe'); 378 | } 379 | }); 380 | 381 | //返回按钮点击 382 | $doc.on('click', '#btn-goback', function () { 383 | $.loadPanel(); 384 | }); 385 | 386 | 387 | //导航条 388 | var $navbox = $('.navbox'); 389 | //导航条拨动 390 | $navbox.length > 0 && $navbox.scroll(); 391 | 392 | //初始化加载指定panel或者首页 393 | var hash = location.hash; 394 | $.loadPanel(hash || $.homeSelector); 395 | 396 | }); 397 | 398 | })(window, $); -------------------------------------------------------------------------------- /ui/ui.scss: -------------------------------------------------------------------------------- 1 | /* 2 | ui/ui 3 | 移动端界面样式 4 | 包含面板,导航,边栏等样式 5 | */ 6 | 7 | //默认变量 8 | //布局 9 | $head-height: 0.8rem !default; 10 | $navbar-height: 1rem !default; 11 | //默认为1:纯色背景,2:渐变背景 12 | $bg-type: 1 !default; 13 | //导航条背景 14 | $head-bgcolor: rgba(255, 255, 255, 0.9) !default; 15 | $head-bg: #006c1a 0%, #04990e 100% !default; 16 | //边框颜色 17 | $head-border-color: rgba(128, 128, 128, 0.5) !default; 18 | //颜色 19 | $head-color: $color !default; 20 | 21 | //引入 22 | @import "../plugin/scroll"; 23 | 24 | /*重排类*/ 25 | .reflow 26 | { 27 | padding-bottom: 1px !important; 28 | } 29 | 30 | 31 | /*左阴影*/ 32 | .left-sd 33 | { 34 | /*outline会导致下边框问题*/ 35 | //outline: 4px solid rgba(0, 0, 0, 0.1); 36 | //border-left: 2px solid rgba(#000, 0.2); 37 | /*box-shadow对安卓动画性能影响太明显*/ 38 | box-shadow: -0.1rem 0 0.06rem -0.06rem rgba(0, 0, 0, 0.2); 39 | } 40 | 41 | 42 | /*head导航条背景*/ 43 | .head, #navbar 44 | { 45 | overflow: hidden; 46 | 47 | @if $bg-type == 1 48 | { 49 | background-color: $head-bgcolor; 50 | } @else 51 | { 52 | background: linear-gradient(to bottom, $head-bg); 53 | } 54 | } 55 | 56 | 57 | /*head类*/ 58 | .head 59 | { 60 | @extend %ph_palt; 61 | height: $head-height; 62 | line-height: $head-height; 63 | right: 0; 64 | z-index: 1; 65 | color: $head-color; 66 | border-bottom: 1px solid $head-border-color; 67 | 68 | .btnleft, .btnright 69 | { 70 | z-index: 2; 71 | padding: 0 0.6em; 72 | height: 100%; 73 | font-size: 0.32rem; 74 | } 75 | 76 | .btnleft 77 | { 78 | @extend %ph_palt; 79 | } 80 | 81 | .btnright 82 | { 83 | @extend %ph_part; 84 | } 85 | 86 | /*返回按钮*/ 87 | .btnback 88 | { 89 | padding-left: 0.44rem; 90 | 91 | &:before 92 | { 93 | $w: 0.28rem; 94 | 95 | content: ''; 96 | @include mx_plt($left: $w, $top: 50%); 97 | margin-top: -$w / 2; 98 | @include mx_left-arrow($width: $w, $color: $head-color, $line-width: 2px); 99 | } 100 | 101 | &.focus:before 102 | { 103 | box-shadow: -2px -2px 0 $color-focus; 104 | } 105 | } 106 | 107 | /*菜单按钮*/ 108 | .btnmenu 109 | { 110 | width: 2.5em; 111 | padding: 0.6em; 112 | background: linear-gradient($color 2px, transparent 0%) left 0.8em; 113 | background-size: 100% 20%; 114 | background-clip: content-box; 115 | 116 | &.focus 117 | { 118 | background-image: linear-gradient($color-focus 2px, transparent 0%); 119 | } 120 | } 121 | 122 | .title 123 | { 124 | text-align: center; 125 | } 126 | } 127 | 128 | 129 | /*mainbox*/ 130 | #mainbox 131 | { 132 | @extend .transform; 133 | 134 | .onsidebox & 135 | { 136 | transform: translate3d(-50%, 0, 0); 137 | } 138 | } 139 | 140 | 141 | /*边栏*/ 142 | #sidebox 143 | { 144 | /*必须fixed定位,absolute在qq浏览器中有bug(横向滚动条)*/ 145 | @extend %ph_pfrt; 146 | height: 100%; 147 | width: 80%; 148 | background-color: $panel-bgcolor; 149 | z-index: 9; 150 | transform: translate3d(100%, 0, 0); 151 | @extend .transform; 152 | 153 | .content 154 | { 155 | height: 100%; 156 | padding-top: $head-height; 157 | overflow: auto; 158 | } 159 | 160 | .onsidebox & 161 | { 162 | transform: translate3d(0, 0, 0); 163 | @extend .left-sd; 164 | } 165 | } 166 | 167 | 168 | /*头部*/ 169 | #header 170 | { 171 | @extend .transition; 172 | 173 | .offheader & 174 | { 175 | //兼容性不太好 176 | //transform:translate3d(0, -100%, 0); 177 | @extend %ph_hidden; 178 | } 179 | 180 | .roottitle, .subtitle 181 | { 182 | @extend %ph_pafull; 183 | @extend .transition; 184 | overflow: hidden; 185 | } 186 | 187 | /*二级页面标题*/ 188 | .subtitle 189 | { 190 | @extend %ph_hidden; 191 | } 192 | 193 | /*显示二级页面标题*/ 194 | &.onsubtitle 195 | { 196 | .roottitle 197 | { 198 | @extend %ph_hidden; 199 | } 200 | 201 | .subtitle 202 | { 203 | @extend %ph_visible; 204 | } 205 | } 206 | } 207 | 208 | 209 | /*面板*/ 210 | .panel 211 | { 212 | /*二级面板会出现横向滚动条的bug,可以通过对二级面板的重排来解决,比如显示面板时,padding-bottom的值的改变*/ 213 | @extend %ph_palt; 214 | right: 0; 215 | height: 100%; 216 | overflow: auto; 217 | padding-top: $head-height; 218 | display: none; 219 | @extend .transform; 220 | transform: translate3d(100%, 0, 0); 221 | background-color: $panel-bgcolor; 222 | @extend .left-sd; 223 | 224 | &[data-role=root] 225 | { 226 | padding-bottom: $navbar-height; 227 | } 228 | 229 | &.subopened 230 | { 231 | transform: translate3d(-40%, 0, 0); 232 | } 233 | 234 | &.opened 235 | { 236 | transform: translate3d(0, 0, 0); 237 | } 238 | 239 | .offheader & 240 | { 241 | padding-top: 0; 242 | } 243 | } 244 | 245 | 246 | /*打开iframe页面的面板*/ 247 | #paneliframe 248 | { 249 | height: 100%; 250 | 251 | iframe 252 | { 253 | @extend %ph_full; 254 | border: none; 255 | } 256 | } 257 | 258 | 259 | /*导航*/ 260 | #navbar 261 | { 262 | /*safari中,在滚动页面隐藏工具栏的情况下,点击屏幕下方bottom:约50px以内的范围内,都会触发显示工具栏操作,而导致点击失效,必须点第二次*/ 263 | @extend %ph_palb; 264 | right: 0; 265 | height: $navbar-height; 266 | z-index: 1; 267 | @extend .center; 268 | border-top: 1px solid $head-border-color; 269 | @extend .transition; 270 | 271 | .offnavbar > & 272 | { 273 | @extend %ph_hidden; 274 | } 275 | 276 | .navbox 277 | { 278 | overflow: hidden; 279 | height: 100%; 280 | max-width: 100%; 281 | display: inline-block; 282 | } 283 | 284 | .navlist 285 | { 286 | display: table; 287 | height: 100%; 288 | white-space: nowrap; 289 | line-height: 1.1; 290 | 291 | a 292 | { 293 | @extend %ph_td; 294 | } 295 | } 296 | } --------------------------------------------------------------------------------