Merge branch 'master' of gitlab.qima-inc.com:fe/zanui-vue

This commit is contained in:
taiyong 2017-03-14 10:33:32 +08:00
commit a8d75dc0ab
83 changed files with 2324 additions and 184 deletions

View File

@ -1,35 +1,61 @@
## 下载项目
```bash
git@gitlab.qima-inc.com:fe/zanui-vue.git
cd zanui-vue
<p>
<a href="https://github.com/youzan/"><img alt="有赞logo" width="36px" src="https://img.yzcdn.cn/public_files/2017/02/09/e84aa8cbbf7852688c86218c1f3bbf17.png" alt="youzan">
</p></a>
<p align="center">
<img alt="项目logo" src="https://img.yzcdn.cn/public_files/2017/02/06/ee0ebced79a80457d77ce71c7d414c74.png">
</p>
<p align="center">Vue Mobile UI at YouZan</p>
## 一、安装
```shell
ynpm install @youzan/zanui-vue
```
## 二、使用
### 1. 导入所有组件
```javascript
import Vue from 'vue';
import ZanUI from '@youzan/zanui-vue';
// 你也可以使用自己的主题
import '@youzan/zanui-vue/lib/zanui-css/index.css';
Vue.use(ZanUI);
```
### 2. 按需导入组件
```javascript
import Vue from 'vue';
import { Button, Cell } from '@youzan/zanui-vue';
import '@youzan/zanui-vue/lib/zanui-css/button.css';
import '@youzan/zanui-vue/lib/zanui-css/cell.css';
Vue.component(Button.name, Button);
Vue.component(Cell.name, Cell);
```
## 安装组件依赖库
```bash
ynpm i
## 三、开发
### 1. 新建一个组件
```shell
make init componentName
```
## 新建组件以waterfall为例
新建一个Vue组件比如 waterfall
```bash
make init waterfall
```
就可以在 packages目录 里面看到waterfall初始化的组件代码了。记得更新package.json和README.md里的组件描述信息
### 2. 示例预览
## 示例预览以waterfall为例
在 docs/nav.config.json 文件里合适的地方写入组件声明根据组件类型JS组件CSS组件Form等进行区分
在 docs/examples 目录里新建 同名的md文件如 waterfall.md
在项目的根目录下执行以下命令启动server
```
`docs/nav.config.json`文件里合适的地方写入组件声明根据组件类型JS组件CSS组件Form等进行区分 在`docs/examples-docs`目录里新建同名的md文件`waterfall.md`在项目的根目录下执行以下命令启动server
```shell
make dev
```
浏览器访问 http://localhost:8080/#/ 就可以看到所有组件的示例了
浏览器访问[http://localhost:8080](http://localhost:8080)就可以看到所有组件的示例了。
## 四、开源协议
本项目基于 [MIT](https://zh.wikipedia.org/wiki/MIT%E8%A8%B1%E5%8F%AF%E8%AD%89) 协议,请自由地享受和参与开源。

View File

@ -5,6 +5,10 @@ delete config.devtool;
config.entry = Components;
config.externals = {
vue: 'vue'
};
config.output = {
path: './lib',
filename: '[name].js',

View File

@ -42,7 +42,9 @@ module.exports = {
'vue$': 'vue/dist/vue.runtime.common.js',
'zanui': path.join(__dirname, '..'),
'src': path.join(__dirname, '../src'),
'packages': path.join(__dirname, '../packages')
'packages': path.join(__dirname, '../packages'),
'lib': path.join(__dirname, '../lib'),
'components': path.join(__dirname, '../docs/components')
}
},
module: {

View File

@ -22,8 +22,13 @@
"badge": "./packages/badge/index.js",
"search": "./packages/search/index.js",
"step": "./packages/step/index.js",
"tabs": "./packages/tabs/index.js",
"tab": "./packages/tab/index.js",
"lazyload": "./packages/lazyload/index.js",
"image-preview": "./packages/image-preview/index.js",
"col": "./packages/col/index.js",
"row": "./packages/row/index.js",
"actionsheet": "./packages/actionsheet/index.js"
"actionsheet": "./packages/actionsheet/index.js",
"quantity": "./packages/quantity/index.js",
"progress": "./packages/progress/index.js"
}

View File

@ -34,7 +34,7 @@ export default {
line-height: 40px;
}
h3 {
section > h3 {
font-size: 22px;
margin: 23px 0;
}
@ -72,6 +72,12 @@ export default {
color: #5e6d82;
margin: 14px 0;
}
p > code {
background-color: #eee;
padding: 2px 4px;
color: #26a2ff;
}
}
.demo-page {

8
docs/build/0.js vendored

File diff suppressed because one or more lines are too long

2
docs/build/1.js vendored
View File

@ -1 +1 @@
webpackJsonp([1],{212:function(t,e,a){a(358);var i=a(0)(a(225),a(317),null,null);t.exports=i.exports},225:function(t,e,a){"use strict";function i(t){return t&&t.__esModule?t:{default:t}}Object.defineProperty(e,"__esModule",{value:!0});var n=a(24),s=i(n);e.default={data:function(){return{highlights:[],navState:[],data:s.default["zh-CN"],base:"/component"}}}},259:function(t,e,a){e=t.exports=a(15)(),e.push([t.i,".side-nav{width:100%;box-sizing:border-box;padding:40px 20px;background:#f9fafb}.side-nav li{list-style:none}.side-nav ul{padding:0;margin:0;overflow:hidden}.side-nav .nav-item a{font-size:16px;color:#5e6d82;line-height:40px;height:40px;margin:0;padding:0;text-decoration:none;display:block;position:relative;-webkit-transition:all .3s;transition:all .3s}.side-nav .nav-item a.active{color:#20a0ff}.side-nav .nav-item .nav-item a{display:block;height:40px;line-height:40px;font-size:13px;padding-left:24px}.side-nav .nav-item .nav-item a:hover{color:#20a0ff}.side-nav .nav-group__title{font-size:12px;color:#99a9bf;padding-left:8px;line-height:26px;margin-top:10px}",""])},317:function(t,e){t.exports={render:function(){var t=this,e=t.$createElement,a=t._self._c||e;return a("div",{staticClass:"side-nav"},[a("ul",t._l(t.data,function(e){return a("li",{staticClass:"nav-item"},[e.path?a("router-link",{attrs:{"active-class":"active",to:t.base+e.path,exact:""},domProps:{textContent:t._s(e.title||e.name)}}):a("a",[t._v(t._s(e.name))]),t._v(" "),e.children?a("ul",{staticClass:"pure-menu-list sub-nav"},t._l(e.children,function(e){return a("li",{staticClass:"nav-item"},[a("router-link",{attrs:{"active-class":"active",to:t.base+e.path},domProps:{textContent:t._s(e.title||e.name)}})],1)})):t._e(),t._v(" "),e.groups?t._l(e.groups,function(e){return a("div",{staticClass:"nav-group"},[a("div",{staticClass:"nav-group__title"},[t._v(t._s(e.groupName))]),t._v(" "),a("ul",{staticClass:"pure-menu-list"},[t._l(e.list,function(e){return[e.disabled?t._e():a("li",{staticClass:"nav-item"},[a("router-link",{attrs:{"active-class":"active",to:t.base+e.path},domProps:{textContent:t._s(e.title)}})],1)]})],2)])}):t._e()],2)}))])},staticRenderFns:[]}},358:function(t,e,a){var i=a(259);"string"==typeof i&&(i=[[t.i,i,""]]),i.locals&&(t.exports=i.locals);a(25)("1517d9c0",i,!0)}});
webpackJsonp([1],{229:function(t,e,a){a(425);var i=a(0)(a(243),a(373),null,null);t.exports=i.exports},243:function(t,e,a){"use strict";function i(t){return t&&t.__esModule?t:{default:t}}Object.defineProperty(e,"__esModule",{value:!0});var n=a(24),s=i(n);e.default={data:function(){return{highlights:[],navState:[],data:s.default["zh-CN"],base:"/component"}}}},287:function(t,e,a){e=t.exports=a(15)(),e.push([t.i,".side-nav{width:100%;box-sizing:border-box;padding:40px 20px;background:#f9fafb}.side-nav li{list-style:none}.side-nav ul{padding:0;margin:0;overflow:hidden}.side-nav .nav-item a{font-size:16px;color:#5e6d82;line-height:40px;height:40px;margin:0;padding:0;text-decoration:none;display:block;position:relative;-webkit-transition:all .3s;transition:all .3s}.side-nav .nav-item a.active{color:#20a0ff}.side-nav .nav-item .nav-item a{display:block;height:40px;line-height:40px;font-size:13px;padding-left:24px}.side-nav .nav-item .nav-item a:hover{color:#20a0ff}.side-nav .nav-group__title{font-size:12px;color:#99a9bf;padding-left:8px;line-height:26px;margin-top:10px}",""])},373:function(t,e){t.exports={render:function(){var t=this,e=t.$createElement,a=t._self._c||e;return a("div",{staticClass:"side-nav"},[a("ul",t._l(t.data,function(e){return a("li",{staticClass:"nav-item"},[e.path?a("router-link",{attrs:{"active-class":"active",to:t.base+e.path,exact:""},domProps:{textContent:t._s(e.title||e.name)}}):a("a",[t._v(t._s(e.name))]),t._v(" "),e.children?a("ul",{staticClass:"pure-menu-list sub-nav"},t._l(e.children,function(e){return a("li",{staticClass:"nav-item"},[a("router-link",{attrs:{"active-class":"active",to:t.base+e.path},domProps:{textContent:t._s(e.title||e.name)}})],1)})):t._e(),t._v(" "),e.groups?t._l(e.groups,function(e){return a("div",{staticClass:"nav-group"},[a("div",{staticClass:"nav-group__title"},[t._v(t._s(e.groupName))]),t._v(" "),a("ul",{staticClass:"pure-menu-list"},[t._l(e.list,function(e){return[e.disabled?t._e():a("li",{staticClass:"nav-item"},[a("router-link",{attrs:{"active-class":"active",to:t.base+e.path},domProps:{textContent:t._s(e.title)}})],1)]})],2)])}):t._e()],2)}))])},staticRenderFns:[]}},425:function(t,e,a){var i=a(287);"string"==typeof i&&(i=[[t.i,i,""]]),i.locals&&(t.exports=i.locals);a(25)("1517d9c0",i,!0)}});

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,19 @@
import MobilePopup from 'components/mobile-popup.vue';
export default {
components: {
MobilePopup
},
computed: {
mobileUrl() {
return location.pathname + 'examples.html' + location.hash;
}
},
data() {
return {
mobileShow: false
};
}
};

View File

@ -0,0 +1,45 @@
<template>
<zan-popup v-model="currentValue">
<div class="mobile-popup">
<iframe :src="url" class="mobile-popup-iframe"></iframe>
</div>
</zan-popup>
</template>
<script>
export default {
props: {
url: String,
value: {}
},
data() {
return {
currentValue: this.value
};
},
watch: {
currentValue(val) {
this.$emit('input', val);
},
value(val) {
console.log(val);
this.currentValue = val;
}
}
};
</script>
<style>
.mobile-popup {
width: 380px;
height: 500px;
border: 5px solid #e5e5e5;
}
.mobile-popup-iframe {
width: 100%;
height: 500px;
}
</style>

View File

@ -0,0 +1,76 @@
<template><section class="demo-actionsheet"><h1 class="demo-title">actionsheet</h1><example-block title="基础用法">
<div class="zan-row">
<zan-button @click="show1 = true">弹出actionsheet</zan-button>
</div>
<zan-actionsheet v-model="show1" :actions="actions1">
</zan-actionsheet>
</example-block><example-block title="带取消按钮的ActionSheet">
<div class="zan-row">
<zan-button @click="show2 = true">弹出带取消按钮的actionsheet</zan-button>
</div>
<zan-actionsheet v-model="show2" :actions="actions1" cancel-text="取消">
</zan-actionsheet>
</example-block><example-block title="带标题的ActionSheet">
<div class="zan-row">
<zan-button @click="show3 = true">弹出带标题的actionsheet</zan-button>
</div>
<zan-actionsheet v-model="show3" title="支持以下配送方式" class="title-actionsheet">
<p>一些内容</p>
</zan-actionsheet>
</example-block></section></template>
<style>
@component-namespace demo {
@b actionsheet {
.actionsheet-wx {
color: #06BF04;
}
.zan-button {
margin-left: 15px;
}
.title-actionsheet p {
padding: 20px;
}
}
}
</style>
<script>
import Vue from "vue";import ExampleBlock from "../components/example-block";Vue.component("example-block", ExampleBlock);
import MobileComputed from 'components/mobile-computed';
export default {
mixins: [MobileComputed],
data() {
return {
show1: false,
show2: false,
show3: false,
actions1: [
{
name: '微信安全支付',
className: 'actionsheet-wx'
},
{
name: '支付宝支付',
loading: true
},
{
name: '有赞E卡',
subname: '剩余260.50元)'
},
{
name: '信用卡支付'
},
{
name: '其他支付方式'
}
]
};
}
}
</script>

View File

@ -3,13 +3,12 @@
</zan-card>
</example-block><example-block title="高级用法">
<zan-card title="商品名称是什么,两行显示状态如效果图,多余多余多余两行显示状态如效果图,多余多余多余两行显示状态如效果图,多余多余多余两行显示状态如效果图,多余多余多余两行显示状态如效果图,多余多余多余" desc="商品SKU1商品SKU2" thumb="https://img.yzcdn.cn/upload_files/2017/02/17/FnDwvwHmU-OiqsbjAO5X7wh1KWrR.jpg!100x100.jpg">
<zan-card thumb="https://img.yzcdn.cn/upload_files/2017/02/17/FnDwvwHmU-OiqsbjAO5X7wh1KWrR.jpg!100x100.jpg">
<div class="zan-card__row" slot="title">
<h4 class="zan-card__title">商品名称是什么两行显示状态如效果图多余多余多余两行显示状态如效果图多余多余多余两行显示状态如效果图多余多余多余两行显示状态如效果图多余多余多余两行显示状态如效果图多余多余多余</h4>
<span class="zan-card__price">¥ 2.00</span>
</div>
<div class="zan-card__row" slot="desc">
<h4 class="zan-card__desc">商品sku</h4>
<span class="zan-card__num">x 2</span>
</div>
<div class="zan-card__footer" slot="footer">

View File

@ -6,12 +6,23 @@
</example-block></section></template>
<style>
@component-namespace demo {
@b dialog {
.zan-button {
margin: 15px;
}
}
}
</style>
<script>
import Vue from "vue";import ExampleBlock from "../components/example-block";Vue.component("example-block", ExampleBlock);
import { Dialog } from 'src/index';
import MobileComputed from 'components/mobile-computed';
export default {
mixins: [MobileComputed],
methods: {
handleAlertClick() {
Dialog.alert({

View File

@ -1,6 +1,6 @@
<template><section class="demo-field"><h1 class="demo-title">field</h1><example-block title="基础用法">
<zan-cell-group>
<zan-field type="text" label="用户名:" placeholder="请输入用户名"></zan-field>
<zan-field type="text" label="用户名:" placeholder="请输入用户名" v-model="username"></zan-field>
<zan-field type="password" label="密码:" placeholder="请输入密码"></zan-field>
<zan-field type="textarea" label="个人介绍:" placeholder="请输入个人介绍"></zan-field>
</zan-cell-group>
@ -10,12 +10,25 @@
<zan-field type="text" placeholder="请输入用户名"></zan-field>
</zan-cell-group>
</example-block><example-block title="监听change事件">
</example-block><example-block title="禁用的输入框">
<zan-cell-group>
<zan-field type="text" label="用户名:" placeholder="请输入用户名" @change="handleChange"></zan-field>
<zan-field label="用户名:" type="text" placeholder="请输入用户名" v-model="username" disabled></zan-field>
</zan-cell-group>
</example-block><example-block title="错误的输入框">
<zan-cell-group>
<zan-field label="用户名:" type="text" placeholder="请输入用户名" error=""></zan-field>
</zan-cell-group>
</example-block></section></template>
<script>
import Vue from "vue";import ExampleBlock from "../components/example-block";Vue.component("example-block", ExampleBlock);</script>
import Vue from "vue";import ExampleBlock from "../components/example-block";Vue.component("example-block", ExampleBlock);
export default {
data() {
return {
username: 'zhangmin'
};
}
};
</script>

View File

@ -0,0 +1,33 @@
<template><section class="demo-icon"><h1 class="demo-title">icon</h1><example-block title="所有Icon">
<zan-icon name="album"></zan-icon>
<zan-icon name="arrow"></zan-icon>
<zan-icon name="camera"></zan-icon>
<zan-icon name="certificate"></zan-icon>
<zan-icon name="check"></zan-icon>
<zan-icon name="checked"></zan-icon>
<zan-icon name="close"></zan-icon>
<zan-icon name="gift"></zan-icon>
<zan-icon name="home"></zan-icon>
<zan-icon name="location"></zan-icon>
<zan-icon name="message"></zan-icon>
<zan-icon name="send"></zan-icon>
<zan-icon name="shopping-cart"></zan-icon>
<zan-icon name="sign"></zan-icon>
<zan-icon name="store"></zan-icon>
<zan-icon name="topay"></zan-icon>
<zan-icon name="tosend"></zan-icon>
</example-block></section></template>
<style>
@component-namespace demo {
@b icon {
.zan-icon {
margin: 10px;
font-size: 45px;
}
}
}
</style>
<script>
import Vue from "vue";import ExampleBlock from "../components/example-block";Vue.component("example-block", ExampleBlock);</script>

View File

@ -1,6 +1,13 @@
<template><section class="demo-picker"><h1 class="demo-title">picker</h1><example-block title="基础用法">
<zan-picker :columns="pickerColumns" @change="handlePickerChange"></zan-picker>
</example-block><example-block title="带toolbar的Picker">
<zan-picker :columns="pickerColumns" show-toolbar="" @change="handlePickerChange" @cancel="handlePickerCancel" @confirm="handlePickerConfirm"></zan-picker>
</example-block></section></template>
<script>
@ -30,6 +37,12 @@ export default {
methods: {
handlePickerChange(picker, values) {
picker.setColumnValues(1, citys[values[0]]);
},
handlePickerCancel() {
alert('picker cancel');
},
handlePickerConfirm() {
alert('picker confirm');
}
}
};

View File

@ -1,9 +1,9 @@
<template><section class="demo-popup"><h1 class="demo-title">popup</h1><example-block title="基础用法">
<div class="zan-row">
<zan-button @click="popupShow1 = true">从下方弹出popup</zan-button>
<zan-button @click="popupShow1 = true;">从下方弹出popup</zan-button>
</div>
<zan-popup v-model="popupShow1" position="bottom" class="zan-popup-1">
xxxx
<zan-button @click="showDialog">弹出dialog</zan-button>
</zan-popup>
<div class="zan-row">
@ -23,17 +23,55 @@
<div class="zan-row">
<zan-button @click="popupShow4 = true">从中间弹出popup</zan-button>
</div>
<zan-popup v-model="popupShow4" transition="popup-fade" class="zan-popup-4">
一些内容
<zan-popup v-model="popupShow4" class="zan-popup-4">
从中间弹出popup
</zan-popup>
</example-block></section></template>
</example-block></section></template>
<style>
@component-namespace demo {
@b popup {
.zan-popup-1 {
width: 100%;
height: 200px;
box-sizing: border-box;
padding: 20px;
}
.zan-popup-2 {
line-height: 50px;
text-align: center;
background-color: rgba(0, 0, 0, 0.701961);
color: #fff;
}
.zan-popup-3 {
width: 100%;
height: 100%;
}
.zan-popup-4 {
width: 60%;
height: 200px;
}
.zan-button {
margin: 15px;
}
}
}
</style>
<script>
import Vue from "vue";import ExampleBlock from "../components/example-block";Vue.component("example-block", ExampleBlock);
import MobileComputed from 'components/mobile-computed';
import Dialog from 'packages/dialog';
export default {
mixins: [MobileComputed],
data() {
return {
popupShow1: false,
@ -51,6 +89,19 @@ export default {
}, 2000);
}
}
},
methods: {
showDialog() {
Dialog.confirm({
title: 'confirm标题',
message: '弹窗提示文字左右始终距离边20PX上下距离20PX文字左对齐。弹窗提示文字左右始终距离边20PX上下距离20PX文字左对齐。'
}).then((action) => {
console.log(action);
}, (error) => {
console.log(error);
});
}
}
};
</script>

View File

@ -0,0 +1,46 @@
<template><section class="demo-progress"><h1 class="demo-title">progress</h1><example-block title="基础用法">
<div class="demo-progress__wrapper">
<zan-progress class="demo-progress__demo1" :percentage="0"></zan-progress>
</div>
<div class="demo-progress__wrapper">
<zan-progress class="demo-progress__demo2" :percentage="46"></zan-progress>
</div>
<div class="demo-progress__wrapper">
<zan-progress class="demo-progress__demo1" :percentage="100"></zan-progress>
</div>
</example-block><example-block title="Inactive">
<div class="demo-progress__wrapper">
<zan-progress class="demo-progress__demo1" :inactive="true" :percentage="0"></zan-progress>
</div>
<div class="demo-progress__wrapper">
<zan-progress class="demo-progress__demo2" :inactive="true" :percentage="46"></zan-progress>
</div>
<div class="demo-progress__wrapper">
<zan-progress class="demo-progress__demo1" :inactive="true" :percentage="100"></zan-progress>
</div>
</example-block><example-block title="自定义颜色">
<div class="demo-progress__wrapper">
<zan-progress class="demo-progress__demo1" pivot-text="红色" color="#ed5050" :percentage="26"></zan-progress>
</div>
<div class="demo-progress__wrapper">
<zan-progress class="demo-progress__demo1" pivot-text="橙色" color="#f60" :percentage="46"></zan-progress>
</div>
<div class="demo-progress__wrapper">
<zan-progress class="demo-progress__demo1" pivot-text="黄色" color="#f09000" :percentage="66"></zan-progress>
</div>
</example-block></section></template>
<style>
@component-namespace demo {
@b progress {
@e wrapper {
padding: 5px;
margin: 20px 10px;
}
}
}
</style>
<script>
import Vue from "vue";import ExampleBlock from "../components/example-block";Vue.component("example-block", ExampleBlock);</script>

View File

@ -0,0 +1,36 @@
<template><section class="demo-quantity"><h1 class="demo-title">quantity</h1><example-block title="基础用法">
<zan-quantity v-model="quantity1"></zan-quantity>
<p class="curr-quantity">当前值{{ quantity1 }}</p>
</example-block><example-block title="禁用Quantity">
<zan-quantity v-model="quantity1" disabled></zan-quantity>
</example-block><example-block title="高级用法">
<zan-quantity v-model="quantity2" min="5" max="40" step="2" default-value="9"></zan-quantity>
<p class="curr-quantity">当前值{{ quantity2 }}</p>
</example-block></section></template>
<style>
@component-namespace demo {
@b quantity {
.zan-quantity {
margin: 15px;
}
.curr-quantity {
margin: 15px;
}
}
}
</style>
<script>
import Vue from "vue";import ExampleBlock from "../components/example-block";Vue.component("example-block", ExampleBlock);
export default {
data() {
return {
quantity1: 1,
quantity2: null,
};
}
};
</script>

View File

@ -0,0 +1,68 @@
<template><section class="demo-tab"><h1 class="demo-title">tab</h1><example-block title="基础用法">
<zan-tabs>
<zan-tab title="选项一">内容一</zan-tab>
<zan-tab title="选项二">内容二</zan-tab>
<zan-tab title="选项三">内容三</zan-tab>
<zan-tab title="选项四">内容四</zan-tab>
<zan-tab title="选项五">内容五</zan-tab>
</zan-tabs>
</example-block><example-block title="禁用用法">
<zan-tabs>
<zan-tab title="选项一">内容一</zan-tab>
<zan-tab disable="" title="选项二" @disable="popalert">内容二</zan-tab>
<zan-tab title="选项三">内容三</zan-tab>
<zan-tab title="选项四">内容四</zan-tab>
<zan-tab title="选项五">内容五</zan-tab>
</zan-tabs>
</example-block><example-block title="card样式用法">
<zan-tabs type="card">
<zan-tab title="选项一">内容一</zan-tab>
<zan-tab title="选项二">内容二</zan-tab>
<zan-tab title="选项三">内容三</zan-tab>
<zan-tab title="选项四">内容四</zan-tab>
<zan-tab title="选项五">内容五</zan-tab>
</zan-tabs>
</example-block><example-block title="自定义样式用法">
<zan-tabs active="2" navclass="custom-tabwrap">
<zan-tab title="选项一" class="custom-pane">内容一</zan-tab>
<zan-tab title="选项二" class="custom-pane">内容二</zan-tab>
<zan-tab title="选项三" class="custom-pane">内容三</zan-tab>
<zan-tab title="选项四" class="custom-pane">内容四</zan-tab>
<zan-tab title="选项五" class="custom-pane">内容五</zan-tab>
</zan-tabs>
</example-block></section></template>
<style>
.page-tab {
padding: 0 15px;
}
.custom-tabwrap .zan-tab-active{
color: #20a0ff;
}
.custom-tabwrap .zan-tabs-nav-bar{
background: #20a0ff;
}
.custom-tab {
font-weight: bold;
}
.custom-pane {
text-align: center;
height: 50px;
line-height: 50px;
}
</style>
<script>
import Vue from "vue";import ExampleBlock from "../components/example-block";Vue.component("example-block", ExampleBlock);
export default {
methods: {
popalert() {
alert('haha')
}
}
};
</script>

View File

@ -10,9 +10,49 @@
</div>
</div>
</example-block></section></template>
<style>
.waterfall {
max-height: 300px;
overflow: scroll;
}
</style>
<script>
import Vue from "vue";import ExampleBlock from "../components/example-block";Vue.component("example-block", ExampleBlock);</script>
import Vue from "vue";import ExampleBlock from "../components/example-block";Vue.component("example-block", ExampleBlock);
export default {
data() {
return {
list: [1, 2, 3, 4, 5],
loading: false,
finished: false
};
},
methods: {
loadMore() {
if (this.list.length >= 200) {
this.finished = true;
return;
}
this.loading = true;
setTimeout(() => {
let lastNumber = this.list[this.list.length - 1];
for (let i = 0; i < 5; i ++) {
lastNumber += 1;
this.list.push(lastNumber);
}
this.loading = false;
}, 2500);
},
loadMoreUpper() {
if (this.list[0] < 0) return;
this.list.unshift(-1);
}
},
computed: {
isWaterfallDisabled: function() {
return this.loading || this.finished;
}
}
};
</script>

View File

@ -0,0 +1,118 @@
<style>
@component-namespace demo {
@b actionsheet {
.actionsheet-wx {
color: #06BF04;
}
.zan-button {
margin-left: 15px;
}
.title-actionsheet p {
padding: 20px;
}
}
}
</style>
<script>
import MobileComputed from 'components/mobile-computed';
export default {
mixins: [MobileComputed],
data() {
return {
show1: false,
show2: false,
show3: false,
actions1: [
{
name: '微信安全支付',
className: 'actionsheet-wx'
},
{
name: '支付宝支付',
loading: true
},
{
name: '有赞E卡',
subname: '剩余260.50元)'
},
{
name: '信用卡支付'
},
{
name: '其他支付方式'
}
]
};
}
}
</script>
## ActionSheet
### 基础用法
:::demo 基础用法
```html
<div class="zan-row">
<zan-button @click="show1 = true">弹出actionsheet</zan-button>
</div>
<zan-actionsheet v-model="show1" :actions="actions1">
</zan-actionsheet>
```
:::
### 带取消按钮的ActionSheet
:::demo 带取消按钮的ActionSheet
```html
<div class="zan-row">
<zan-button @click="show2 = true">弹出带取消按钮的actionsheet</zan-button>
</div>
<zan-actionsheet v-model="show2" :actions="actions1" cancel-text="取消">
</zan-actionsheet>
```
:::
### 带标题的ActionSheet
:::demo 带标题的ActionSheet
```html
<div class="zan-row">
<zan-button @click="show3 = true">弹出带标题的actionsheet</zan-button>
</div>
<zan-actionsheet v-model="show3" title="支持以下配送方式" class="title-actionsheet">
<p>一些内容</p>
</zan-actionsheet>
```
:::
点击以下按钮查看手机端效果:
<zan-button @click="mobileShow = true">点击查看手机端效果</zan-button>
<mobile-popup v-model="mobileShow" :url="mobileUrl"></mobile-popup>
### API
| 参数 | 说明 | 类型 | 默认值 | 可选值 |
|-----------|-----------|-----------|-------------|-------------|
| actions | 行动按钮数组 | Array | [] | |
| title | 标题 | String | | |
| cancelText | 取消按钮文案 | String | | |
| overlay | 是否显示遮罩 | Boolean | | |
| closeOnClickOverlay | 点击遮罩是否关闭ActionSheet | Boolean | | |
### actions
`API`中的`actions`为一个对象数组,数组中的每一个对象配置每一列,每一列有以下`key`
| key | 说明 |
|-----------|-----------|
| name | 标题 |
| subname | 二级标题 |
| className | 为对应列添加特殊的`class` |
| loading | 是否是loading状态 |

View File

@ -21,15 +21,12 @@
:::demo 高级用法
```html
<zan-card
title="商品名称是什么,两行显示状态如效果图,多余多余多余两行显示状态如效果图,多余多余多余两行显示状态如效果图,多余多余多余两行显示状态如效果图,多余多余多余两行显示状态如效果图,多余多余多余"
desc="商品SKU1商品SKU2"
thumb="https://img.yzcdn.cn/upload_files/2017/02/17/FnDwvwHmU-OiqsbjAO5X7wh1KWrR.jpg!100x100.jpg">
<div class="zan-card__row" slot="title">
<h4 class="zan-card__title">商品名称是什么,两行显示状态如效果图,多余多余多余两行显示状态如效果图,多余多余多余两行显示状态如效果图,多余多余多余两行显示状态如效果图,多余多余多余两行显示状态如效果图,多余多余多余</h4>
<span class="zan-card__price">¥ 2.00</span>
</div>
<div class="zan-card__row" slot="desc">
<h4 class="zan-card__desc">商品sku</h4>
<span class="zan-card__num">x 2</span>
</div>
<div class="zan-card__footer" slot="footer">

View File

@ -1,7 +1,20 @@
<style>
@component-namespace demo {
@b dialog {
.zan-button {
margin: 15px;
}
}
}
</style>
<script>
import { Dialog } from 'src/index';
import MobileComputed from 'components/mobile-computed';
export default {
mixins: [MobileComputed],
methods: {
handleAlertClick() {
Dialog.alert({
@ -66,6 +79,12 @@ export default {
```
:::
点击以下按钮查看手机端效果:
<zan-button @click="mobileShow = true">点击查看手机端效果</zan-button>
<mobile-popup v-model="mobileShow" :url="mobileUrl"></mobile-popup>
### API
| 参数 | 说明 | 类型 | 默认值 | 可选值 |

View File

@ -1,3 +1,13 @@
<script>
export default {
data() {
return {
username: 'zhangmin'
};
}
};
</script>
## Field组件
表单中`input``textarea`的输入框。
@ -9,7 +19,7 @@
:::demo 基础用法
```html
<zan-cell-group>
<zan-field type="text" label="用户名:" placeholder="请输入用户名"></zan-field>
<zan-field type="text" label="用户名:" placeholder="请输入用户名" v-model="username"></zan-field>
<zan-field type="password" label="密码:" placeholder="请输入密码"></zan-field>
<zan-field type="textarea" label="个人介绍:" placeholder="请输入个人介绍"></zan-field>
</zan-cell-group>
@ -28,14 +38,26 @@
```
:::
### 监听change事件
### 禁用的输入框
监听组件的`change`事件
传入`disabled`属性即可
:::demo 监听change事件
:::demo 禁用的输入框
```html
<zan-cell-group>
<zan-field type="text" label="用户名:" placeholder="请输入用户名" @change="handleChange"></zan-field>
<zan-field label="用户名:" type="text" placeholder="请输入用户名" v-model="username" disabled></zan-field>
</zan-cell-group>
```
:::
### 错误的输入框
传入`error`属性即可。
:::demo 错误的输入框
```html
<zan-cell-group>
<zan-field label="用户名:" type="text" placeholder="请输入用户名" error></zan-field>
</zan-cell-group>
```
:::
@ -49,6 +71,7 @@
| value | 输入框的值 | string | '' | |
| label | 输入框标签 | string | '' | |
| disabled | 是否禁用输入框 | boolean | false | |
| error | 输入框是否有错误 | boolean | false | |
| readonly | 输入框是否只读 | boolean | false | |
| maxlength | 输入框maxlength | [String, Number] | '' | |

View File

@ -0,0 +1,43 @@
<style>
@component-namespace demo {
@b icon {
.zan-icon {
margin: 10px;
font-size: 45px;
}
}
}
</style>
## Icon
### 所有Icon
:::demo 所有Icon
```html
<zan-icon name="album"></zan-icon>
<zan-icon name="arrow"></zan-icon>
<zan-icon name="camera"></zan-icon>
<zan-icon name="certificate"></zan-icon>
<zan-icon name="check"></zan-icon>
<zan-icon name="checked"></zan-icon>
<zan-icon name="close"></zan-icon>
<zan-icon name="gift"></zan-icon>
<zan-icon name="home"></zan-icon>
<zan-icon name="location"></zan-icon>
<zan-icon name="message"></zan-icon>
<zan-icon name="send"></zan-icon>
<zan-icon name="shopping-cart"></zan-icon>
<zan-icon name="sign"></zan-icon>
<zan-icon name="store"></zan-icon>
<zan-icon name="topay"></zan-icon>
<zan-icon name="tosend"></zan-icon>
```
:::
### API
| 参数 | 说明 | 类型 | 默认值 | 可选值 |
|-----------|-----------|-----------|-------------|-------------|
| name | icon名称 | string | '' | |

View File

@ -5,6 +5,53 @@ const citys = {
'湖南': ['长沙', '株洲', '湘潭', '衡阳', '邵阳', '岳阳', '常德', '张家界', '益阳', '郴州', '永州', '怀化', '娄底', '湘西土家族苗族自治州']
};
export default {
data() {
return {
pickerColumns: [
{
values: Object.keys(citys),
className: 'column1'
},
{
values: ['杭州', '宁波', '温州', '嘉兴', '湖州', '绍兴', '金华', '衢州', '舟山', '台州', '丽水'],
className: 'column2'
}
]
};
},
methods: {
handlePickerChange(picker, values) {
picker.setColumnValues(1, citys[values[0]]);
},
handlePickerCancel() {
alert('picker cancel');
},
handlePickerConfirm() {
alert('picker confirm');
}
}
};
</script>
## Picker组件
模仿iOS中的`UIPickerView`
### 基础用法
:::demo 基础用法
```html
<zan-picker :columns="pickerColumns" @change="handlePickerChange"></zan-picker>
<script>
const citys = {
'浙江': ['杭州', '宁波', '温州', '嘉兴', '湖州', '绍兴', '金华', '衢州', '舟山', '台州', '丽水'],
'福建': ['福州', '厦门', '莆田', '三明', '泉州', '漳州', '南平', '龙岩', '宁德'],
'湖南': ['长沙', '株洲', '湘潭', '衡阳', '邵阳', '岳阳', '常德', '张家界', '益阳', '郴州', '永州', '怀化', '娄底', '湘西土家族苗族自治州']
};
export default {
data() {
return {
@ -28,16 +75,51 @@ export default {
}
};
</script>
```
:::
## Picker组件
### 带toolbar的Picker
模仿iOS中的`UIPickerView`
### 基础用法
:::demo 基础用法
:::demo 带toolbar的Picker
```html
<zan-picker :columns="pickerColumns" @change="handlePickerChange"></zan-picker>
<zan-picker :columns="pickerColumns" show-toolbar @change="handlePickerChange" @cancel="handlePickerCancel" @confirm="handlePickerConfirm"></zan-picker>
<script>
const citys = {
'浙江': ['杭州', '宁波', '温州', '嘉兴', '湖州', '绍兴', '金华', '衢州', '舟山', '台州', '丽水'],
'福建': ['福州', '厦门', '莆田', '三明', '泉州', '漳州', '南平', '龙岩', '宁德'],
'湖南': ['长沙', '株洲', '湘潭', '衡阳', '邵阳', '岳阳', '常德', '张家界', '益阳', '郴州', '永州', '怀化', '娄底', '湘西土家族苗族自治州']
};
export default {
data() {
return {
pickerColumns: [
{
values: Object.keys(citys),
className: 'column1'
},
{
values: ['杭州', '宁波', '温州', '嘉兴', '湖州', '绍兴', '金华', '衢州', '舟山', '台州', '丽水'],
className: 'column2'
}
]
};
},
methods: {
handlePickerChange(picker, values) {
picker.setColumnValues(1, citys[values[0]]);
},
handlePickerCancel() {
alert('picker cancel');
},
handlePickerConfirm() {
alert('picker confirm');
}
}
};
</script>
```
:::

View File

@ -1,5 +1,44 @@
<style>
@component-namespace demo {
@b popup {
.zan-popup-1 {
width: 100%;
height: 200px;
box-sizing: border-box;
padding: 20px;
}
.zan-popup-2 {
line-height: 50px;
text-align: center;
background-color: rgba(0, 0, 0, 0.701961);
color: #fff;
}
.zan-popup-3 {
width: 100%;
height: 100%;
}
.zan-popup-4 {
width: 60%;
height: 200px;
}
.zan-button {
margin: 15px;
}
}
}
</style>
<script>
import MobileComputed from 'components/mobile-computed';
import Dialog from 'packages/dialog';
export default {
mixins: [MobileComputed],
data() {
return {
popupShow1: false,
@ -17,6 +56,19 @@ export default {
}, 2000);
}
}
},
methods: {
showDialog() {
Dialog.confirm({
title: 'confirm标题',
message: '弹窗提示文字左右始终距离边20PX上下距离20PX文字左对齐。弹窗提示文字左右始终距离边20PX上下距离20PX文字左对齐。'
}).then((action) => {
console.log(action);
}, (error) => {
console.log(error);
});
}
}
};
</script>
@ -28,10 +80,10 @@ export default {
:::demo 基础用法
```html
<div class="zan-row">
<zan-button @click="popupShow1 = true">从下方弹出popup</zan-button>
<zan-button @click="popupShow1 = true;">从下方弹出popup</zan-button>
</div>
<zan-popup v-model="popupShow1" position="bottom" class="zan-popup-1">
xxxx
<zan-button @click="showDialog">弹出dialog</zan-button>
</zan-popup>
<div class="zan-row">
@ -51,8 +103,8 @@ export default {
<div class="zan-row">
<zan-button @click="popupShow4 = true">从中间弹出popup</zan-button>
</div>
<zan-popup v-model="popupShow4" transition="popup-fade" class="zan-popup-4">
一些内容
<zan-popup v-model="popupShow4" class="zan-popup-4">
从中间弹出popup
</zan-popup>
<script>
@ -77,9 +129,15 @@ export default {
}
};
</script>
```
:::
点击以下按钮查看手机端效果:
<zan-button @click="mobileShow = true">点击查看手机端效果</zan-button>
<mobile-popup v-model="mobileShow" :url="mobileUrl"></mobile-popup>
### API
| 参数 | 说明 | 类型 | 默认值 | 可选值 |

View File

@ -0,0 +1,72 @@
<style>
@component-namespace demo {
@b progress {
@e wrapper {
padding: 5px;
margin: 20px 10px;
}
}
}
</style>
## Switch组件
### 基础用法
:::demo 基础用法
```html
<div class="demo-progress__wrapper">
<zan-progress class="demo-progress__demo1" :percentage="0"></zan-progress>
</div>
<div class="demo-progress__wrapper">
<zan-progress class="demo-progress__demo2" :percentage="46"></zan-progress>
</div>
<div class="demo-progress__wrapper">
<zan-progress class="demo-progress__demo1" :percentage="100"></zan-progress>
</div>
```
:::
### Inactive
:::demo Inactive
```html
<div class="demo-progress__wrapper">
<zan-progress class="demo-progress__demo1" :inactive="true" :percentage="0"></zan-progress>
</div>
<div class="demo-progress__wrapper">
<zan-progress class="demo-progress__demo2" :inactive="true" :percentage="46"></zan-progress>
</div>
<div class="demo-progress__wrapper">
<zan-progress class="demo-progress__demo1" :inactive="true" :percentage="100"></zan-progress>
```
:::
### 自定义颜色和文字
:::demo 自定义颜色
```html
</div>
<div class="demo-progress__wrapper">
<zan-progress class="demo-progress__demo1" pivot-text="红色" color="#ed5050" :percentage="26"></zan-progress>
</div>
<div class="demo-progress__wrapper">
<zan-progress class="demo-progress__demo1" pivot-text="橙色" color="#f60" :percentage="46"></zan-progress>
</div>
<div class="demo-progress__wrapper">
<zan-progress class="demo-progress__demo1" pivot-text="黄色" color="#f09000" :percentage="66"></zan-progress>
</div>
```
:::
### API
| 参数 | 说明 | 类型 | 默认值 | 可选值 |
|-----------|-----------|-----------|-------------|-------------|
| inactive | 是否只会 | boolean | false | true, false |
| percentage | 进度百分比 | number | false | 0-100 |
| pivotText | 文字显示 | string | 百分比文字 | - |
| color | 进度条颜色 | string | #38f | hexvalue |
| textColor | 进度条文字颜色 | string | #fff | hexvalue |

View File

@ -0,0 +1,65 @@
<style>
@component-namespace demo {
@b quantity {
.zan-quantity {
margin: 15px;
}
.curr-quantity {
margin: 15px;
}
}
}
</style>
<script>
export default {
data() {
return {
quantity1: 1,
quantity2: null,
};
}
};
</script>
## Quantity
### 基础用法
:::demo 基础用法
```html
<zan-quantity v-model="quantity1"></zan-quantity>
<p class="curr-quantity">当前值:{{ quantity1 }}</p>
```
:::
### 禁用Quantity
:::demo 禁用Quantity
```html
<zan-quantity v-model="quantity1" disabled></zan-quantity>
```
:::
### 高级用法
默认是每次加减为1可以对组件设置`step``min``max``defaultValue`属性。
:::demo 高级用法
```html
<zan-quantity v-model="quantity2" min="5" max="40" step="2" default-value="9"></zan-quantity>
<p class="curr-quantity">当前值:{{ quantity2 }}</p>
```
:::
### API
| 参数 | 说明 | 类型 | 默认值 | 可选值 |
|-----------|-----------|-----------|-------------|-------------|
| min | 最小值 | string/number | 1 | '' |
| max | 最大值 | string/number | '' | '' |
| step | 步数 | string/number | 1 | '' |
| disabled | 是否被禁用了 | boolean | false | '' |
| defaultValue | 默认值 | string/number | 1 | '' |

126
docs/examples-docs/tab.md Normal file
View File

@ -0,0 +1,126 @@
## Tab 组件
### 基础用法
:::demo 基础用法
```html
<zan-tabs>
<zan-tab title="选项一">内容一</zan-tab>
<zan-tab title="选项二">内容二</zan-tab>
<zan-tab title="选项三">内容三</zan-tab>
<zan-tab title="选项四">内容四</zan-tab>
<zan-tab title="选项五">内容五</zan-tab>
</zan-tabs>
```
<script>
export default {
methods: {
popalert() {
alert('haha')
}
}
};
</script>
:::
### 禁用用法
:::demo 禁用用法
```html
<zan-tabs>
<zan-tab title="选项一">内容一</zan-tab>
<zan-tab disable title="选项二" @disable="popalert">内容二</zan-tab>
<zan-tab title="选项三">内容三</zan-tab>
<zan-tab title="选项四">内容四</zan-tab>
<zan-tab title="选项五">内容五</zan-tab>
</zan-tabs>
<script>
export default {
methods: {
popalert() {
alert('haha')
}
}
};
</script>
```
:::
### card样式用法
:::demo card样式用法
```html
<zan-tabs type="card">
<zan-tab title="选项一">内容一</zan-tab>
<zan-tab title="选项二">内容二</zan-tab>
<zan-tab title="选项三">内容三</zan-tab>
<zan-tab title="选项四">内容四</zan-tab>
<zan-tab title="选项五">内容五</zan-tab>
</zan-tabs>
```
:::
<style>
.page-tab {
padding: 0 15px;
}
.custom-tabwrap .zan-tab-active{
color: #20a0ff;
}
.custom-tabwrap .zan-tabs-nav-bar{
background: #20a0ff;
}
.custom-tab {
font-weight: bold;
}
.custom-pane {
text-align: center;
height: 50px;
line-height: 50px;
}
</style>
### 自定义样式用法
:::demo 自定义样式用法
```html
<zan-tabs active="2" navclass="custom-tabwrap">
<zan-tab title="选项一" class="custom-pane">内容一</zan-tab>
<zan-tab title="选项二" class="custom-pane">内容二</zan-tab>
<zan-tab title="选项三" class="custom-pane">内容三</zan-tab>
<zan-tab title="选项四" class="custom-pane">内容四</zan-tab>
<zan-tab title="选项五" class="custom-pane">内容五</zan-tab>
</zan-tabs>
<style>
.page-tab {
padding: 0 15px;
}
.custom-tabwrap .zan-tab-active{
color: #20a0ff;
}
.custom-tabwrap .zan-tabs-nav-bar{
background: #20a0ff;
}
.custom-tab {
font-weight: bold;
}
.custom-pane {
text-align: center;
height: 50px;
line-height: 50px;
}
</style>
```
:::
### zan-tabs API
| 参数 | 说明 | 类型 | 默认值 | 可选 |
|-----------|-----------|-----------|-------------|-------------|
| classtype | 两种UI | string | line | card |
| active | 默认激活的tab | string || number | 0 | |
| navclass | tabs的内部nav上的自定义classname | string | '' | |
### zan-tab API
| 参数 | 说明 | 类型 | 默认值 | 必须 |
|-----------|-----------|-----------|-------------|-------------|
| title | tab的标题 | string | '' | required |
| disable | 是否禁用这个tab | Boolean | false | |

View File

@ -2,28 +2,6 @@
### 基础用法
:::demo 基础用法
```html
<div class="waterfall">
<div
v-waterfall-lower="loadMore"
v-waterfall-upper="loadMoreUpper"
waterfall-disabled="isWaterfallDisabled"
waterfall-offset="400"
>
<div
class="waterfall-item"
v-for="item in list"
style="text-align: center;"
>
{{ item }}
</div>
<div v-if="loading" style="text-align: center;">
loading
</div>
</div>
</div>
<script>
export default {
data() {
@ -62,6 +40,35 @@ export default {
}
};
</script>
<style>
.waterfall {
max-height: 300px;
overflow: scroll;
}
</style>
:::demo 基础用法
```html
<div class="waterfall">
<div
v-waterfall-lower="loadMore"
v-waterfall-upper="loadMoreUpper"
waterfall-disabled="isWaterfallDisabled"
waterfall-offset="400"
>
<div
class="waterfall-item"
v-for="item in list"
style="text-align: center;"
>
{{ item }}
</div>
<div v-if="loading" style="text-align: center;">
loading
</div>
</div>
</div>
```
:::
@ -69,6 +76,6 @@ export default {
| 参数 | 说明 | 类型 | 默认值 | 可选值 |
|-----------|-----------|-----------|-------------|-------------|
| waterfall-disabled | 是否禁止瀑布流触发 | Boolean | false | |
| waterfall-disabled | 在vue对象中表示是否禁止瀑布流触发的key值 | String | - | |
| waterfall-offset | 触发瀑布流加载的阈值 | Number | 300 | |

View File

@ -9,6 +9,12 @@ import ZanUI from 'src/index.js';
import 'packages/zanui-css/src/index.css';
function isMobile() {
var platform = navigator.userAgent.toLowerCase();
return (/(android|bb\d+|meego).+mobile|kdtunion|weibo|m2oapp|micromessenger|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i).test(platform) ||
(/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i).test(platform.substr(0, 4));
}
Vue.use(VueRouter);
Vue.use(ZanUI);
Vue.component('side-nav', SideNav);
@ -31,6 +37,10 @@ router.beforeEach((route, redirect, next) => {
if (route.path !== '/') {
indexScrollTop = document.body.scrollTop;
}
if (isMobile()) {
window.location.replace(location.pathname + 'examples.html#' + route.path);
return;
}
document.title = route.meta.title || document.title;
next();
});

View File

@ -27,6 +27,10 @@
"path": "/button",
"title": "Button"
},
{
"path": "/icon",
"title": "Icon"
},
{
"path": "/cell",
"title": "Cell"
@ -89,6 +93,10 @@
{
"groupName": "JS组件",
"list": [
{
"path": "/actionsheet",
"title": "ActionSheet"
},
{
"path": "/tab",
"title": "Tab"
@ -125,6 +133,10 @@
"path": "/swipe",
"title": "Swipe"
},
{
"path": "/quantity",
"title": "Quantity"
},
{
"path": "/waterfall",
"title": "Waterfall"

View File

@ -1,6 +1,6 @@
{
"name": "@youzan/zanui-vue",
"version": "0.0.15",
"version": "0.0.30",
"description": "有赞vue wap组件库",
"main": "lib/zanui.js",
"style": "lib/zanui-css/index.css",
@ -24,7 +24,8 @@
"lint": "eslint src/**/*.js packages/**/*.{js,vue} --quiet",
"test": "karma start test/unit/karma.conf.js --single-run; npm run coverage",
"test:watch": "karma start test/unit/karma.conf.js",
"coverage": "find test/unit/coverage/lcov-report -name 'index.html' | sed -n 1,1p | xargs -I {} open {} "
"coverage": "find test/unit/coverage/lcov-report -name 'index.html' | sed -n 1,1p | xargs -I {} open {} ",
"deploy": "sh build/release.sh"
},
"repository": {
"type": "git",
@ -41,7 +42,7 @@
"raf.js": "0.0.4"
},
"peerDependencies": {
"vue": "^2.1.8"
"vue": "2.1.8"
},
"devDependencies": {
"2webpack2": "^1.2.1",
@ -129,14 +130,14 @@
"transliteration": "^1.1.11",
"uppercamelcase": "^1.1.0",
"url-loader": "^0.5.7",
"vue": "^2.1.8",
"vue": "2.1.8",
"vue-hot-reload-api": "^1.3.3",
"vue-html-loader": "^1.2.3",
"vue-loader": "^10.0.2",
"vue-loader": "^10.3.0",
"vue-markdown-loader": "^0.6.1",
"vue-router": "^2.0.0",
"vue-style-loader": "^1.0.0",
"vue-template-compiler": "^2.1.8",
"vue-template-compiler": "2.1.8",
"vue-template-es2015-compiler": "^1.4.2",
"webpack": "^2.2.1",
"webpack-dev-server": "^1.16.0",

View File

@ -1,28 +1,54 @@
<template>
<transition name="actionsheet-float">
<div class="zan-actionsheet" v-show="currentValue">
<div class="zan-actionsheet-header" v-if="title">
<div class="zan-actionsheet" :class="[ title ? 'zan-actionsheet--withtitle' : '' ]" v-show="currentValue">
<div class="zan-actionsheet__header" v-if="title">
<h3 v-text="title"></h3>
<zan-icon name="close" @click.stop="currentValue = false"></zan-icon>
</div>
<slot>
<ul class="zan-actionsheet-list">
<li v-for="item in actions" class="zan-actionsheet-item" :class="item.className" @click.stop="handleItemClick(item)">{{ item.name }}</li>
<template v-if="!title">
<ul class="zan-actionsheet__list">
<li
v-for="item in actions"
class="zan-actionsheet__item"
:class="[item.className, item.loading ? 'zan-actionsheet__item--loading' : '']"
@click.stop="handleItemClick(item)">
<template v-if="!item.loading">
<span class="zan-actionsheet__name">{{ item.name }}</span>
<span class="zan-actionsheet__subname" v-if="item.subname">{{ item.subname }}</span>
</template>
<template v-else>
<zan-loading class="zan-actionsheet__loading" type="circle" color="black"></zan-loading>
</template>
</li>
</ul>
<a class="zan-actionsheet-button" @click.stop="currentValue = false" v-if="cancelText">{{ cancelText }}</a>
</slot>
<a class="zan-actionsheet__button" @click.stop="currentValue = false" v-if="cancelText">{{ cancelText }}</a>
</template>
<template v-else>
<div class="zan-actionsheet__content">
<slot></slot>
</div>
</template>
</div>
</transition>
</template>
<script>
import Popup from 'src/mixins/popup';
import ZanLoading from 'packages/loading';
import ZanIcon from 'packages/icon';
export default {
name: 'zan-actionsheet',
mixins: [Popup],
components: {
ZanLoading,
ZanIcon
},
props: {
value: {},
actions: {
type: Array,
default: () => []
@ -40,7 +66,7 @@ export default {
data() {
return {
currentValue: false
currentValue: this.value
};
},

View File

@ -7,7 +7,7 @@
<h4 v-text="title" class="zan-card__title"></h4>
</slot>
<slot name="desc">
<p v-if="desc" v-text="desc" class="zan-card__title"></p>
<p v-if="desc" v-text="desc" class="zan-card__desc"></p>
</slot>
<slot name="tags"></slot>
</div>

View File

@ -6,6 +6,7 @@
}">
<span class="zan-checkbox__input">
<input
ref="input"
v-model="currentValue"
type="checkbox"
class="zan-checkbox__control"
@ -16,7 +17,7 @@
}">
</span>
</span>
<span class="zan-checkbox__label">
<span class="zan-checkbox__label" @click="handleLabelClick">
<slot></slot>
</span>
</div>
@ -92,6 +93,15 @@ export default {
? this.parentGroup.disabled || this.disabled
: this.disabled;
}
},
methods: {
handleLabelClick() {
if (this.isDisabled) {
return;
}
this.currentValue = !this.currentValue;
}
}
};
</script>

View File

@ -3,14 +3,15 @@
class="zan-field"
:title="label"
:class="{
'is-textarea': type === 'textarea',
'is-nolabel': !label
'zan-field--hastextarea': type === 'textarea',
'zan-field--nolabel': !label,
'zan-field--disabled': disabled,
'zan-field--error': error
}">
<textarea
v-if="type === 'textarea'"
class="zan-field__control"
v-model="currentValue"
@change="$emit('change', currentValue)"
:placeholder="placeholder"
:maxlength="maxlength"
:disabled="disabled"
@ -20,7 +21,6 @@
v-else
class="zan-field__control"
:value="currentValue"
@change="$emit('change', currentValue)"
@input="handleInput"
:type="type"
:placeholder="placeholder"
@ -46,9 +46,10 @@ export default {
default: 'text'
},
placeholder: String,
value: String,
value: {},
label: String,
disabled: Boolean,
error: Boolean,
readonly: Boolean,
maxlength: [String, Number]
},
@ -66,7 +67,6 @@ export default {
currentValue(val) {
this.$emit('input', val);
console.log(val);
}
},

View File

@ -1,5 +1,5 @@
<template>
<i class="zanui-icon" :class="'zan-icon-' + name"></i>
<i class="zan-icon" :class="'zan-icon-' + name" @click="handleIconClick"></i>
</template>
<script>
@ -8,6 +8,12 @@
props: {
name: String
},
methods: {
handleIconClick(event) {
this.$emit('click', event);
}
}
};
</script>

View File

@ -0,0 +1,8 @@
## 0.0.2 (2017-01-20)
* 改了bug A
* 加了功能B
## 0.0.1 (2017-01-10)
* 第一版

View File

@ -0,0 +1,26 @@
# @youzan/<%= name %>
!!! 请在此处填写你的文档最简单描述 !!!
[![version][version-image]][download-url]
[![download][download-image]][download-url]
[version-image]: http://npm.qima-inc.com/badge/v/@youzan/<%= name %>.svg?style=flat-square
[download-image]: http://npm.qima-inc.com/badge/d/@youzan/<%= name %>.svg?style=flat-square
[download-url]: http://npm.qima-inc.com/package/@youzan/<%= name %>
## Demo
## Usage
## API
| 参数 | 说明 | 类型 | 默认值 | 可选值 |
|-----------|-----------|-----------|-------------|-------------|
| className | 自定义额外类名 | string | '' | '' |
## License
[MIT](https://opensource.org/licenses/MIT)

View File

@ -0,0 +1,79 @@
export default {
install: function(Vue, options) {
options = options || { fade: false, nohori: false };
// scroll结束的时候触发scrollend事件
var timer = null;
var topValue = 0;
var bodyEle = document.body;
var scrollEnd = document.createEvent('HTMLEvents');
scrollEnd.initEvent('scrollEnd', true, false);
function enterFrame() {
if (bodyEle.scrollTop === topValue) {
window.cancelAnimationFrame(timer);
window.dispatchEvent(scrollEnd);
} else {
topValue = bodyEle.scrollTop;
}
window.requestAnimationFrame(enterFrame);
}
document.addEventListener('scroll', function() {
if (!timer) {
timer = window.requestAnimationFrame(enterFrame);
}
}, true);
// vue指令
function update(value) {
if (!value) {
return;
}
var isFadeIn = this.modifiers.fade || options.fade;
var isNoHori = this.modifiers.nohori || options.nohori;
// 用css3来控制过渡效果
if (isFadeIn) {
this.el.style.opacity = 0;
this.el.style.transition = 'opacity .3s';
this.el.style.webkitTransition = 'opacity .3s';
}
var compute = function() {
if (this.el === null) {
return;
}
var rect = this.el.getBoundingClientRect();
var vpWidth = document.head.parentNode.clientWidth;
var vpHeight = document.head.parentNode.clientHeight;
var loadImg = function() {
this.el.src = value;
this.el.addEventListener('load', onloadEnd);
window.removeEventListener('scrollEnd', compute, true);
window.removeEventListener('resize', compute, true);
}.bind(this);
if (this.el.src === value) return;
if (isNoHori) {
if (rect.bottom >= 0 && rect.top <= vpHeight) {
loadImg();
}
} else if (rect.bottom >= 0 && rect.top <= vpHeight && rect.right >= 0 && rect.left <= vpWidth) {
loadImg();
}
}.bind(this);
var onload = function() {
compute();
this.el && this.el.removeEventListener('load', onload);
window.addEventListener('scrollEnd', compute, true);
window.addEventListener('resize', compute, true);
}.bind(this);
var onloadEnd = function() {
if (this.el === null) {
return;
}
if (isFadeIn) {
this.el.style.opacity = 1;
}
this.el.removeEventListener('load', onloadEnd);
}.bind(this);
// 元素load触发事件
this.el.addEventListener('load', onload);
}
Vue.directive('lazyload', update);
}
};

View File

@ -0,0 +1,10 @@
{
"name": "<%= name %>",
"version": "<%= version %>",
"description": "<%= description %>",
"main": "./lib/index.js",
"author": "<%= author %>",
"license": "<%= license %>",
"devDependencies": {},
"dependencies": {}
}

View File

@ -6,7 +6,7 @@
class="zan-picker-column__item"
:class="{ 'zan-picker-column__item--selected': item === currentValue }"
:style="{ height: itemHeight + 'px', lineHeight: itemHeight + 'px' }">
{{item}}
{{ typeof item === 'object' && item[valueKey] ? item[valueKey] : item }}
</div>
</div>
</div>
@ -52,7 +52,8 @@ export default {
type: Number,
default: DEFAULT_ITEM_HEIGHT
},
value: {}
value: {},
valueKey: String
},
data() {

View File

@ -1,7 +1,9 @@
<template>
<div class="zan-picker">
<div class="zan-picker__toolbar">
<div class="zan-picker__toolbar" v-show="showToolbar">
<slot>
<a href="javascript:void(0)" class="zan-picker__cancel" @click="handlePickerCancel">取消</a>
<a href="javascript:void(0)" class="zan-picker__confirm" @click="handlePickerConfirm">完成</a>
</slot>
</div>
<div class="zan-picker__columns" :class="['zan-picker__columns--' + columns.length]">
@ -12,7 +14,8 @@
:class-name="item.className"
:itemHeight="itemHeight"
:visible-item-count="visibleItemCount"
@change="columnValueChange">
:value-key="valueKey"
@change="columnValueChange(index)">
</picker-column>
<div class="zan-picker-center-highlight" :style="{ height: itemHeight + 'px', marginTop: -itemHeight / 2 + 'px' }"></div>
</div>
@ -60,8 +63,9 @@ export default {
*/
showToolbar: {
type: Boolean,
default: true
}
default: false
},
valueKey: String
},
computed: {
@ -78,11 +82,17 @@ export default {
},
methods: {
handlePickerCancel() {
this.$emit('cancel', this.values);
},
handlePickerConfirm() {
this.$emit('confirm', this.values);
},
/**
* 处理列`change`事件
*/
columnValueChange() {
this.$emit('change', this, this.values);
columnValueChange(index) {
this.$emit('change', this, this.values, index);
},
/**

View File

@ -0,0 +1,26 @@
# @youzan/<%= name %>
!!! 请在此处填写你的文档最简单描述 !!!
[![version][version-image]][download-url]
[![download][download-image]][download-url]
[version-image]: http://npm.qima-inc.com/badge/v/@youzan/<%= name %>.svg?style=flat-square
[download-image]: http://npm.qima-inc.com/badge/d/@youzan/<%= name %>.svg?style=flat-square
[download-url]: http://npm.qima-inc.com/package/@youzan/<%= name %>
## Demo
## Usage
## API
| 参数 | 说明 | 类型 | 默认值 | 可选值 |
|-----------|-----------|-----------|-------------|-------------|
| className | 自定义额外类名 | string | '' | '' |
## License
[MIT](https://opensource.org/licenses/MIT)

View File

@ -0,0 +1,3 @@
import Progress from './src/progress';
export default Progress;

View File

@ -0,0 +1,10 @@
{
"name": "@youzan/zan-progress",
"version": "0.0.1",
"description": "progress component",
"main": "./index.js",
"author": "jiangruowei",
"license": "MIT",
"devDependencies": {},
"dependencies": {}
}

View File

@ -0,0 +1,84 @@
<template>
<div class="zan-progress">
<div class="zan-progress__bar">
<span class="zan-progress__bar__finished-portion" :style="{backgroundColor: componentColor, width: percentage + '%'}"></span>
<span class="zan-progress__bar__pivot" :style="pivotStyle">
{{pivotText}}
</span>
</div>
</div>
</template>
<script>
/**
* zan-progress
* @module components/progress
* @desc 开关
* @param {boolean} [inactive=false] - 是否置灰
* @param {number} [percentage=0] - 进度百分比
* @param {string} [pivotText=percentage] - 进度条显示文字
* @param {string} [color='#38f'] - 进度条颜色
* @param {string} [textColor='#fff'] - 进度条文字颜色
*
* @example
* <zan-switch checked="true" disabled="false"></zan-switch>
*/
export default {
name: 'zan-progress',
props: {
percentage: {
type: Number,
default: 0,
validate(value) {
return value <= 100 && value >= 0;
}
},
inactive: {
type: Boolean,
default: false
},
pivotText: {
type: String,
default: function() {
return this.percentage.toString() + '%';
}
},
color: {
type: String,
default: '#38f'
},
textColor: {
type: String,
default: '#fff'
}
},
computed: {
componentColor() {
return this.inactive ? '#cacaca' : this.color;
},
pivotStyle() {
const pivotStyle = {
backgroundColor: this.componentColor,
color: this.textColor,
left: this.percentage + '%',
marginLeft: '-14px'
};
console.log(this.percentage);
if (this.percentage <= 5) {
pivotStyle.left = '0%';
pivotStyle.marginLeft = '0';
} else if (this.percentage >= 95) {
pivotStyle.left = '100%';
pivotStyle.marginLeft = '-28px';
} else {
pivotStyle.left = this.percentage + '%';
pivotStyle.marginLeft = '-14px';
}
return pivotStyle;
}
}
};
</script>

View File

@ -0,0 +1,8 @@
## 0.0.2 (2017-01-20)
* 改了bug A
* 加了功能B
## 0.0.1 (2017-01-10)
* 第一版

View File

@ -0,0 +1,26 @@
# @youzan/<%= name %>
!!! 请在此处填写你的文档最简单描述 !!!
[![version][version-image]][download-url]
[![download][download-image]][download-url]
[version-image]: http://npm.qima-inc.com/badge/v/@youzan/<%= name %>.svg?style=flat-square
[download-image]: http://npm.qima-inc.com/badge/d/@youzan/<%= name %>.svg?style=flat-square
[download-url]: http://npm.qima-inc.com/package/@youzan/<%= name %>
## Demo
## Usage
## API
| 参数 | 说明 | 类型 | 默认值 | 可选值 |
|-----------|-----------|-----------|-------------|-------------|
| className | 自定义额外类名 | string | '' | '' |
## License
[MIT](https://opensource.org/licenses/MIT)

View File

@ -0,0 +1,3 @@
import Quantity from './src/quantity';
export default Quantity;

View File

@ -0,0 +1,10 @@
{
"name": "<%= name %>",
"version": "<%= version %>",
"description": "<%= description %>",
"main": "./lib/index.js",
"author": "<%= author %>",
"license": "<%= license %>",
"devDependencies": {},
"dependencies": {}
}

View File

@ -0,0 +1,104 @@
<template>
<div class="zan-quantity">
<button
@click="handleChange('minus')"
class="zan-quantity__stepper zan-quantity__minus"
:class="{
'zan-quantity__minus--disabled': isMinusDisabled
}">
</button>
<input type="text" class="zan-quantity__input" :value="currentValue" @input="handleInputChange" :disabled="disabled">
<button
@click="handleChange('plus')"
class="zan-quantity__stepper zan-quantity__plus"
:class="{
'zan-quantity__plus--disabled': isPlusDisabled
}">
</button>
</div>
</template>
<script>
export default {
name: 'zan-quantity',
props: {
min: {
type: [String, Number],
default: 1
},
max: {
type: [String, Number],
default: Infinity
},
value: {},
step: {
type: [String, Number],
default: 1
},
disabled: Boolean,
defaultValue: {
type: [String, Number],
default: 1
}
},
data() {
return {
currentValue: this.value ? +this.value : +this.defaultValue
};
},
computed: {
isMinusDisabled() {
const min = +this.min;
const step = +this.step;
const currentValue = +this.currentValue;
return min === currentValue || (currentValue - step) < min || this.disabled;
},
isPlusDisabled() {
const max = +this.max;
const step = +this.step;
const currentValue = +this.currentValue;
return max === currentValue || (currentValue + step) > max || this.disabled;
}
},
watch: {
currentValue(val) {
this.$emit('input', +val);
},
value(val) {
if (val) {
this.currentValue = +val;
}
}
},
methods: {
handleInputChange(event) {
let val = +event.target.value;
const max = +this.max;
const min = +this.min;
if (val > max) {
val = max;
} else if (val < min) {
val = min;
}
this.currentValue = val;
},
handleChange(type) {
if ((this.isMinusDisabled && type === 'minus') || (this.isPlusDisabled && type === 'plus')) {
return;
}
const step = +this.step;
const currentValue = +this.currentValue;
this.currentValue = type === 'minus' ? (currentValue - step) : (currentValue + step);
this.$emit('change', this.currentValue);
}
}
};
</script>

View File

@ -0,0 +1,8 @@
## 0.0.2 (2017-01-20)
* 改了bug A
* 加了功能B
## 0.0.1 (2017-01-10)
* 第一版

26
packages/tab/README.md Normal file
View File

@ -0,0 +1,26 @@
# @youzan/<%= name %>
!!! 请在此处填写你的文档最简单描述 !!!
[![version][version-image]][download-url]
[![download][download-image]][download-url]
[version-image]: http://npm.qima-inc.com/badge/v/@youzan/<%= name %>.svg?style=flat-square
[download-image]: http://npm.qima-inc.com/badge/d/@youzan/<%= name %>.svg?style=flat-square
[download-url]: http://npm.qima-inc.com/package/@youzan/<%= name %>
## Demo
## Usage
## API
| 参数 | 说明 | 类型 | 默认值 | 可选值 |
|-----------|-----------|-----------|-------------|-------------|
| className | 自定义额外类名 | string | '' | '' |
## License
[MIT](https://opensource.org/licenses/MIT)

2
packages/tab/index.js Normal file
View File

@ -0,0 +1,2 @@
import Tab from './src/tab';
export default Tab;

10
packages/tab/package.json Normal file
View File

@ -0,0 +1,10 @@
{
"name": "<%= name %>",
"version": "<%= version %>",
"description": "<%= description %>",
"main": "./lib/index.js",
"author": "<%= author %>",
"license": "<%= license %>",
"devDependencies": {},
"dependencies": {}
}

27
packages/tab/src/tab.vue Normal file
View File

@ -0,0 +1,27 @@
<template>
<div class="zan-tabs-pane" :class="classNames">
<slot></slot>
</div>
</template>
<script>
export default {
name: 'zan-tab',
props: {
//
title: {
type: String,
required: true
},
disable: Boolean
},
computed: {
classNames() {
return { 'is-select': this.$parent.tabs.indexOf(this) === this.$parent.switchActiveTabKey };
}
},
created() {
this.$parent.tabs.push(this);
}
};
</script>

79
packages/tab/src/tabs.vue Normal file
View File

@ -0,0 +1,79 @@
<template>
<div class="zan-tabs">
<div class="zan-tabs-nav" :class="classNames">
<div class="zan-tabs-nav-bar" :style="navBarStyle"></div>
<div
v-for="(tab, index) in tabs"
class="zan-tab"
:class="{'zan-tab-active': index == switchActiveTabKey}"
ref="tabkey"
@click="handleTabClick(index,tab)"
>
{{ tab.title }}
</div>
</div>
<div class="zan-tabs-content"><slot></slot></div>
</div>
</template>
<script>
export default {
name: 'zan-tabs',
props: {
// tab
active: {
type: [Number, String],
default: 0
},
// linecard
type: {
type: String,
default: 'line'
},
// navwrap
navclass: {
type: String,
default: ''
}
},
data() {
return {
tabs: [],
isReady: false,
switchActiveTabKey: this.active
};
},
computed: {
classNames() {
return [`zan-tabs-${this.type}`, this.navclass];
},
navBarStyle() {
if (!this.isReady) return;
const tabKey = this.switchActiveTabKey;
const elem = this.$refs.tabkey[tabKey];
const offsetWidth = `${elem.offsetWidth || 0}px`;
const offsetLeft = `${elem.offsetLeft || 0}px`;
return {
width: offsetWidth,
transform: `translate3d(${offsetLeft}, 0px, 0px)`
};
}
},
methods: {
handleTabClick(index, el) {
if (el.disable) {
el.$emit('disable');
return;
}
this.switchActiveTabKey = index;
}
},
mounted() {
//
this.$nextTick(() => {
// computednav-barcss
this.isReady = true;
});
}
};
</script>

3
packages/tabs/index.js Normal file
View File

@ -0,0 +1,3 @@
import Tabs from '../tab/src/tabs';
export default Tabs;

View File

@ -14,6 +14,7 @@ function doBindEvent() {
if (disabledExpr) {
this.vm.$watch(disabledExpr, (value) => {
this.disabled = value;
this.scrollEventListener();
});
disabled = Boolean(this.vm[disabledExpr]);
}

View File

@ -1,6 +1,6 @@
{
"name": "@youzan/zanui-css",
"version": "0.0.15",
"version": "0.0.30",
"description": "zanui css.",
"main": "lib/index.css",
"style": "lib/index.css",

View File

@ -1,9 +1,81 @@
@import './common/var.css';
@import './mixins/border_retina.css';
@component-namespace zan {
@b actionsheet {
position: fixed;
width: 100%;
top: auto;
bottom: 0;
right: auto;
left: 50%;
transform: translate3d(-50%, 0, 0);
backface-visibility: hidden;
transition: .2s ease-out;
background-color: #e0e0e0;
@m withtitle {
background-color: $c-white;
}
@e item {
line-height: 50px;
text-align: center;
color: $c-black;
font-size: 16px;
position: relative;
background-color: $c-white;
@m loading {
padding: 10px 0;
}
&::after {
@mixin border-retina (top);
}
}
@e subname {
color: $c-gray-darker;
font-size: 12px;
}
@e loading {
margin: 0 auto;
}
@e button {
display: block;
margin-top: 5px;
line-height: 50px;
color: $c-black;
font-size: 16px;
text-align: center;
background-color: $c-white;
}
@e header {
line-height: 44px;
color: $c-black;
text-align: center;
position: relative;
&::after {
@mixin border-retina (top, bottom);
}
.zan-icon-close {
position: absolute;
font-size: 22px;
line-height: 22px;
top: 11px;
right: 15px;
}
}
}
}
.actionsheet-float-bottom-enter,
.actionsheet-float-bottom-leave-active {
.actionsheet-float-enter,
.actionsheet-float-leave-active {
transform: translate3d(-50%, 100%, 0);
}

View File

@ -2,7 +2,8 @@
@component-namespace zan {
@b card {
padding: 5px 15px;
padding: 5px 15px 5px 115px;
height: 90px;
background: #FAFAFA;
overflow: hidden;
position: relative;
@ -13,15 +14,17 @@
}
@e img {
float: left;
width: 90px;
height: 90px;
border: 0;
position: absolute;
top: 5px;
left: 15px;
}
@e content {
margin-left: 100px;
display: table;
width: 100%;
@when center {
display: table;
@ -45,6 +48,7 @@
color: #333;
max-height: 40px;
margin-bottom: 5px;
word-break: break-all;
@mixin multi-ellipsis 2;
}
@ -52,6 +56,7 @@
font-size: 12px;
color: #666;
max-height: 20px;
word-break: break-all;
@mixin multi-ellipsis 1;
}

View File

@ -6,13 +6,13 @@
width: 100%;
overflow: hidden;
@when textarea {
@m hastextarea {
.zan-field__control {
min-height: 60px;
}
}
@when nolabel {
@m nolabel {
.zan-cell__title {
display: none;
}
@ -23,6 +23,19 @@
}
}
@m disabled {
.zan-field__control {
color: $c-gray-dark;
}
}
@m error {
.zan-field__control,
.zan-cell__title {
color: $c-red;
}
}
.zan-cell__title,
.zan-cell__value {
float: none;

View File

@ -18,7 +18,10 @@
@import './steps.css';
@import './tag.css';
@import './checkbox.css';
@import './tab.css';
@import './col.css';
@import './row.css';
@import './image_preview.css';
@import './actionsheet.css';
@import './quantity.css';
@import './progress.css';

View File

@ -1,9 +1,29 @@
@import "./mixins/border_retina.css";
@component-namespace zan {
@b picker {
overflow: hidden;
@e toolbar {
height: 40px;
line-height: 40px;
overflow: hidden;
padding: 0 15px;
position: relative;
&::after {
@mixin border-retina (top, bottom);
}
}
@e cancel {
color: #3388FF;
float: left;
}
@e confirm {
color: #3388FF;
float: right;
}
@e columns {

View File

@ -6,6 +6,7 @@
top: 0;
left: 0;
background-color: rgba(0, 0, 0, 0.701961);
transition: background-color .5s ease-out;
}
@b popup {
@ -18,6 +19,7 @@
transition: .2s ease-out;
@m top {
width: 100%;
top: 0;
right: auto;
bottom: auto;
@ -34,6 +36,7 @@
}
@m bottom {
width: 100%;
top: auto;
bottom: 0;
right: auto;

View File

@ -0,0 +1,33 @@
@import './common/var.css';
@component-namespace zan {
@b progress {
@e bar {
height: 4px;
border-radius: 4.5px;
width: 100%;
background: $c-gray-light;
position: relative;
@e finished-portion {
border-radius: 4.5px;
height: 100%;
position: absolute;
left: 0;
display: inline-block;
}
@e pivot {
padding: 2px 0;
font-size: 8px;
position: absolute;
border-radius: 6px;
width: 28px;
background-color: $c-gray-light;
line-height: 8px;
text-align: center;
top: 50%;
transform: translate3d(0, -50%, 0);
}
}
}
}

View File

@ -0,0 +1,77 @@
@import './common/var.css';
@component-namespace zan {
@b quantity {
font-size: 0;
@e stepper {
width: 40px;
height: 30px;
box-sizing: border-box;
background-color: $c-white;
border: 1px solid $c-gray-dark;
position: relative;
outline: 0;
padding: 5px;
vertical-align: middle;
&::before {
width: 9px;
height: 1px;
}
&::after {
width: 1px;
height: 9px;
}
&::before,
&::after {
content: '';
position: absolute;
margin: auto;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #6c6c6c;
}
}
@e minus {
border-radius: 2px 0 0 2px;
&::after {
display: none;
}
@m disabled {
background-color: #f8f8f8;
border-color: #e8e8e8 #999 #e8e8e8 #e8e8e8;
}
}
@e plus {
border-radius: 0 2px 2px 0;
@m disabled {
background-color: #f8f8f8;
border-color: #e8e8e8 #e8e8e8 #e8e8e8 #999;
}
}
@e input {
width: 33px;
height: 26px;
padding: 1px;
border: 1px solid $c-gray-dark;
border-width: 1px 0;
box-sizing: content-box;
color: $c-gray-darker;
font-size: 14px;
outline: 0;
vertical-align: middle;
text-align: center;
}
}
}

View File

@ -106,7 +106,7 @@
.zan-step__circle-container {
left: auto;
right: -8px;
right: -9px;
}
.zan-step__line {

View File

@ -0,0 +1,100 @@
@import "./common/var.css";
@import "./mixins/border_retina.css";
@component-namespace zan {
@b tabs {
position: relative;
}
@b tabs-line {
height: 44px;
background-color: $c-white;
&::after {
@mixin border-retina (top);
@mixin border-retina (bottom);
}
@b tabs-nav-bar {
display: block;
}
}
@b tabs-card {
height: 28px;
margin: 0 15px;
background-color: $c-white;
border-radius: 2px;
border: 1px solid #666666;
overflow: hidden;
.zan-tabs-nav-bar {
display: none;
}
.zan-tab {
color: #666666;
line-height: 28px;
border-right: 1px solid #666666;
&:last-child {
border-right: none;
}
&.zan-tab-active {
background-color: #666666;
color: $c-white;
}
}
}
@b tabs-nav {
display: flex;
transition: transform .5s cubic-bezier(.645, .045, .355, 1);
position: relative;
/*float: left*/
&::after, &::before {
display: table;
content: " "
}
&::after {
clear: both
}
}
@b tabs-nav-bar {
z-index: 1;
position: absolute;
left: 0;
bottom: 0;
height: 2px;
background-color: #f13e3a;
transition: transform .3s cubic-bezier(.645, .045, .355, 1);
transform-origin: 0 0;
}
@b tab {
color: $c-black;
font-size: 14px;
line-height: 44px;
flex: 1;
display: inline-block;
box-sizing: border-box;
transition: color .3s cubic-bezier(.645, .045, .355, 1);
cursor: pointer;
text-align: center;
}
@b tab-active {
color: #FF4444;
}
@b tabs-pane {
display: none;
@when select {
display: block;
}
}
}

View File

@ -21,10 +21,15 @@ import BadgeGroup from '../packages/badge-group/index.js';
import Badge from '../packages/badge/index.js';
import Search from '../packages/search/index.js';
import Step from '../packages/step/index.js';
import Tabs from '../packages/tabs/index.js';
import Tab from '../packages/tab/index.js';
import Lazyload from '../packages/lazyload/index.js';
import ImagePreview from '../packages/image-preview/index.js';
import Col from '../packages/col/index.js';
import Row from '../packages/row/index.js';
import Actionsheet from '../packages/actionsheet/index.js';
import Quantity from '../packages/quantity/index.js';
import Progress from '../packages/progress/index.js';
const install = function(Vue) {
if (install.installed) return;
@ -50,9 +55,13 @@ const install = function(Vue) {
Vue.component(Badge.name, Badge);
Vue.component(Search.name, Search);
Vue.component(Step.name, Step);
Vue.component(Tabs.name, Tabs);
Vue.component(Tab.name, Tab);
Vue.component(Col.name, Col);
Vue.component(Row.name, Row);
Vue.component(Actionsheet.name, Actionsheet);
Vue.component(Quantity.name, Quantity);
Vue.component(Progress.name, Progress);
};
// auto install
@ -62,7 +71,7 @@ if (typeof window !== 'undefined' && window.Vue) {
module.exports = {
install,
version: '0.0.15',
version: '0.0.30',
Button,
Switch,
Field,
@ -86,8 +95,13 @@ module.exports = {
Badge,
Search,
Step,
Tabs,
Tab,
Lazyload,
ImagePreview,
Col,
Row,
Actionsheet
Actionsheet,
Quantity,
Progress
};

View File

@ -1,7 +1,19 @@
import Vue from 'vue';
import merge from 'src/utils/merge';
import PopupManager from './popup-manager';
let idSeed = 1;
let popupContext;
if (!window.popupContext) {
popupContext = window.popupContext = {
idSeed: 1,
zIndex: 2000,
hasModal: false,
instances: {},
modalStack: []
};
} else {
popupContext = window.popupContext;
}
const getDOM = function(dom) {
if (dom.nodeType === 3) {
@ -58,8 +70,8 @@ export default {
},
beforeMount() {
this._popupId = 'popup-' + idSeed++;
PopupManager.register(this._popupId, this);
this._popupId = 'popup-' + popupContext.idSeed++;
PopupManager.register(this._popupId, this, popupContext);
},
data() {
@ -86,9 +98,9 @@ export default {
const props = merge({}, this, options);
const zIndex = props.zIndex;
// 如果属性中传入了`zIndex`,则覆盖`PopupManager`中对应的`zIndex`
// 如果属性中传入了`zIndex`,则覆盖`popupContext`中对应的`zIndex`
if (zIndex) {
PopupManager.zIndex = zIndex;
popupContext.zIndex = zIndex;
}
// 如果显示遮罩层

View File

@ -1,13 +1,12 @@
import Vue from 'vue';
import { addClass } from 'src/utils/dom';
let hasModal = false; // eslint-disable-line
const getModal = function() {
let modalDom = PopupManager.modalDom;
if (modalDom) {
hasModal = true;
PopupManager.popupContext.hasModal = true;
} else {
hasModal = false;
PopupManager.popupContext.hasModal = false;
modalDom = document.createElement('div');
PopupManager.modalDom = modalDom;
@ -24,31 +23,26 @@ const getModal = function() {
return modalDom;
};
const instances = {};
const PopupManager = {
zIndex: 2000,
modalStack: [],
nextZIndex() {
return this.zIndex++;
return this.popupContext.zIndex++;
},
getInstance(id) {
return instances[id];
return this.popupContext.instances[id];
},
register(id, instance) {
register(id, instance, context) {
if (id && instance) {
instances[id] = instance;
this.popupContext = context;
this.popupContext.instances[id] = instance;
}
},
deregister(id) {
if (id) {
instances[id] = null;
delete instances[id];
this.popupContext.instances[id] = null;
delete this.popupContext.instances[id];
}
},
@ -56,7 +50,7 @@ const PopupManager = {
* 遮罩层点击回调`closeOnClickOverlay``true`时会关闭当前`popup`
*/
handleOverlayClick() {
const topModal = PopupManager.modalStack[PopupManager.modalStack.length - 1];
const topModal = this.popupContext.modalStack[this.popupContext.modalStack.length - 1];
if (!topModal) return;
const instance = PopupManager.getInstance(topModal.id);
@ -68,7 +62,7 @@ const PopupManager = {
openModal(id, zIndex, dom) {
if (!id || zIndex === undefined) return;
const modalStack = this.modalStack;
const modalStack = this.popupContext.modalStack;
for (let i = 0, len = modalStack.length; i < len; i++) {
const item = modalStack[i];
@ -81,22 +75,18 @@ const PopupManager = {
addClass(modalDom, 'zan-modal');
if (dom && dom.parentNode && dom.parentNode.nodeType !== 11) {
dom.parentNode.appendChild(modalDom);
} else {
document.body.appendChild(modalDom);
}
document.body.appendChild(modalDom);
if (zIndex) {
modalDom.style.zIndex = zIndex;
}
modalDom.style.display = '';
this.modalStack.push({ id: id, zIndex: zIndex });
this.popupContext.modalStack.push({ id: id, zIndex: zIndex });
},
closeModal(id) {
const modalStack = this.modalStack;
const modalStack = this.popupContext.modalStack;
const modalDom = getModal();
if (modalStack.length > 0) {
@ -118,12 +108,10 @@ const PopupManager = {
if (modalStack.length === 0) {
setTimeout(() => {
if (modalStack.length === 0) {
if (modalDom.parentNode) modalDom.parentNode.removeChild(modalDom);
if (modalDom.parentNode) modalDom.parentNode.removeChild(modalDom);
modalDom.style.display = 'none';
this.modalDom = null;
}
modalDom.style.display = 'none';
this.modalDom = null;
}, 200);
}
}

View File

@ -0,0 +1,16 @@
import { createVue } from '../creater';
import ActionSheet from 'packages/actionsheet';
describe('ActionSheet', () => {
let vm;
afterEach(() => {
vm && vm.destroy();
});
it('create', () => {
vm = createVue(ActionSheet);
vm.mount();
expect(vm.el.classList.contains('zan-actionsheet')).to.true;
});
});

View File

@ -0,0 +1,20 @@
import { createVue } from '../creater';
import Card from 'packages/card';
describe('Card', () => {
let vm;
afterEach(() => {
vm && vm.destroy();
});
it('create', () => {
vm = createVue(Card, {
title: 'card',
desc: 'card',
thumb: 'https://img.yzcdn.cn/upload_files/2017/02/17/FnDwvwHmU-OiqsbjAO5X7wh1KWrR.jpg!100x100.jpg'
});
vm.mount();
expect(vm.el.classList.contains('zan-card')).to.true;
});
});

View File

@ -0,0 +1,16 @@
import { createVue } from '../creater';
import CellGroup from 'packages/cell-group';
describe('Cell', () => {
let vm;
afterEach(() => {
vm && vm.destroy();
});
it('cell group create', () => {
vm = createVue(CellGroup);
vm.mount();
expect(vm.el.classList.contains('zan-cell-group')).to.true;
});
});

View File

@ -0,0 +1,16 @@
import { createVue } from '../creater';
import Checkbox from 'packages/checkbox';
describe('Checkbox', () => {
let vm;
afterEach(() => {
vm && vm.destroy();
});
it('create', () => {
vm = createVue(Checkbox);
vm.mount();
expect(vm.el.classList.contains('zan-checkbox')).to.true;
});
});

View File

@ -0,0 +1,16 @@
import { createVue } from '../creater';
import Field from 'packages/field';
describe('Field', () => {
let vm;
afterEach(() => {
vm && vm.destroy();
});
it('create', () => {
vm = createVue(Field);
vm.mount();
expect(vm.el.classList.contains('zan-field')).to.true;
});
});