Merge remote-tracking branch 'upstream/dev' into dev

This commit is contained in:
niunai 2017-09-08 11:19:37 +08:00
commit 0c69e70a12
132 changed files with 10183 additions and 1303 deletions

View File

@ -1,18 +1,14 @@
/**
* Build npm lib
* Steps:
* 1. 清理目录
* 1. 代码格式校验
* 2. 构建 JS 入口文件
* 3. 代码格式校验
* 4. 构建每个组件对应的 [component].js
* 5. 构建 vant-css
* 4. 构建 vant-css
* 5. 打包 JS 文件vant.js && vant.min.js
* 6. 生成每个组件目录下的 style 入口
* 7. 打包 JS 文件vant.js && vant.min.js
*/
const fs = require('fs');
const path = require('path');
const components = require('./get-components')();
const chalk = require('chalk');
require('shelljs/global');
@ -36,26 +32,16 @@ log('Starting', 'build:vant-css');
exec('npm run build:vant-css --silent');
log('Finished', 'build:vant-css');
// 5. build style entrys
log('Starting', 'build:style-entries');
components.forEach((componentName) => {
const dir = path.join(__dirname, '../../lib/', componentName, '/style');
const file = path.join(dir, 'index.js');
const cssPath = path.join(__dirname, '../../lib/vant-css/', `${componentName}.css`);
const content = [];
if (fs.existsSync(cssPath)) {
content.push(`require('../../vant-css/${componentName}.css');`);
}
mkdir(dir);
writeFile(file, content.join('\n'));
});
log('Finished', 'build:style-entries');
// 6. build vant.js
// 5. build vant.js
log('Starting', 'build:vant');
exec('npm run build:vant --silent');
log('Finished', 'build:vant');
// 6. build style entrys
log('Starting', 'build:style-entries');
exec('npm run build:style-entry --silent');
log('Finished', 'build:style-entries');
// helpers
function log(status, action, breakLine) {
const now = new Date();
@ -66,16 +52,3 @@ function log(status, action, breakLine) {
function padZero(num) {
return (num < 10 ? '0' : '') + num;
}
function writeFile(pathname, content) {
if (!fs.existsSync(pathname)) {
fs.closeSync(fs.openSync(pathname, 'w'));
}
fs.writeFileSync(pathname, content, { encoding: 'utf8' });
}
function mkdir(pathname) {
if (!fs.existsSync(pathname)) {
fs.mkdirSync(pathname);
}
}

View File

@ -0,0 +1,48 @@
/**
* 生成每个组件目录下的 style 入口
*/
const fs = require('fs-extra');
const path = require('path');
const components = require('./get-components')();
const source = require('../../lib/vant');
components.forEach(componentName => {
const dependencies = analyzeDependencies(componentName);
const styleDir = path.join(__dirname, '../../lib/', componentName, '/style');
const content = dependencies.map(component => `require('../../vant-css/${component}.css');`);
fs.outputFileSync(path.join(styleDir, './index.js'), content.join('\n'));
});
// 递归分析组件依赖
// 样式引入顺序:基础样式, 组件依赖样式,组件本身样式
function analyzeDependencies(componentName) {
const checkList = ['base'];
const search = component => {
const componentSource = source[toPascal(component)];
if (componentSource && componentSource.components) {
Object.keys(componentSource.components).forEach(name => {
name = name.replace('van-', '');
if (checkList.indexOf(name) === -1) {
search(name);
}
});
}
if (checkList.indexOf(component) === -1) {
checkList.push(component);
}
}
search(componentName);
return checkList.filter(component => checkComponentHasStyle(component));
}
// 判断组件是否有样式
function checkComponentHasStyle(componentName) {
const cssPath = path.join(__dirname, '../../lib/vant-css/', `${componentName}.css`);
return fs.existsSync(cssPath);
}
function toPascal(str) {
return ('_' + str).replace(/[_.-](\w|$)/g, (_, x) => x.toUpperCase());
}

View File

@ -23,6 +23,7 @@ extractExample({
module.exports = {
entry: {
vendor: ['packages'],
'vant-docs': './docs/src/index.js',
'vant-examples': './docs/src/examples.js'
},
@ -87,7 +88,18 @@ module.exports = {
},
{
test: /\.md/,
loader: 'vue-markdown-loader'
loader: 'vue-markdown-loader',
options: {
preventExtract: true,
use: [[require('markdown-it-container'), 'demo']],
preprocess(MarkdownIt, source) {
const styleRegexp = /<style\b[^<]*(?:(?!<\/style>)<[^<]*)*<\/style>/i;
const scriptRegexp = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/i;
MarkdownIt.renderer.rules.table_open = () =>
'<table class="zan-doc-table">';
return source.replace(styleRegexp, '').replace(scriptRegexp, '');
}
}
},
{
test: /\.(woff2?|eot|ttf|otf|svg)(\?.*)?$/,
@ -98,37 +110,6 @@ module.exports = {
devtool: 'source-map',
plugins: [
new ProgressBarPlugin(),
new webpack.LoaderOptionsPlugin({
minimize: true,
options: {
vue: {
autoprefixer: false
},
vueMarkdown: {
use: [
[
require('markdown-it-container'),
'demo',
{
validate: function(params) {
return params.trim().match(/^demo\s*(.*)$/);
},
render: function(tokens, idx) {
return tokens[idx].nesting === 1
? `<demo-block class="demo-box"><div class="highlight" slot="highlight"å>`
:`</div></demo-block>\n`;
}
}
]
],
preprocess: function(MarkdownIt, source) {
MarkdownIt.renderer.rules.table_open = () => '<table class="zan-doc-table">';
return source;
}
}
}
}),
new HtmlWebpackPlugin({
chunks: ['vendor', 'vant-docs'],
template: 'docs/src/index.tpl',
@ -143,9 +124,9 @@ module.exports = {
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks: 2
minChunks: 2,
filename: isProduction ? 'vendor.[hash:8].js' : 'vendor.js'
}),
new webpack.HotModuleReplacementPlugin(),
new OptimizeCssAssetsPlugin(),
new ExtractTextPlugin({
filename: isProduction ? '[name].[hash:8].css' : '[name].css',

View File

@ -27,10 +27,6 @@ module.exports = merge(devConfig, {
comments: false
},
sourceMap: false
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks: Infinity
})
]
});

View File

@ -73,8 +73,9 @@ Vue.component(Actionsheet.name, Actionsheet);
<van-button @click="show1 = true">弹出actionsheet</van-button>
<van-actionsheet v-model="show1" :actions="actions1">
</van-actionsheet>
```
<script>
```javascript
export default {
data() {
return {
@ -109,7 +110,6 @@ export default {
}
}
}
</script>
```
:::
@ -122,8 +122,9 @@ export default {
<van-button @click="show2 = true">弹出带取消按钮的actionsheet</van-button>
<van-actionsheet v-model="show2" :actions="actions1" cancel-text="取消">
</van-actionsheet>
```
<script>
```javascript
export default {
data() {
return {
@ -152,7 +153,6 @@ export default {
};
}
}
</script>
```
:::

133
docs/examples-docs/area.md Normal file
View File

@ -0,0 +1,133 @@
<script>
import AreaList from '../mock/area.json';
export default {
data() {
return {
areaList: AreaList
}
}
};
</script>
## Area 省市县选择组件
### 使用指南
``` javascript
import { Area } from 'vant';
Vue.component(Area.name, Area);
```
### 代码演示
#### 基础用法
要初始化一个`Area`组件,你需要传入一个`areaList`属性,`areaList`数据格式具体可看下面数据格式章节。
:::demo 基础用法
```html
<van-area :area-list="areaList"></van-area>
<script>
import AreaList from '../mock/area.json';
export default {
data() {
return {
areaList: AreaList
}
}
};
</script>
```
:::
#### 选中省市县
如果想选中某个省市县,需要传入一个`value`属性,绑定对应的省市县`code`
:::demo 选中省市县
```html
<van-area :area-list="areaList" value="110101"></van-area>
```
:::
#### 配置显示列
可以通过`columnsNum`属性配置省市县显示的列数,默认情况下会显示省市县,当你设置为`2`,则只会显示省市选择。
:::demo 配置显示列
```html
<van-area :area-list="areaList" :columns-num="2"></van-area>
```
:::
### API
| 参数 | 说明 | 类型 | 默认值 | 可选值 |
|-----------|-----------|-----------|-------------|-------------|
| value | 当前选中的省市区`code` | `String` | - | |
| areaList | 省市县数据,必须与`province_list``city_list``county_list`为key | `Object` | | |
| columnsNum | 省市县显示列数3-省市县2-省市1-省 | `String`,`Number` | 3 | |
### Event
| 事件名称 | 说明 | 回调参数 |
|-----------|-----------|-----------|
| confirm | 点击右上方完成按钮 | 一个数组参数,具体格式看下方数据格式章节 |
| cancel | 点击取消按钮时 | - |
### 数据格式
#### 省市县列表数据格式
整体是一个Object包含 `province_list`, `city_list`, `county_list` 三个key。
每项以省市区编码作为key省市区名字作为value。编码为6位数字前两位代表省份中间两位代表城市后两位代表区县以0补足6位。如北京编码为 `11`以零补足6位`110000`
`AreaList`具体格式如下:
```javascript
{
province_list: {
110000: '北京市',
120000: '天津市'
},
city_list: {
110100: '北京市',
110200: '县',
120100: '天津市',
120200: '县'
},
county_list: {
110101: '东城区',
110102: '西城区',
110105: '朝阳区',
110106: '丰台区'
120101: '和平区',
120102: '河东区',
120103: '河西区',
120104: '南开区',
120105: '河北区',
// ....
}
}
```
#### 点击完成时返回的数据格式
返回的数据整体为一个数组,数组内包含 `columnsNum` 个数据, 每个数据对应一列选项中被选中的数据。
`code` 代表被选中的地区编码, `name` 代表被选中的地区名称
```javascript
[{
code: '110000',
name: '北京市'
}, {
code: '110100',
name: '北京市'
},{
code: '110101',
name: '东城区'
}]
```

View File

@ -23,25 +23,29 @@ Vue.component(Card.name, Card);
:::demo 基础用法
```html
<van-card title="商品名称" desc="商品描述" :thumb="imageURL" />
<van-card
title="商品名称"
desc="商品描述"
num="2"
price="2.00"
:thumb="imageURL"
/>
```
:::
#### 高级用法
可以使用具名`slot`重写标题等信息,其中包含`title``desc``footer``tag`四个`slot`
可以通过具名`slot`添加定制内容
:::demo 高级用法
```html
<van-card :thumb="imageURL">
<div class="van-card__row" slot="title">
<h4 class="van-card__title">商品名称</h4>
<span class="van-card__price">¥ 2.00</span>
</div>
<div class="van-card__row" slot="desc">
<span class="van-card__num">x 2</span>
</div>
<div class="van-card__footer" slot="footer">
<van-card
title="商品名称"
desc="商品描述"
num="2"
price="2.00"
:thumb="imageURL"
>
<div slot="footer">
<van-button size="mini">按钮一</van-button>
<van-button size="mini">按钮二</van-button>
</div>
@ -51,11 +55,13 @@ Vue.component(Card.name, Card);
### API
| 参数 | 说明 | 类型 | 默认值 | 可选值 |
| 参数 | 说明 | 类型 | 默认值 | 可选值 |
|-----------|-----------|-----------|-------------|-------------|
| thumb | 左侧图片 | `String` | - | - |
| title | 标题 | `String` | - | - |
| desc | 描述 | `String` | - | - |
| thumb | 左侧图片 | `String` | - | - |
| title | 标题 | `String` | - | - |
| desc | 描述 | `String` | - | - |
| num | 商品数量 | `String | Number` | - | - |
| price | 商品价格 | `String | Number` | - | - |
| centered | 内容是否垂直居中 | `String` | `false` | - |
### Slot

View File

@ -1,10 +1,37 @@
## 更新日志
## [v0.9.0](https://github.com/youzan/vant/tree/v0.9.0) (2017-09-07)
[Full Changelog](https://github.com/youzan/vant/compare/v0.8.9...v0.9.0)
**非兼容更新和新特性:**
- add PullRefresh component [\#117](https://github.com/youzan/vant/pull/117) ([chenjiahan](https://github.com/chenjiahan))
- Build: analyzes component dependencies when build style entries [\#115](https://github.com/youzan/vant/pull/115) ([chenjiahan](https://github.com/chenjiahan))
- Toast: use flex layout, support loading with text, improve performance [\#114](https://github.com/youzan/vant/pull/114) ([chenjiahan](https://github.com/chenjiahan))
- Card: support num and price props [\#112](https://github.com/youzan/vant/pull/112) ([chenjiahan](https://github.com/chenjiahan))
- vant-css: use hairline classes instead of mixins [\#110](https://github.com/youzan/vant/pull/110) ([chenjiahan](https://github.com/chenjiahan))
- update `popup` and `quickstart` readme [\#109](https://github.com/youzan/vant/pull/109) ([cookfront](https://github.com/cookfront))
- add OrderCoupon component [\#108](https://github.com/youzan/vant/pull/108) ([chenjiahan](https://github.com/chenjiahan))
- Doc: improve site load speed [\#107](https://github.com/youzan/vant/pull/107) ([chenjiahan](https://github.com/chenjiahan))
**修复:**
- Fix: swipe tabs animation time and timing function [\#111](https://github.com/youzan/vant/pull/111) ([cookfront](https://github.com/cookfront))
- hide indicators when one swipe page [\#106](https://github.com/youzan/vant/pull/106) ([Raistlin916](https://github.com/Raistlin916))
**合并的 Pull Request (可能有不兼容改动):**
- 新增Area省市区选择组件 [\#113](https://github.com/youzan/vant/pull/113) ([cookfront](https://github.com/cookfront))
## [v0.8.9](https://github.com/youzan/vant/tree/v0.8.9) (2017-09-01)
[Full Changelog](https://github.com/youzan/vant/compare/v0.8.8...v0.8.9)
## [v0.8.8](https://github.com/youzan/vant/tree/v0.8.8) (2017-09-01)
[Full Changelog](https://github.com/youzan/vant/compare/v0.8.7...v0.8.8)
**非兼容更新和新特性:**
- PayOrder component add tip slot [\#105](https://github.com/youzan/vant/pull/105) ([Raistlin916](https://github.com/Raistlin916))
- Checkbox: support listen to change event [\#104](https://github.com/youzan/vant/pull/104) ([chenjiahan](https://github.com/chenjiahan))
- add GoodsAction component [\#102](https://github.com/youzan/vant/pull/102) ([chenjiahan](https://github.com/chenjiahan))
- add InvalidGoods component [\#100](https://github.com/youzan/vant/pull/100) ([chenjiahan](https://github.com/chenjiahan))
@ -17,7 +44,6 @@
**合并的 Pull Request (可能有不兼容改动):**
- PayOrder component add tip slot [\#105](https://github.com/youzan/vant/pull/105) ([Raistlin916](https://github.com/Raistlin916))
- Add deep-select component and fix a popup bug. [\#103](https://github.com/youzan/vant/pull/103) ([Tinysymphony](https://github.com/Tinysymphony))
- Doc: update Step/Loading/Tag/Badge documents [\#101](https://github.com/youzan/vant/pull/101) ([chenjiahan](https://github.com/chenjiahan))

View File

@ -52,16 +52,16 @@ Vue.component(Checkbox.name, Checkbox);
<div class="van-checkbox-wrapper">
<van-checkbox v-model="checkbox1">复选框1</van-checkbox>
</div>
```
<script>
```javascript
export default {
data() {
return {
checkbox1: true
};
}
};
</script>
};
```
:::
@ -74,16 +74,16 @@ export default {
<div class="van-checkbox-wrapper">
<van-checkbox v-model="checkbox2" disabled>复选框2</van-checkbox>
</div>
```
<script>
```javascript
export default {
data() {
return {
checkbox2: true
};
}
};
</script>
};
```
:::
@ -98,8 +98,9 @@ export default {
<van-checkbox v-for="(item, index) in list" :key="index" :name="item">复选框{{item}}</van-checkbox>
</van-checkbox-group>
</div>
```
<script>
```javascript
export default {
data() {
return {
@ -118,7 +119,6 @@ export default {
}
}
};
</script>
```
:::
@ -133,8 +133,9 @@ export default {
<van-checkbox v-for="(item, index) in list" :key="index" :name="item">复选框{{item}}</van-checkbox>
</van-checkbox-group>
</div>
```
<script>
```javascript
export default {
data() {
return {
@ -147,7 +148,6 @@ export default {
};
}
};
</script>
```
:::
@ -164,8 +164,9 @@ export default {
</van-cell>
</van-cell-group>
</van-checkbox-group>
```
<script>
```javascript
export default {
data() {
return {
@ -178,7 +179,6 @@ export default {
};
}
};
</script>
```
:::

View File

@ -50,8 +50,9 @@ Vue.component(DatetimePicker.name, DatetimePicker);
:max-date="maxDate"
@change="handlePickerChange">
</van-datetime-picker>
```
<script>
```javascript
export default {
data() {
return {
@ -69,7 +70,6 @@ export default {
}
}
};
</script>
```
:::

View File

@ -119,7 +119,6 @@ export default {
}
}
}
</script>
```
:::

View File

@ -7,7 +7,7 @@
</style>
<script>
import { Dialog } from 'packages/index';
import { Dialog } from 'packages';
const message = '弹窗内容';
@ -56,8 +56,9 @@ import { Dialog } from 'vant';
```html
<van-button @click="onClickAlert">Alert</van-button>
<van-button @click="onClickAlert2">无标题 Alert</van-button>
```
<script>
```javascript
export default {
methods: {
onClickAlert() {
@ -78,7 +79,6 @@ export default {
}
}
};
</script>
```
:::
@ -89,8 +89,9 @@ export default {
:::demo 消息确认
```html
<van-button @click="onClickConfirm">Confirm</van-button>
```
<script>
```javascript
export default {
methods: {
onClickConfirm() {
@ -105,7 +106,6 @@ export default {
}
}
};
</script>
```
:::

View File

@ -1,7 +1,7 @@
## ExpressWay 配送方式
<script>
import { Toast, CellGroup } from 'packages/index';
import { Toast } from 'packages';
export default {
data() {
@ -26,10 +26,6 @@ export default {
onChange(item, index) {
Toast('配送方式更换为:' + item.postage_title);
}
},
components: {
[CellGroup.name]: CellGroup
}
}
</script>
@ -47,17 +43,16 @@ Vue.component(ExpressWay.name, ExpressWay);
:::demo 基础用法
```html
<template>
<van-cell-group>
<van-express-way
v-model="currentExpressType"
:express-list="expressList"
@change="onChange"
/>
</van-cell-group>
</tempalte>
<van-cell-group>
<van-express-way
v-model="currentExpressType"
:express-list="expressList"
@change="onChange"
></van-express-way>
</van-cell-group>
```
<script>
```javascript
export default {
data() {
return {
@ -77,7 +72,6 @@ export default {
}
}
}
</script>
```
:::
@ -91,7 +85,7 @@ export default {
:express-list="expressList"
:editable="false"
@change="onChange"
/>
></van-express-way>
</van-cell-group>
```
:::

View File

@ -21,7 +21,7 @@ export default {
}
</style>
## GoodsAction 商品操作组件
## GoodsAction 商品操作
### 使用指南
``` javascript

View File

@ -32,7 +32,6 @@
<script>
import Vue from 'vue';
import { Icon, Col } from 'packages';
const icons = [
'close',
@ -113,10 +112,6 @@ const icons = [
];
const IconListConstructor = Vue.extend({
components: {
[Col.name]: Col,
[Icon.name]: Icon
},
render(h) {
return (
<div>

View File

@ -7,7 +7,7 @@
</style>
<script>
import { ImagePreview } from 'packages/index';
import { ImagePreview } from 'packages';
export default {
methods: {

View File

@ -33,11 +33,10 @@ Vue.component(InvalidGoods.name, InvalidGoods);
:::demo 基础用法
```html
<template>
<van-invalid-goods :goods="goods" />
<tempalte/>
<van-invalid-goods :goods="goods" />
```
<script>
```javascript
const item = {
num: 2,
sku_id: 123,
@ -58,7 +57,6 @@ export default {
}
}
}
</script>
```
:::

View File

@ -1,14 +1,15 @@
<style>
.demo-lazyload {
.lazy-img {
display: block;
width: 100%;
height: auto;
}
.lazy-background {
height: 300px;
background-size: cover;
img,
div[lazy] {
padding: 15px;
width: 315px;
height: 250px;
margin: 10px 15px 0;
background-color: white;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
background-size: 315px 250px;
background-position: 15px;
background-repeat: no-repeat;
}
}
@ -19,20 +20,18 @@ export default {
data() {
return {
imageList: [
'https://img.yzcdn.cn/upload_files/2016/01/27/Fo2dFWjXYzWDR9Jaa1AEqk1jt7e0',
'https://img.yzcdn.cn/upload_files/2016/01/27/FkyhiZfVE8tx-4qjxR2VeiqsSZYL',
'https://img.yzcdn.cn/upload_files/2016/01/27/FpWD3kX18w8qjM6faH-4JqOWHsF4',
'https://img.yzcdn.cn/upload_files/2016/09/08/9ff28d555e5760fa830344f12efa0087.jpg',
'https://img.yzcdn.cn/upload_files/2016/11/13/FlZIeSgbSANSPkmUHttMjoIgY3cv.jpg',
'https://img.yzcdn.cn/upload_files/2016/12/12/FuxgsGPRnupGu_eaMuaR8W0DuSKp.jpeg'
'https://img.yzcdn.cn/public_files/2017/09/05/3bd347e44233a868c99cf0fe560232be.jpg',
'https://img.yzcdn.cn/public_files/2017/09/05/c0dab461920687911536621b345a0bc9.jpg',
'https://img.yzcdn.cn/public_files/2017/09/05/4e3ea0898b1c2c416eec8c11c5360833.jpg',
'https://img.yzcdn.cn/public_files/2017/09/05/fd08f07665ed67d50e11b32a21ce0682.jpg'
],
backgroundImageList: [
'https://img.yzcdn.cn/upload_files/2016/01/27/Fo2dFWjXYzWDR9Jaa1AEqk1jt7e0',
'https://img.yzcdn.cn/upload_files/2016/01/27/FkyhiZfVE8tx-4qjxR2VeiqsSZYL'
'https://img.yzcdn.cn/public_files/2017/09/05/bac1903e863834ace25773f3554b6890.jpg',
'https://img.yzcdn.cn/public_files/2017/09/05/138c32d4384b5e4a78dc4e1ba58e6a80.jpg'
],
componentImageList: [
'https://img.yzcdn.cn/upload_files/2017/03/09/FvkZahKoq1vkxLQFdVWeLf2UCqDz.png',
'https://img.yzcdn.cn/upload_files/2017/03/09/Fk0rpe_svu9d5Xk3MUCWd1QeMXOu.png'
'https://img.yzcdn.cn/public_files/2017/09/05/100a7845756a70af2df513bdd1307d0e.jpg',
'https://img.yzcdn.cn/public_files/2017/09/05/8a4f5be8289cb3a7434fc19a3de780a2.jpg'
]
};
},
@ -61,60 +60,47 @@ Vue.use(Lazyload, options);
### 代码演示
#### 基础用法
比如商品详情页很多图片的情况需要对图片进行懒加载,只需将`v-lazy`指令的值设置为你需要懒加载的图片。
`v-lazy`指令的值设置为你需要懒加载的图片
:::demo 基础用法
```html
<ul class="image-list" ref="container">
<li v-for="(img, index) in imageList" :key="index">
<img class="lazy-img" v-lazy="img">
</li>
</ul>
<img v-for="img in imageList" v-lazy="img">
```
<script>
```javascript
export default {
data() {
return {
imageList: [
'https://img.yzcdn.cn/upload_files/2016/01/27/Fo2dFWjXYzWDR9Jaa1AEqk1jt7e0',
'https://img.yzcdn.cn/upload_files/2016/01/27/FkyhiZfVE8tx-4qjxR2VeiqsSZYL',
'https://img.yzcdn.cn/upload_files/2016/01/27/FpWD3kX18w8qjM6faH-4JqOWHsF4',
'https://img.yzcdn.cn/upload_files/2016/09/08/9ff28d555e5760fa830344f12efa0087.jpg',
'https://img.yzcdn.cn/upload_files/2016/11/13/FlZIeSgbSANSPkmUHttMjoIgY3cv.jpg',
'https://img.yzcdn.cn/upload_files/2016/12/12/FuxgsGPRnupGu_eaMuaR8W0DuSKp.jpeg'
'https://img.yzcdn.cn/1.jpg',
'https://img.yzcdn.cn/2.jpg'
]
};
}
}
</script>
```
:::
#### 背景图懒加载
和图片懒加载不同的背景图懒加载需要使用`v-lazy:background-image`,值设置为背景图片的地址。还有一个需要注意的是你需要设置容器的样式,否则高度不会撑开
和图片懒加载不同,背景图懒加载需要使用`v-lazy:background-image`,值设置为背景图片的地址,需要注意的是必须声明容器高度
:::demo 背景图懒加载
```html
<ul class="image-list" ref="container">
<li v-for="(img, index) in backgroundImageList" :key="index">
<div class="lazy-background" v-lazy:background-image="img"></div>
</li>
</ul>
<div v-for="img in backgroundImageList" v-lazy:background-image="img" />
```
<script>
```javascript
export default {
data() {
return {
backgroundImageList: [
'https://img.yzcdn.cn/upload_files/2016/01/27/Fo2dFWjXYzWDR9Jaa1AEqk1jt7e0',
'https://img.yzcdn.cn/upload_files/2016/01/27/FkyhiZfVE8tx-4qjxR2VeiqsSZYL'
'https://img.yzcdn.cn/1.jpg',
'https://img.yzcdn.cn/2.jpg'
]
};
}
}
</script>
```
:::
@ -124,32 +110,22 @@ export default {
:::demo 懒加载模块
```html
<lazy-component @show="handleComponentShow">
<ul class="image-list">
<li v-for="(img, index) in componentImageList" :key="index">
<img class="lazy-img" v-lazy="img">
</li>
</ul>
<lazy-component>
<img v-for="img in componentImageList" v-lazy="img">
</lazy-component>
```
<script>
```javascript
export default {
data() {
return {
componentImageList: [
'https://img.yzcdn.cn/upload_files/2017/03/09/FvkZahKoq1vkxLQFdVWeLf2UCqDz.png',
'https://img.yzcdn.cn/upload_files/2017/03/09/Fk0rpe_svu9d5Xk3MUCWd1QeMXOu.png'
'https://img.yzcdn.cn/1.jpg',
'https://img.yzcdn.cn/2.jpg'
]
};
},
methods: {
handleComponentShow() {
console.log('component show');
}
}
}
</script>
```
:::
@ -157,11 +133,13 @@ export default {
| 参数 | 说明 | 类型 | 默认值 | 可选值 |
|-----------|-----------|-----------|-------------|-------------|
| loading | 加载时的图片 | `String` | | |
| error | 错误时的图片 | `String` | | |
| preload | 预加载高度的比例 | `String` | | |
| attempt | 尝试次数 | `Number` | `3` | |
| listenEvents | 监听的事件 | `Array` | `['scroll', 'wheel', 'mousewheel', 'resize', 'animationend', 'transitionend', 'touchmove']` | |
| adapter | 适配器 | `Object` | | |
| filter | 图片url过滤 | `Object` | | |
| lazyComponent | 是否能懒加载模块 | `Boolean` | `false` | |
| loading | 加载时的图片 | `String` | - | - |
| error | 错误时的图片 | `String` | - | - |
| preload | 预加载高度的比例 | `String` | - | - |
| attempt | 尝试次数 | `Number` | `3` | |
| listenEvents | 监听的事件 | `Array` | `scroll`等 | - |
| adapter | 适配器 | `Object` | - | - |
| filter | 图片url过滤 | `Object` | - | - |
| lazyComponent | 是否能懒加载模块 | `Boolean` | `false` | - |
更多内容请参照:[ vue-lazyload 官方文档](https://github.com/hilongjw/vue-lazyload)

View File

@ -0,0 +1,173 @@
## OrderCoupon 下单页优惠券
<script>
import { Toast } from 'packages';
const coupon = {
available: 1,
discount: 0,
denominations: 150,
origin_condition: 0,
reason: '',
value: 150,
condition: '下单立减 1.50 元',
name: '新手专用优惠券',
start_at: 1489104000,
end_at: 1514592000
};
const discountCoupon = {
...coupon,
discount: 88,
denominations: 0,
origin_condition: 50,
value: 12,
condition: '下单即享 8.8 折',
};
const disabledCoupon = {
...coupon,
avaliable: 0,
reason: '未满足使用门槛'
};
const disabledDiscountCoupon = {
...discountCoupon,
avaliable: 0,
reason: '未满足使用门槛'
};
export default {
data() {
return {
showList: false,
chosenCoupon: -1,
coupons: [coupon, discountCoupon],
disabledCoupons: [disabledCoupon, disabledDiscountCoupon]
}
},
methods: {
onChange(index) {
this.chosenCoupon = index;
},
onExchange(code) {
Toast('兑换成功');
this.coupons.push(coupon);
}
}
}
</script>
### 使用指南
``` javascript
import { OrderCoupon, OrderCouponList } from 'vant';
Vue.component(OrderCoupon.name, OrderCoupon);
Vue.component(OrderCouponList.name, OrderCouponList);
```
### 代码演示
#### 基础用法
:::demo 基础用法
```html
<!-- 优惠券单元格 -->
<van-order-coupon
:coupons="coupons"
:chosen-coupon="chosenCoupon"
@click="showList = true"
></van-order-coupon>
<!-- 优惠券列表 -->
<van-order-coupon-list
v-model="showList"
:coupons="coupons"
:chosen-coupon="chosenCoupon"
:disabled-coupons="disabledCoupons"
@change="onChange"
@exchange="onExchange"
></van-order-coupon-list>
```
```javascript
const mockCoupon = {
available: 1,
discount: 0,
denominations: 150,
origin_condition: 0,
reason: '',
value: 150,
condition: '下单立减 1.50 元',
name: '新手专用优惠券',
start_at: 1489104000,
end_at: 1514592000
};
export default {
data() {
return {
chosenCoupon: -1,
coupons: [mockCoupon],
disabledCoupons: [mockCoupon]
}
},
methods: {
onChange(index) {
this.chosenCoupon = index;
},
onExchange(code) {
this.coupons.push(mockCoupon);
}
}
}
```
:::
### OrderCoupon API
| 参数 | 说明 | 类型 | 默认值 | 必须 |
|-----------|-----------|-----------|-------------|-------------|
| chosenCoupon | 当前选中优惠券的索引 | `Number` | `-1` | - |
| coupons | 可用优惠券列表 | `Array` | `[]` | - |
| editable | 能否切换优惠券 | `Boolean` | `true` | - |
### OrderCouponList API
| 参数 | 说明 | 类型 | 默认值 | 必须 |
|-----------|-----------|-----------|-------------|-------------|
| v-model | 是否展示优惠券列表 | `Boolean` | `false` | - |
| chosenCoupon | 当前选中优惠券的索引 | `Number` | `-1` | - |
| coupons | 可用优惠券列表 | `Array` | `[]` | - |
| disabledCoupons | 不可用优惠券列表 | `Array` | `[]` | - |
| exchangeButtonText | 兑换按钮文字 | `String` | `兑换` | - |
| exchangeButtonDisabled | 是否禁用兑换按钮 | `Boolean` | `false` | - |
| displayedCouponIndex | 滚动至特定优惠券位置 | `Number` | - | - |
| closeButtonText | 列表底部按钮文字 | `String` | 不使用优惠 | - |
| disabledListTitle | 不可用券列表标题 | `String` | 不可用优惠 | - |
| inputPlaceholder | 输入框文字提示 | `String` | 请输入优惠码 | - |
### OrderCouponList Event
| 事件名 | 说明 | 参数 |
|-----------|-----------|-----------|
| change | 优惠券切换回调 | index, 选中优惠券的索引 |
| exchange | 兑换优惠券回调 | code, 兑换码 |
### 数据格式
#### 优惠券字段说明
| key | 说明 | 类型 |
|-----------|-----------|-----------|
| id | 优惠券 id | `String` |
| name | 优惠券名称 | `String` |
| available | 是否可用, 1:可用,0:不可用 | `Number` |
| discount | 折扣0为满减券88=>8.8折 | `Number` |
| denominations | 面值0为折扣券单位分 | `Number` |
| origin_condition | 满减条件0为无门槛满XX元可用单位分 | `Number` |
| start_at | 卡有效开始时间 | `Number` |
| end_at | 卡失效日期 | `Number` |
| reason | 不可用原因 | `String` |
| value | 订单优惠金额,单位分 | `Number` |
| condition | 格式化输出 value | `String` |

View File

@ -64,16 +64,15 @@ Vue.component(OrderGoods.name, OrderGoods);
:::demo 基础用法
```html
<template>
<van-order-goods
v-model="message1"
shop-name="起码运动馆"
:price="1050"
:item-list="itemList1"
/>
</template>
<van-order-goods
v-model="message1"
shop-name="起码运动馆"
:price="1050"
:item-list="itemList1"
/>
```
<script>
```javascript
export default {
data() {
return {
@ -87,7 +86,6 @@ export default {
}
}
}
</script>
```
:::
@ -95,17 +93,16 @@ export default {
:::demo 积分商品
```html
<template>
<van-order-goods
v-model="message2"
shop-name="起码运动馆"
:item-list="itemList2"
:price="50"
:points="200"
/>
</template>
<van-order-goods
v-model="message2"
shop-name="起码运动馆"
:item-list="itemList2"
:price="50"
:points="200"
/>
```
<script>
```javascript
export default {
data() {
return {
@ -124,7 +121,6 @@ export default {
}
}
}
</script>
```
:::
@ -132,16 +128,15 @@ export default {
:::demo 预售商品
```html
<template>
<van-order-goods
v-model="message3"
shop-name="起码运动馆"
:price="1050"
:item-list="itemList3"
/>
</template>
<van-order-goods
v-model="message3"
shop-name="起码运动馆"
:price="1050"
:item-list="itemList3"
/>
```
<script>
```javascript
export default {
data() {
return {
@ -159,7 +154,6 @@ export default {
}
}
}
</script>
```
:::

View File

@ -1,7 +1,7 @@
## PayOrder 支付订单
## PayOrder 提交订单栏
<script>
import { Toast } from 'packages/index';
import { Toast } from 'packages';
export default {
methods: {

View File

@ -52,8 +52,9 @@ Vue.component(Picker.name, Picker);
:::demo 基础用法
```html
<van-picker :columns="pickerColumns" @change="handlePickerChange"></van-picker>
```
<script>
```javascript
const citys = {
'浙江': ['杭州', '宁波', '温州', '嘉兴', '湖州', '绍兴', '金华', '衢州', '舟山', '台州', '丽水'],
'福建': ['福州', '厦门', '莆田', '三明', '泉州', '漳州', '南平', '龙岩', '宁德'],
@ -82,7 +83,6 @@ export default {
}
}
};
</script>
```
:::
@ -98,8 +98,9 @@ export default {
@cancel="handlePickerCancel"
@confirm="handlePickerConfirm"
></van-picker>
```
<script>
```javascript
const citys = {
'浙江': ['杭州', '宁波', '温州', '嘉兴', '湖州', '绍兴', '金华', '衢州', '舟山', '台州', '丽水'],
'福建': ['福州', '厦门', '莆田', '三明', '泉州', '漳州', '南平', '龙岩', '宁德'],
@ -135,7 +136,6 @@ export default {
}
}
};
</script>
```
:::

View File

@ -94,8 +94,9 @@ Vue.component(Popup.name, Popup);
<van-popup v-model="popupShow1" class="van-popup-1" :lock-on-scroll="true">
从中间弹出popup
</van-popup>
```
<script>
```javascript
export default {
data() {
return {
@ -103,7 +104,6 @@ export default {
}
}
};
</script>
```
:::
@ -133,8 +133,9 @@ export default {
<van-popup v-model="popupShow5" position="left" class="van-popup-5" :overlay="false">
<van-button @click.native="popupShow5 = false">关闭 popup</van-button>
</van-popup>
```
<script>
```javascript
export default {
data() {
return {
@ -155,7 +156,6 @@ export default {
}
}
};
</script>
```
:::
@ -169,3 +169,4 @@ export default {
| position | 弹出菜单位置 | `String` | - | `top`, `bottom`, `right`, `left` |
| closeOnClickOverlay | 点击遮罩层是否关闭弹出菜单 | `Boolean` | `true` | - |
| transition | 弹出菜单的`transition` | `String` | `popup-slide` | |
| preventScroll | 是否防止滚动穿透 | `Boolean` | `false` | - |

View File

@ -0,0 +1,115 @@
<style>
.demo-pull-refresh {
.zan-doc-demo-block__title,
.zan-doc-demo-block__subtitle {
display: none;
}
.van-pull-refresh {
height: 450px;
background-color: #fff;
.zan-doc-demo-block__title {
display: block;
}
p {
margin: 10px 0 0 15px;
}
}
}
</style>
<script>
import { Toast } from 'packages';
export default {
data() {
return {
count: 0,
isLoading: false
}
},
watch: {
isLoading() {
if (this.isLoading) {
setTimeout(() => {
Toast('刷新成功');
this.isLoading = false;
this.count++;
}, 500);
}
}
},
mounted() {
const head = document.querySelector('.van-pull-refresh__head');
head.insertAdjacentHTML('afterend', '<h1 class="zan-doc-demo-block__title">PullRefresh 下拉刷新</h1>');
}
}
</script>
## PullRefresh 下拉刷新
### 使用指南
``` javascript
import { PullRefresh } from 'vant';
Vue.component(PullRefresh.name, PullRefresh);
```
### 代码演示
:::demo
```html
<!-- 通过 v-model 控制加载状态 -->
<van-pull-refresh v-model="isLoading">
<p>刷新次数: {{ count }}</p>
</van-pull-refresh>
```
```javascript
export default {
data() {
return {
count: 0,
isLoading: false
}
},
watch: {
isLoading() {
if (this.isLoading) {
setTimeout(() => {
Toast('刷新成功');
this.isLoading = false;
this.count++;
}, 500);
}
}
}
}
```
:::
### API
| 参数 | 说明 | 类型 | 默认值 | 可选值 |
|-----------|-----------|-----------|-------------|-------------|
| v-model | 是否在加载中 | `Boolean` | - | - |
| pullingText | 下拉过程中顶部文案 | `String` | `下拉即可刷新...` | - |
| loosingText | 释放过程中顶部文案 | `String` | `释放即可刷新...` | - |
| loadingText | 加载过程中顶部文案 | `String` | `加载中...` | - |
| animationDuration | 动画时长 | `Number` | `300` | - |
| headHeight | 顶部内容高度 | `Number` | `50` | - |
### Slot
| name | 描述 |
|-----------|-----------|
| - | 自定义内容 |
| normal | 非下拉状态时顶部内容 |
| pulling | 下拉过程中顶部内容 |
| loosing | 释放过程中顶部内容 |
| loading | 加载过程中顶部内容 |

View File

@ -66,3 +66,10 @@ cd packages/vant-css
修改你下载主题对应的样式即可,然后引入你修改后的主题。
### vue-cli模板
可以使用`vue-cli`来初始化`vant`的通用模板:
```shell
vue init youzan/vue-cli-template-vant projectName
```

View File

@ -44,8 +44,8 @@ Vue.component(Radio.name, Radio);
<van-radio name="1" v-model="radio1">单选框1</van-radio>
<van-radio name="2" v-model="radio1">单选框2</van-radio>
</div>
<script>
```
```javascript
export default {
data() {
return {
@ -53,7 +53,6 @@ export default {
}
}
};
</script>
```
:::
@ -67,8 +66,9 @@ export default {
<van-radio name="1" v-model="radio2" disabled>未选中禁用</van-radio>
<van-radio name="2" v-model="radio2" disabled>选中且禁用</van-radio>
</div>
```
<script>
```javascript
export default {
data() {
return {
@ -76,7 +76,6 @@ export default {
}
}
};
</script>
```
:::
@ -92,8 +91,9 @@ export default {
<van-radio name="2">单选框2</van-radio>
</van-radio-group>
</div>
```
<script>
```javascript
export default {
data() {
return {
@ -101,7 +101,6 @@ export default {
}
}
};
</script>
```
:::
@ -117,8 +116,9 @@ export default {
<van-cell><van-radio name="2">单选框2</van-radio></van-cell>
</van-cell-group>
</van-radio-group>
```
<script>
```javascript
export default {
data() {
return {
@ -126,7 +126,6 @@ export default {
}
}
};
</script>
```
:::

View File

@ -32,8 +32,9 @@ Vue.component(Search.name, Search);
:::demo 基础用法
```html
<van-search placeholder="商品名称" @search="goSearch"></van-search>
```
<script>
```javascript
export default {
methods: {
goSearch(value) {
@ -41,7 +42,6 @@ export default {
}
}
};
</script>
```
:::
@ -60,8 +60,9 @@ export default {
:::demo 监听对应事件
```html
<van-search placeholder="商品名称" @search="goSearch" @change="handleChange" @cancel="handleCancel"></van-search>
```
<script>
```javascript
export default {
methods: {
goSearch(value) {
@ -75,7 +76,6 @@ export default {
}
}
};
</script>
```
:::

View File

@ -55,8 +55,9 @@ Vue.component(Steps.name, Steps);
</van-steps>
<van-button @click="nextStep">下一步</van-button>
```
<script>
```javascript
export default {
data() {
return {
@ -70,7 +71,6 @@ export default {
}
}
}
</script>
```
:::

View File

@ -55,8 +55,9 @@ Vue.component(Swipe.name, Swipe);
</a>
</van-swipe-item>
</van-swipe>
```
<script>
```javascript
export default {
data() {
return {
@ -67,7 +68,6 @@ export default {
};
}
};
</script>
```
:::
@ -82,8 +82,9 @@ export default {
<img v-lazy="img" alt="">
</van-swipe-item>
</van-swipe>
```
<script>
```javascript
export default {
data() {
return {
@ -94,7 +95,6 @@ export default {
};
}
};
</script>
```
:::
@ -109,8 +109,9 @@ export default {
<img v-lazy="img" alt="">
</van-swipe-item>
</van-swipe>
```
<script>
```javascript
export default {
data() {
return {
@ -127,7 +128,6 @@ export default {
}
}
};
</script>
```
:::

View File

@ -25,13 +25,12 @@ Vue.component(SwitchCell.name, SwitchCell);
:::demo 基础用法
```html
<template>
<van-cell-group>
<van-switch-cell v-model="checked" title="标题" />
</van-cell-group>
</template>
<van-cell-group>
<van-switch-cell v-model="checked" title="标题" />
</van-cell-group>
```
<script>
```javascript
export default {
data() {
return {
@ -39,7 +38,6 @@ export default {
}
}
}
</script>
```
:::

View File

@ -66,10 +66,9 @@ Vue.component(Switch.name, Switch);
<div class="demo-switch__text">{{ switchState2 ? ' 打开' : '关闭' }}</div>
</van-col>
</van-row>
```
<script>
```javascript
export default {
data() {
return {
@ -90,7 +89,6 @@ export default {
}
}
};
</script>
```
:::
@ -110,8 +108,9 @@ export default {
<div class="demo-switch__text">关闭</div>
</van-col>
</van-row>
```
<script>
```javascript
export default {
data() {
return {
@ -120,7 +119,6 @@ export default {
};
}
};
</script>
```
:::
@ -140,8 +138,9 @@ export default {
<div class="demo-switch__text">关闭</div>
</van-col>
</van-row>
```
<script>
```javascript
export default {
data() {
return {
@ -150,7 +149,6 @@ export default {
};
}
};
</script>
```
:::

View File

@ -134,8 +134,9 @@ Vue.component(Tabs.name, Tabs);
<van-tab title="选项三">内容三</van-tab>
<van-tab title="选项四">内容四</van-tab>
</van-tabs>
```
<script>
```javascript
export default {
methods: {
popalert() {
@ -143,7 +144,6 @@ export default {
}
}
};
</script>
```
:::
@ -216,8 +216,9 @@ export default {
<van-tab title="选项三">内容三</van-tab>
<van-tab title="选项四">内容四</van-tab>
</van-tabs>
```
<script>
```javascript
export default {
methods: {
handleTabClick(index) {
@ -225,7 +226,6 @@ export default {
}
}
};
</script>
```
:::

View File

@ -1,17 +1,17 @@
<style>
.demo-toast {
.van-button {
margin: 15px;
margin-left: 15px;
}
}
</style>
<script>
import { Toast } from 'packages/index';
import { Toast } from 'packages';
export default {
methods: {
showSimpleToast() {
showToast() {
Toast('我是提示文案,建议不超过十五字~');
},
showLoadingToast() {
@ -23,39 +23,23 @@ export default {
showFailToast() {
Toast.fail('失败文案');
},
showForbidClickToast() {
Toast({
message: '背景不能点击',
forbidClick: true
})
},
showCustomizedToast(duration) {
let leftSec = duration / 1000;
let toast = Toast({
duration: duration + 1000,
type: 'success',
message: leftSec.toString()
const toast = Toast.loading({
duration: 0,
forbidClick: true,
message: '倒计时 3 秒'
});
const id = window.setInterval(() => {
if (leftSec <= 1) {
window.clearInterval(id);
toast.message = '跳转中...'
return;
let second = 3;
const timer = setInterval(() => {
second--;
if (second) {
toast.message = `倒计时 ${second} 秒`;
} else {
clearInterval(timer);
Toast.clear();
}
toast.message = (--leftSec).toString();
}, 1000);
},
showToast() {
this.toast = Toast('我是提示文案,建议不超过十五字~');
},
closeToast() {
this.toast.clear();
},
showHtmlToast() {
Toast({
type: 'html',
message: '<em>HTML<em>'
})
}
}
};
@ -65,163 +49,118 @@ export default {
### 使用指南
`Toast`和其他组件不同不是通过HTML结构的方式来使用而是通过函数调用的方式。使用前需要先引入它。
```js
```javascript
import { Toast } from 'vant';
```
### 代码演示
#### 基础用法
#### 文字提示
:::demo 基础用法
:::demo 文字提示
```html
<van-button @click="showSimpleToast">普通文字提示</van-button>
<van-button @click="showLoadingToast">加载Toast</van-button>
<van-button @click="showSuccessToast">成功</van-button>
<van-button @click="showFailToast">失败</van-button>
<van-button @click="showForbidClickToast">背景不能点击</van-button>
<van-button @click="showCustomizedToast(5000)">倒数5秒</van-button>
<script>
import { Toast } from 'packages/index';
<van-button @click="showToast">文字提示</van-button>
```
```javascript
export default {
methods: {
showSimpleToast() {
showToast() {
Toast('我是提示文案,建议不超过十五字~');
},
}
}
}
```
:::
#### 加载提示
:::demo 加载提示
```html
<van-button @click="showLoadingToast">加载提示</van-button>
```
```javascript
export default {
methods: {
showLoadingToast() {
Toast.loading();
},
}
}
}
```
:::
#### 成功/失败提示
:::demo 成功/失败提示
```html
<van-button @click="showSuccessToast">成功提示</van-button>
<van-button @click="showFailToast">失败提示</van-button>
```
```javascript
export default {
methods: {
showSuccessToast() {
Toast.success('成功文案');
},
showFailToast() {
Toast.fail('失败文案');
},
showForbidClickToast() {
Toast({
message: '背景不能点击',
forbidClick: true
})
},
showCustomizedToast(duration) {
let leftSec = duration / 1000;
let toast = Toast({
duration: duration + 1000,
type: 'success',
message: leftSec.toString()
}
}
}
```
:::
#### 高级用法
:::demo 高级用法
```html
<van-button @click="showCustomizedToast">高级用法</van-button>
```
```javascript
export default {
methods: {
showCustomizedToast() {
const toast = Toast.loading({
duration: 0, // 持续展示 toast
forbidClick: true, // 禁用背景点击
message: '倒计时 3 秒'
});
const id = window.setInterval(() => {
if (leftSec <= 1) {
window.clearInterval(id);
toast.message = '跳转中...'
return;
let second = 3;
const timer = setInterval(() => {
second--;
if (second) {
toast.message = `倒计时 ${second} 秒`;
} else {
clearInterval(timer);
Toast.clear();
}
toast.message = (--leftSec).toString();
}, 1000);
}
}
};
</script>
```
:::
#### 手动关闭
### 方法
:::demo 手动关闭
```html
<van-button @click="showToast">打开</van-button>
<van-button @click="closeToast">关闭</van-button>
| 方法名 | 参数 | 返回值 | 介绍 |
|-----------|-----------|-----------|-------------|
| Toast | `options | message` | toast 实例 | 展示提示 |
| Toast.loading | `options | message` | toast 实例 | 展示加载提示 |
| Toast.success | `options | message` | toast 实例 | 展示成功提示 |
| Toast.fail | `options | message` | toast 实例 | 展示失败提示 |
| Toast.clear | - | `void` | 关闭提示 |
<script>
import { Toast } from 'packages/index';
export default {
methods: {
showToast() {
Toast('我是提示文案,建议不超过十五字~');
},
closeToast() {
Toast.clear();
}
}
};
</script>
```
:::
#### 传入html
:::demo 手动关闭
```html
<van-button @click="showHtmlToast">打开</van-button>
<script>
import { Toast } from 'packages/index';
export default {
methods: {
showHtmlToast() {
Toast({
type: 'html',
message: '<em>HTML<em>'
})
}
}
};
</script>
```
:::
### 基础用法
#### Toast(options)
### Options
| 参数 | 说明 | 类型 | 默认值 | 可选值 |
|-----------|-----------|-----------|-------------|-------------|
| type | 类型 | String | 'text' | 'text', 'loading', 'success', 'fail', 'html' |
| message | 内容 | String | '' | - |\| message | 内容 | String | '' | -
| forbidClick | 不允许背景点击 | Boolean | false | true, false|
| duration | 时长(ms) | Number | 3000ms | -|
### 快速用法
#### Toast(message) || Toast(message, options)
| 参数 | 说明 | 类型 | 默认值 | 可选值 |
|-----------|-----------|-----------|-------------|-------------|
| message | 内容 | String | '' | - |
| forbidClick | 不允许背景点击 | Boolean | false | true, false|
| duration | 时长(ms) | Number | 3000ms | -|
#### Toast.loading() || Toast.loading(message, options)
| 参数 | 说明 | 类型 | 默认值 | 可选值 |
|-----------|-----------|-----------|-------------|-------------|
| forbidClick | 不允许背景点击 | Boolean | false | true, false|
| duration | 时长(ms) | Number | 3000ms | -|
#### Toast.success(message) || Toast.success(message, options)
| 参数 | 说明 | 类型 | 默认值 | 可选值 |
|-----------|-----------|-----------|-------------|-------------|
| type | 类型 | String | 'text' | 'text', 'loading', 'success', 'failure' |
| forbidClick | 不允许背景点击 | Boolean | false | true, false|
| duration | 时长(ms) | Number | 3000ms | -|
#### Toast.fail(message) || Toast.fail(message, options)
| 参数 | 说明 | 类型 | 默认值 | 可选值 |
|-----------|-----------|-----------|-------------|-------------|
| type | 类型 | String | 'text' | 'text', 'loading', 'success', 'failure' |
| forbidClick | 不允许背景点击 | Boolean | false | true, false|
| duration | 时长(ms) | Number | 3000ms | -|
#### Toast.clear()
关闭toast。
| type | 提示类型 | `String` | `text` | `loading` `success` `fail` `html` |
| message | 内容 | `String` | `''` | - |
| forbidClick | 禁止背景点击 | `Boolean` | `false` | - |
| duration | 时长(ms) | `Number` | `3000` | 值为 0 时toast 不会消失 |

View File

@ -34,8 +34,9 @@ Vue.component(Uploader.name, Uploader);
<van-icon name="photograph"></van-icon>
</van-uploader>
</div>
```
<script>
```javascript
export default {
methods: {
logContent(file) {
@ -43,7 +44,6 @@ export default {
}
}
};
</script>
```
:::

3607
docs/mock/area.json Normal file

File diff suppressed because it is too large Load Diff

View File

@ -10,8 +10,6 @@
</template>
<script>
import Vue from 'vue';
export default {
computed: {
visible() {
@ -30,8 +28,8 @@ export default {
},
watch: {
'$route.path': function(val) {
Vue.nextTick(() => {
'$route.path'(val) {
this.$nextTick(() => {
this.computeFooterFixed();
});
}

View File

@ -1,6 +1,6 @@
<template>
<div class="app">
<zan-doc :simulator="simulatorSrc" :config="config">
<zan-doc :simulator="simulator" :config="config">
<router-view></router-view>
</zan-doc>
</div>
@ -12,12 +12,14 @@ import docConfig from './doc.config';
export default {
data() {
return {
simulator: this.getSimulatorPath(),
config: docConfig['zh-CN']
};
},
computed: {
simulatorSrc() {
const dir = this.$route.path.split('/').pop();
methods: {
getSimulatorPath() {
const dir = location.pathname.split('/').pop();
if (dir === 'quickstart' || dir === 'changelog') {
return '/zanui/vue/examples';
} else {

View File

@ -1,17 +0,0 @@
<template>
<zan-doc-block :class="`demo-${component}`">
<slot name="highlight"></slot>
</zan-doc-block>
</template>
<script>
export default {
name: 'demo-block',
computed: {
component() {
return this.$route.path.split('/').pop();
}
}
};
</script>

View File

@ -3,11 +3,9 @@
<h1 class="zanui-title">Zan UI Wap</h1>
<h2 class="zanui-desc">有赞移动wap端组件库</h2>
<div class="mobile-navs">
<template v-for="(item, index) in data">
<div class="mobile-nav-item" v-if="item.showInMobile" :key="index">
<mobile-nav v-for="(group, index) in item.groups" :group="group" :base="base" :nav-key="index" :key="index"></mobile-nav>
</div>
</template>
<div class="mobile-nav-item" v-for="(item, index) in data" v-if="item.showInMobile" :key="index">
<mobile-nav v-for="(group, index) in item.groups" :group="group" :base="base" :nav-key="index" :key="index" />
</div>
</div>
</div>
</template>
@ -19,8 +17,6 @@ import MobileNav from './mobile-nav';
export default {
data() {
return {
highlights: [],
navState: [],
data: docConfig['zh-CN'].nav,
base: '/component'
};

View File

@ -176,6 +176,10 @@ module.exports = {
"path": "/picker",
"title": "Picker 选择器"
},
{
"path": "/pull-refresh",
"title": "PullRefresh 下拉刷新"
},
{
"path": "/toast",
"title": "Toast 轻提示"
@ -201,6 +205,10 @@ module.exports = {
"path": "/invalid-goods",
"title": "InvalidGoods 不可用商品列表"
},
{
"path": "/order-coupon",
"title": "OrderCoupon 下单页优惠券"
},
{
"path": "/order-goods",
"title": "OrderGoods 下单页商品列表"
@ -212,6 +220,10 @@ module.exports = {
{
"path": "/switch-cell",
"title": "SwitchCell 开关单元格"
},
{
"path": "/area",
"title": "Area 省市区选择"
}
]
}

View File

@ -18,21 +18,24 @@ Vue.use(VueRouter);
const routesConfig = routes(true);
routesConfig.push({
path: '/',
component: DemoList.default || DemoList
component: DemoList
});
const router = new VueRouter({
mode: 'history',
base: '/zanui/vue/examples',
routes: routesConfig
});
router.beforeEach((to, from, next) => {
router.afterEach(() => {
const container = document.querySelector('.examples-container');
if (container) {
document.querySelector('.examples-container').scrollTop = 0;
}
next();
window.syncPath();
});
window.vueRouter = router;
new Vue({ // eslint-disable-line
render: h => h(App),
router

41
docs/src/iframe-router.js Normal file
View File

@ -0,0 +1,41 @@
/**
* 同步父窗口和 iframe vue-router 状态
*/
import isMobile from './is-mobile';
window.syncPath = function(dir) {
const router = window.vueRouter;
const isInIframe = window !== window.top;
const currentDir = router.history.current.path;
const iframe = document.querySelector('iframe');
if (!isInIframe && !isMobile && iframe) {
iframeReady(iframe, () => {
iframe.contentWindow.changePath(currentDir);
});
}
};
window.changePath = function(path) {
window.vueRouter.replace(path);
};
function iframeReady(iframe, callback) {
const doc = iframe.contentDocument || iframe.contentWindow.document;
const interval = () => {
if (iframe.contentWindow.changePath) {
callback();
} else {
setTimeout(() => {
interval();
}, 50);
}
};
if (doc.readyState === 'complete') {
interval();
} else {
iframe.onload = interval;
}
}

View File

@ -3,17 +3,10 @@ import VueRouter from 'vue-router';
import App from './ExamplesDocsApp';
import routes from './router.config';
import ZanDoc from 'zan-doc';
import DemoBlock from './components/demo-block';
const isMobile = (function() {
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));
})();
import isMobile from './is-mobile';
Vue.use(VueRouter);
Vue.use(ZanDoc);
Vue.component(DemoBlock.name, DemoBlock);
const routesConfig = routes();
routesConfig.push({
@ -30,18 +23,18 @@ const router = new VueRouter({
router.beforeEach((route, redirect, next) => {
if (isMobile) {
window.location.replace('/zanui/vue/examples');
return;
}
document.title = route.meta.title || document.title;
next();
});
router.afterEach(() => {
if (!isMobile) {
window.scrollTo(0, 0);
}
window.scrollTo(0, 0);
window.syncPath();
});
window.vueRouter = router;
new Vue({ // eslint-disable-line
render: h => h(App),
router

View File

@ -6,7 +6,7 @@
<link rel="shortcut icon" href="https://b.yzcdn.cn/zanui/icon/zanui.ico">
<title>ZanUI - 移动端</title>
</head>
<body>
<body ontouchstart>
<div id="app-container">
<app></app>

7
docs/src/is-mobile.js Normal file
View File

@ -0,0 +1,7 @@
const isMobile = (function() {
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));
})();
export default isMobile;

View File

@ -1,9 +1,16 @@
const navs = require('./doc.config')['zh-CN'].nav;
import docConfig from './doc.config';
import componentDocs from '../examples-dist/entry-docs';
import componentDemos from '../examples-dist/entry-demos';
import './iframe-router';
const navs = docConfig['zh-CN'].nav;
const registerRoute = (isExample) => {
let route = [];
const route = [{
path: '*',
redirect: '/'
}];
navs.forEach(nav => {
if (isExample && !nav.showInMobile) {
return;

View File

@ -1,6 +1,6 @@
{
"name": "vant",
"version": "0.8.9",
"version": "0.9.1",
"description": "有赞vue wap组件库",
"main": "lib/vant.js",
"style": "lib/vant-css/index.css",
@ -17,6 +17,7 @@
"build:components": "node build/bin/build-components.js --color",
"build:vant-css": "gulp build --gulpfile packages/vant-css/gulpfile.js --color && mkdir lib/vant-css && cp -R packages/vant-css/lib/ lib/vant-css",
"build:vant": "cross-env NODE_ENV=production webpack --progress --hide-modules --color --config build/webpack.build.js && cross-env NODE_ENV=production webpack -p --progress --hide-modules --color --config build/webpack.build.js",
"build:style-entry": "VUE_ENV=server node build/bin/build-style-entry.js",
"deploy": "npm run deploy:docs && npm run deploy:cdn && gh-pages -d docs/dist --remote youzan && rimraf docs/dist",
"deploy:cdn": "superman cdn /zanui/vue docs/dist/*.js docs/dist/*.css",
"deploy:docs": "rimraf docs/dist && cross-env NODE_ENV=production webpack --progress --hide-modules --config build/webpack.config.prod.js",
@ -42,7 +43,7 @@
"license": "ISC",
"dependencies": {
"babel-runtime": "6.x",
"vue-lazyload": "^1.1.2"
"vue-lazyload": "^1.1.3"
},
"peerDependencies": {
"vue": "2.4.2"
@ -61,7 +62,7 @@
"babel-plugin-transform-vue-jsx": "^3.5.0",
"babel-polyfill": "^6.26.0",
"babel-preset-env": "^1.6.0",
"chai": "^4.1.1",
"chai": "^4.1.2",
"cheerio": "^0.22.0",
"codecov": "^2.2.0",
"cross-env": "^5.0.5",
@ -107,7 +108,6 @@
"uppercamelcase": "^3.0.0",
"url-loader": "^0.5.9",
"vue": "^2.4.2",
"vue-html-loader": "^1.2.4",
"vue-loader": "^13.0.4",
"vue-markdown-loader": "^2.1.0",
"vue-router": "^2.7.0",
@ -117,6 +117,6 @@
"webpack": "^3.5.5",
"webpack-dev-server": "^2.7.1",
"webpack-merge": "^4.1.0",
"zan-doc": "^0.2.10"
"zan-doc": "^0.2.12"
}
}

View File

@ -1,7 +1,7 @@
<template>
<transition name="van-actionsheet-float">
<div :class="['van-actionsheet', { 'van-actionsheet--withtitle': title }]" v-show="value">
<div class="van-actionsheet__header" v-if="title">
<div class="van-actionsheet__header van-hairline--top-bottom" v-if="title">
<h3 v-text="title" />
<van-icon name="close" @click.stop="$emit('input', false)" />
</div>
@ -9,7 +9,7 @@
<li
v-for="(item, index) in actions"
:key="index"
:class="['van-actionsheet__item', item.className, { 'van-actionsheet__item--loading': item.loading }]"
:class="['van-actionsheet__item', 'van-hairline--top', item.className, { 'van-actionsheet__item--loading': item.loading }]"
@click.stop="onClickItem(item)">
<template v-if="!item.loading">
<span class="van-actionsheet__name">{{ item.name }}</span>
@ -18,7 +18,7 @@
<van-loading v-else class="van-actionsheet__loading" type="circle" color="black" />
</li>
</ul>
<div class="van-actionsheet__item van-actionsheet__cancel" @click.stop="$emit('input', false)" v-if="cancelText">{{ cancelText }}</div>
<div class="van-actionsheet__item van-actionsheet__cancel van-hairline--top" @click.stop="$emit('input', false)" v-if="cancelText">{{ cancelText }}</div>
<div class="van-actionsheet__content" v-else>
<slot></slot>
</div>

159
packages/area/index.vue Normal file
View File

@ -0,0 +1,159 @@
<template>
<div class="van-area">
<van-picker ref="picker" :columns="areaColumns" value-key="name" show-toolbar @change="handleAreaChange" @confirm="handleAreaConfirm" @cancel="handleAreaCancel"></van-picker>
</div>
</template>
<script>
import Picker from '../picker';
const DEFAULT_PROVINCE = {
code: '-1',
name: '选择省份'
};
const DEFAULT_CITY = {
code: '-1',
name: '选择城市'
};
const DEFAULT_COUNTY = {
code: '-1',
name: '选择地区'
};
const PROVINCE_TYPE = 'provice';
const CITY_TYPE = 'city';
const COUNTY_TYPE = 'county';
export default {
name: 'van-area',
components: {
[Picker.name]: Picker
},
props: {
value: {},
areaList: Object,
/**
* 省市县显示列数3-省市县2-省市1-
*/
columnsNum: {
type: [String, Number],
default: 3
}
},
computed: {
areaColumns() {
const areaList = this.areaList;
if (!areaList || (areaList && typeof areaList.province_list !== 'object')) return [];
const columns = [];
const curValue = this.value || '';
columns.push({
values: [DEFAULT_PROVINCE].concat(this.computedAreaList(PROVINCE_TYPE)),
className: 'van-area__province',
defaultIndex: this.getAreaIndex(PROVINCE_TYPE, curValue)
});
const columnsNum = this.columnsNum;
if (+columnsNum > 1) {
columns.push({
values: [DEFAULT_CITY].concat(this.computedAreaList(CITY_TYPE, curValue.slice(0, 2))),
className: 'van-area__city',
defaultIndex: this.getAreaIndex(CITY_TYPE, curValue)
});
}
if (+columnsNum > 2) {
columns.push({
values: [DEFAULT_COUNTY].concat(this.computedAreaList(COUNTY_TYPE, curValue.slice(0, 4))),
className: 'van-area__county',
defaultIndex: this.getAreaIndex(COUNTY_TYPE, curValue)
});
}
return columns;
}
},
methods: {
/**
* 根据省市县类型和对应的`code`获取对应列表
*
* @param {string} type 省市县类型
* @param {string} code 对应code
*/
computedAreaList(type, code) {
const result = [];
const curAreaList = this.areaList;
const areaList = type === PROVINCE_TYPE
? curAreaList.province_list
: (type === CITY_TYPE ? curAreaList.city_list : curAreaList.county_list);
for (const i in areaList) {
//
//
if (type === PROVINCE_TYPE || (code && i.slice(0, code.length) === code)) {
result.push({
code: i,
name: areaList[i]
});
}
}
return result;
},
/**
* 获取对应省市县在列表中的索引
*/
getAreaIndex(type, code) {
const compareNum = type === PROVINCE_TYPE
? 2
: (type === CITY_TYPE ? 4 : 6);
const areaList = this.computedAreaList(type, code.slice(0, compareNum - 2));
for (let i = 0; i < areaList.length; i++) {
if (+areaList[i].code.slice(0, compareNum) === +code.slice(0, compareNum)) {
return i + 1;
}
}
return 0;
},
handleAreaChange(picker, values, index) {
const code = values[index].code;
//
if (index === 0) {
picker.setColumnValues(
1,
[DEFAULT_CITY].concat(this.computedAreaList(CITY_TYPE, code.slice(0, 2)))
);
picker.setColumnValues(
2,
[DEFAULT_COUNTY].concat(this.computedAreaList(COUNTY_TYPE, code.slice(0, 4)))
);
} else if (index === 1) {
picker.setColumnValues(
2,
[DEFAULT_COUNTY].concat(this.computedAreaList(COUNTY_TYPE, code.slice(0, 4)))
);
}
},
handleAreaConfirm(values) {
this.$emit('confirm', values);
},
handleAreaCancel() {
this.$emit('cancel');
}
}
};
</script>

View File

@ -1,5 +1,5 @@
<template>
<div class="van-badge-group">
<div class="van-badge-group van-hairline--top-bottom">
<slot></slot>
</div>
</template>

View File

@ -1,6 +1,5 @@
<template>
<a :class="['van-badge', { 'van-badge--select': isSelect }]" :href="url" @click="onClick">
<div class="van-badge__active"></div>
<a :class="['van-badge van-hairline', { 'van-badge--select': isSelect }]" :href="url" @click="onClick">
<div v-if="info" class="van-badge__info">{{ info }}</div>
{{ title }}
</a>

View File

@ -7,14 +7,22 @@
</div>
<div class="van-card__content">
<slot name="title">
<h4 v-text="title" class="van-card__title"></h4>
<div class="van-card__row" v-if="title || price !== undefined">
<h4 v-if="title" class="van-card__title">{{ title }}</h4>
<p v-if="price !== undefined" class="van-card__price">¥ {{ price }}</p>
</div>
</slot>
<slot name="desc">
<p v-if="desc" v-text="desc" class="van-card__desc"></p>
<div class="van-card__row" v-if="desc || num !== undefined">
<p v-if="desc" class="van-card__desc">{{ desc }}</p>
<p v-if="num !== undefined" class="van-card__num">x {{ num }}</p>
</div>
</slot>
<slot name="tags"></slot>
</div>
<slot name="footer"></slot>
<div class="van-card__footer" v-if="$slots.footer">
<slot name="footer"></slot>
</div>
</div>
</template>
@ -26,7 +34,9 @@ export default {
thumb: String,
title: String,
desc: String,
centered: Boolean
num: [Number, String],
centered: Boolean,
price: [Number, String]
}
};
</script>

View File

@ -1,5 +1,5 @@
<template>
<div class="van-cell-group">
<div class="van-cell-group van-hairline--top-bottom">
<slot></slot>
</div>
</template>

View File

@ -1,5 +1,5 @@
<template>
<a :class="['van-cell', { 'van-cell--required': required }]" :href="url" @click="$emit('click')">
<a :class="['van-cell', 'van-hairline', { 'van-cell--required': required }]" :href="url" @click="$emit('click')">
<div
class="van-cell__title"
v-if="$slots.title || title"

View File

@ -1,20 +1,20 @@
<template>
<div class="van-deep-select" v-bind:style="{ height: mainHeight + 'px' }">
<div class="van-deep-select" :style="{ height: mainHeight + 'px' }">
<div class="van-deep-select__nav">
<div
v-for="(item, index) in items"
class="van-deep-select__nitem"
v-bind:class="{ 'van-deep-select__nitem--active': mainActiveIndex === index }"
:class="{ 'van-deep-select__nitem--active': mainActiveIndex === index }"
@click="onNavClick(index)">
{{ item.text }}
</div>
</div>
<div class="van-deep-select__content" v-bind:style="{ height: itemHeight + 'px' }">
<div class="van-deep-select__content" :style="{ height: itemHeight + 'px' }">
<div
v-for="item in subItems"
:key="item.id"
class="van-deep-select__item"
v-bind:class="{ 'van-deep-select__item--active': activeId === item.id }"
:class="{ 'van-deep-select__item--active': activeId === item.id }"
@click="onItemSelect(item)">
{{ item.text }}
<van-icon

View File

@ -2,14 +2,28 @@
<transition name="van-dialog-bounce">
<div class="van-dialog" v-show="value">
<div class="van-dialog__header" v-if="title" v-text="title" />
<div class="van-dialog__content">
<div class="van-dialog__content van-hairline">
<slot>
<div class="van-dialog__message" v-if="message" :class="{ 'van-dialog__message--withtitle': title }" v-html="message" />
</slot>
</div>
<div class="van-dialog__footer" :class="{ 'is-twobtn': showCancelButton && showConfirmButton }">
<van-button size="large" class="van-dialog__cancel" v-show="showCancelButton" @click="handleAction('cancel')">{{ cancelButtonText }}</van-button>
<van-button size="large" class="van-dialog__confirm" v-show="showConfirmButton" @click="handleAction('confirm')">{{ confirmButtonText }}</van-button>
<van-button
size="large"
class="van-dialog__cancel"
v-show="showCancelButton"
@click="handleAction('cancel')"
>
{{ cancelButtonText }}
</van-button>
<van-button
size="large"
:class="['van-dialog__confirm', { 'van-hairline--left': showCancelButton && showConfirmButton }]"
v-show="showConfirmButton"
@click="handleAction('confirm')"
>
{{ confirmButtonText }}
</van-button>
</div>
</div>
</transition>

View File

@ -58,5 +58,5 @@ Dialog.close = () => {
export default Dialog;
export {
Dialog
DialogComponent as Dialog
};

View File

@ -9,6 +9,7 @@
'van-field--disabled': disabled,
'van-field--error': error,
'van-field--border': border,
'van-hairline--surround': border,
'van-field--autosize': autosize,
'van-field--has-icon': showIcon
}">

View File

@ -1,5 +1,5 @@
<template>
<a :href="url" class="van-goods-action__mini-btn" @click="$emit('click', $event);">
<a :href="url" class="van-goods-action__mini-btn van-hairline" @click="$emit('click', $event);">
<van-icon :class="['van-goods-action__mini-btn-icon', iconClass]" :name="icon" />
<slot></slot>
</a>

View File

@ -1,4 +1,5 @@
import Actionsheet from './actionsheet';
import Area from './area';
import Badge from './badge';
import BadgeGroup from './badge-group';
import Button from './button';
@ -23,12 +24,15 @@ import InvalidGoods from './invalid-goods';
import Lazyload from './lazyload';
import Loading from './loading';
import NoticeBar from './notice-bar';
import OrderCoupon from './order-coupon';
import OrderCouponList from './order-coupon-list';
import OrderGoods from './order-goods';
import Panel from './panel';
import PayOrder from './pay-order';
import Picker from './picker';
import Popup from './popup';
import Progress from './progress';
import PullRefresh from './pull-refresh';
import Quantity from './quantity';
import Radio from './radio';
import RadioGroup from './radio-group';
@ -47,9 +51,10 @@ import Toast from './toast';
import Uploader from './uploader';
import Waterfall from './waterfall';
const version = '0.8.9';
const version = '0.9.1';
const components = [
Actionsheet,
Area,
Badge,
BadgeGroup,
Button,
@ -71,12 +76,15 @@ const components = [
InvalidGoods,
Loading,
NoticeBar,
OrderCoupon,
OrderCouponList,
OrderGoods,
Panel,
PayOrder,
Picker,
Popup,
Progress,
PullRefresh,
Quantity,
Radio,
RadioGroup,
@ -111,6 +119,7 @@ export {
install,
version,
Actionsheet,
Area,
Badge,
BadgeGroup,
Button,
@ -135,12 +144,15 @@ export {
Lazyload,
Loading,
NoticeBar,
OrderCoupon,
OrderCouponList,
OrderGoods,
Panel,
PayOrder,
Picker,
Popup,
Progress,
PullRefresh,
Quantity,
Radio,
RadioGroup,

View File

@ -0,0 +1,71 @@
<template>
<div :class="['van-order-coupon-coupon', { 'van-order-coupon-coupon--disabled': disabled }]">
<div class="van-order-coupon-coupon__head">
<div class="van-order-coupon-coupon__lines"></div>
<div class="van-order-coupon-coupon__gradient">
<h2 v-html="faceAmount" />
<p>{{ conditionMessage }}</p>
</div>
</div>
<div class="van-order-coupon-coupon__body">
<h2>{{ data.name }}</h2>
<span>{{ validPeriod }}</span>
<p v-if="disabled && data.reason">{{ data.reason }}</p>
<div class="van-order-coupon-coupon__corner" v-if="chosen">
<van-icon name="success" />
</div>
</div>
</div>
</template>
<script>
import Icon from '../icon';
export default {
name: 'van-order-coupon-coupon',
components: {
[Icon.name]: Icon
},
props: {
data: Object,
chosen: Boolean,
disabled: Boolean
},
computed: {
validPeriod() {
return `${this.getDate(this.data.start_at)}-${this.getDate(this.data.end_at)}`;
},
faceAmount() {
return this.data.denominations !== 0
? `<span>¥</span> ${this.formatAmount(this.data.denominations)}`
: this.data.discount !== 0
? this.formatDiscount(this.data.discount)
: '';
},
conditionMessage() {
let condition = this.data.origin_condition;
condition = condition % 100 === 0 ? Math.round(condition / 100) : (condition / 100).toFixed(2);
return this.data.origin_condition === 0 ? '无使用门槛' : `${condition}元可用`;
}
},
methods: {
getDate(timeStamp) {
const date = new Date(timeStamp * 1000);
return `${date.getFullYear()}.${this.padZero(date.getMonth() + 1)}.${this.padZero(date.getDate())}`;
},
padZero(num) {
return (num < 10 ? '0' : '') + num;
},
formatDiscount(discount) {
return `${(discount / 10).toFixed(discount % 10 === 0 ? 0 : 1)}`;
},
formatAmount(amount) {
return (amount / 100).toFixed(amount % 100 === 0 ? 0 : amount % 10 === 0 ? 1 : 2);
}
}
};
</script>

View File

@ -0,0 +1,153 @@
<template>
<van-popup v-model="showPopup" position="bottom" class="van-order-coupon-list">
<van-cell-group class="van-order-coupon-list__top">
<van-field v-model="exchangeCode" :placeholder="inputPlaceholder" :maxlength="20" />
<van-button size="small" type="danger" class="van-order-coupon-list__exchange" :disabled="exchangeButtonDisabled || !exchangeCode.length" @click="onClickExchangeButton">{{ exchangeButtonText }}</van-button>
</van-cell-group>
<div class="van-order-coupon-list__list" ref="list">
<van-order-coupon-coupon
ref="card"
v-for="(item, index) in coupons"
:key="item.id || item.name"
:data="item"
:chosen="index === chosenCoupon"
@click.native="onClickCoupon(index)"
/>
<h3 v-if="disabledCoupons.length">{{ disabledListTitle }}</h3>
<van-order-coupon-coupon
disabled
v-for="item in disabledCoupons"
:key="item.id || item.name"
:data="item"
/>
</div>
<div class="van-order-coupon-list__close van-hairline--top" @click="onClickNotUse">{{ closeButtonText }}</div>
</van-popup>
</template>
<script>
import Cell from '../cell';
import CellGroup from '../cell-group';
import Coupon from './Coupon';
import Field from '../field';
import Popup from '../popup';
import Button from '../button';
export default {
name: 'van-order-coupon-list',
components: {
[Button.name]: Button,
[Cell.name]: Cell,
[CellGroup.name]: CellGroup,
[Field.name]: Field,
[Popup.name]: Popup,
[Coupon.name]: Coupon
},
model: {
prop: 'show'
},
props: {
show: {
type: Boolean,
default: false
},
chosenCoupon: {
type: Number,
default: -1
},
coupons: {
type: Array,
default: () => []
},
disabledCoupons: {
type: Array,
default: () => []
},
exchangeButtonText: {
type: String,
default: '兑换'
},
exchangeButtonDisabled: {
type: Boolean,
default: false
},
displayedCouponIndex: {
type: Number,
default: -1
},
closeButtonText: {
type: String,
default: '不使用优惠'
},
disabledListTitle: {
type: String,
default: '不可用优惠'
},
inputPlaceholder: {
type: String,
default: '请输入优惠码'
}
},
watch: {
show(val) {
this.showPopup = val;
},
showPopup(val) {
this.$emit('input', val);
this.scrollToTop();
},
displayedCouponIndex(val) {
this.scrollToShowCoupon(val);
}
},
data() {
return {
exchangeCode: '',
showPopup: this.show
};
},
mounted() {
this.scrollToShowCoupon(this.displayedCouponIndex);
},
methods: {
onClickNotUse() {
this.showPopup = false;
this.$emit('change', -1);
},
onClickCoupon(index) {
this.showPopup = false;
this.$emit('change', index);
},
onClickExchangeButton() {
this.$emit('exchange', this.exchangeCode);
this.exchangeCode = '';
},
//
scrollToShowCoupon(index) {
if (index === -1) {
return;
}
this.$nextTick(() => {
const { card, list } = this.$refs;
if (list && card && card[index]) {
list.scrollTop = card[index].$el.offsetTop - 100;
}
});
},
scrollToTop() {
const { list } = this.$refs;
list.scrollTop = 0;
}
}
};
</script>

View File

@ -0,0 +1,56 @@
<template>
<div class="van-order-coupon">
<van-cell-group>
<van-cell title="优惠" :isLink="editable" @click="$emit('click')">
<div v-if="coupons[chosenCoupon]">
<h2>{{ amount }}</h2>
<span>{{ coupons[chosenCoupon].condition }}</span>
</div>
<template v-else>{{ guide }}</template>
</van-cell>
</van-cell-group>
</div>
</template>
<script>
import Cell from '../cell';
import CellGroup from '../cell-group';
export default {
name: 'van-order-coupon',
components: {
[Cell.name]: Cell,
[CellGroup.name]: CellGroup
},
model: {
prop: 'chosenCoupon'
},
props: {
coupons: {
type: Array,
default: () => []
},
chosenCoupon: {
type: Number,
default: -1
},
editable: {
type: Boolean,
default: true
}
},
computed: {
guide() {
return this.coupons.length === 0 ? '使用优惠' : `您有 ${this.coupons.length} 个可用优惠`;
},
amount() {
const coupon = this.coupons[this.chosenCoupon];
return `${coupon.name} 省¥${(coupon.value / 100).toFixed(2)}`;
}
}
};
</script>

View File

@ -1,5 +1,5 @@
<template>
<div class="van-order-goods-card">
<div class="van-order-goods-card van-hairline">
<van-card>
<div slot="thumb">
<img :src="data.img_url" />
@ -29,11 +29,11 @@
</div>
</template>
</van-card>
<van-cell class="van-order-goods-card__delivery" v-if="data.show_delivery_time" title="发货时间" :value="data.delivery_time" />
<van-cell class="van-order-goods-card__delivery van-hairline--top" v-if="data.show_delivery_time" title="发货时间" :value="data.delivery_time" />
<van-popup v-if="hasMessage" class="van-order-goods-card__message" v-model="showMessage" position="right">
<h2>备注信息</h2>
<ul>
<li v-for="(value, key) in data.message">
<li v-for="(value, key) in data.message" class="van-hairline">
<label>{{ key }}</label>
<a v-if="isURL(value)" :href="value">
<img :src="value" />

View File

@ -1,5 +1,5 @@
<template>
<div class="van-order-goods-empty">
<div class="van-order-goods-empty van-hairline--top">
<img :src="icon" />
<p>{{ message }}</p>
<van-button @click="$emit('clickEmptyButton')">{{ buttonText }}</van-button>

View File

@ -1,6 +1,6 @@
<template>
<div class="van-panel">
<div class="van-panel__header">
<div class="van-panel van-hairline--top-bottom">
<div class="van-panel__header van-hairline--bottom">
<slot name="header">
<h4 class="van-panel__title" v-text="title"></h4>
<span class="van-panel__desc" v-if="desc" v-text="desc"></span>
@ -10,7 +10,7 @@
<div class="van-panel__content">
<slot></slot>
</div>
<div class="van-panel__footer" v-if="$slots.footer">
<div class="van-panel__footer van-hairline--top" v-if="$slots.footer">
<slot name="footer"></slot>
</div>
</div>
@ -20,8 +20,8 @@
export default {
name: 'van-panel',
props: {
title: String,
desc: String,
title: String,
status: String
}
};

View File

@ -1,6 +1,8 @@
<template>
<div class="van-pay-order">
<div class="van-pay-order__tip" v-show="tip || hasTipSlot">{{ tip }}<slot name="tip" /></div>
<div class="van-pay-order__tip" v-show="tip || $slots.tip">
<slot name="tip">{{ tip }}</slot>
</div>
<div class="van-pay-order__bar">
<div class="van-pay-order__price">
<template v-if="hasPrice">
@ -49,9 +51,6 @@ export default {
priceDecimal() {
const decimal = this.price % 100;
return (decimal < 10 ? '0' : '') + decimal;
},
hasTipSlot () {
return !!this.$slots['tip']
}
},

View File

@ -1,6 +1,6 @@
<template>
<div class="van-picker">
<div class="van-picker__toolbar" v-show="showToolbar">
<div class="van-picker__toolbar van-hairline--top-bottom" v-show="showToolbar">
<slot>
<a href="javascript:void(0)" class="van-picker__cancel" @click="handlePickerCancel">取消</a>
<a href="javascript:void(0)" class="van-picker__confirm" @click="handlePickerConfirm">完成</a>

View File

@ -0,0 +1,176 @@
<template>
<div
class="van-pull-refresh"
:style="style"
@touchstart="onTouchStart"
@touchmove="onTouchMove"
@touchend="onTouchEnd"
@touchcalcel="onTouchEnd"
>
<div class="van-pull-refresh__head">
<slot name="normal" v-if="status === 'normal'"></slot>
<slot name="pulling" v-if="status === 'pulling'">
<span class="van-pull-refresh__text">{{ pullingText }}</span>
</slot>
<slot name="loosing" v-if="status === 'loosing'">
<span class="van-pull-refresh__text">{{ loosingText }}</span>
</slot>
<slot name="loading" v-if="status === 'loading'">
<div class="van-pull-refresh__loading">
<van-loading />
<span>{{ loadingText }}</span>
</div>
</slot>
</div>
<slot></slot>
</div>
</template>
<script>
import Loading from '../loading';
export default {
name: 'van-pull-refresh',
props: {
value: {
type: Boolean,
required: true
},
pullingText: {
type: String,
default: '下拉即可刷新...'
},
loosingText: {
type: String,
default: '释放即可刷新...'
},
loadingText: {
type: String,
default: '加载中...'
},
animationDuration: {
type: Number,
default: 300
},
headHeight: {
type: Number,
default: 50
}
},
components: {
[Loading.name]: Loading
},
data() {
return {
status: 'normal',
height: 0,
duration: 0
};
},
computed: {
style() {
return {
transition: `${this.duration}ms`,
transform: `translate3d(0,${this.height}px, 0)`
};
}
},
watch: {
value(val) {
if (!val) {
this.duration = this.animationDuration;
this.getStatus(0);
}
}
},
methods: {
onTouchStart(event) {
if (this.status === 'loading') {
return;
}
if (this.getCeiling()) {
this.duration = 0;
this.startX = event.touches[0].clientX;
this.startY = event.touches[0].clientY;
}
},
onTouchMove(event) {
if (this.status === 'loading') {
return;
}
this.deltaY = event.touches[0].clientY - this.startY;
this.direction = this.getDirection(event.touches[0]);
if (!this.ceiling && this.getCeiling()) {
this.duration = 0;
this.startY = event.touches[0].clientY;
this.deltaY = 0;
}
if (this.ceiling && this.deltaY >= 0) {
if (this.direction === 'vertical') {
event.preventDefault();
}
this.getStatus(this.ease(this.deltaY));
}
},
onTouchEnd() {
if (this.status === 'loading') {
return;
}
if (this.ceiling && this.deltaY) {
this.duration = this.animationDuration;
if (this.status === 'loosing') {
this.getStatus(this.headHeight, true);
this.$emit('input', true);
} else {
this.getStatus(0);
}
}
},
getCeiling() {
this.ceiling = (window.scrollY || window.pageYOffset) === 0;
return this.ceiling;
},
ease(height) {
const { headHeight } = this;
return height < headHeight
? height
: height < headHeight * 2
? Math.round(headHeight + (height - headHeight) / 2)
: Math.round(headHeight * 1.5 + (height - headHeight * 2) / 4);
},
getStatus(height, isLoading) {
this.height = height;
const status = isLoading
? 'loading' : height === 0
? 'normal' : height < this.headHeight
? 'pulling' : 'loosing';
if (status !== this.status) {
this.status = status;
}
},
getDirection(touch) {
const distanceX = Math.abs(touch.clientX - this.startX);
const distanceY = Math.abs(touch.clientY - this.startY);
return distanceX > distanceY ? 'horizontal' : distanceX < distanceY ? 'vertical' : '';
}
}
};
</script>

View File

@ -1,5 +1,5 @@
<template>
<div class="van-step" :class="stepClass">
<div class="van-step van-hairline" :class="stepClass">
<div class="van-step__circle-container">
<i class="van-step__circle" v-if="status !== 'process'"></i>
<i class="van-icon van-icon-checked" :style="{ color: $parent.activeColor }" v-else></i>

View File

@ -16,8 +16,8 @@
</slot>
</div>
<div class="van-steps__items" :class="{
'van-steps__items--alone': !title && !description
}">
'van-steps__items--alone': !title && !description
}">
<slot></slot>
</div>
</div>
@ -60,11 +60,11 @@ export default {
computed: {
stepsClass() {
const direction = this.direction;
const lengthClass = `van-steps--${this.steps.length}`;
const directionClass = `van-steps--${direction}`;
return direction === 'horizontal' ? [lengthClass, directionClass] : [directionClass];
return [
`van-steps--${this.direction}`, {
[`van-steps--${this.steps.length}`]: this.direction === 'horizontal'
}
];
}
}
};

View File

@ -1,7 +1,7 @@
<template>
<div class="van-switch" :class="switchStates" @click="toggleState">
<div class="van-switch__node">
<van-loading v-if="loading" class="van-switch__loading"></van-loading>
<div class="van-switch" :class="[`van-switch--${checked ? 'on' : 'off'}`, { 'van-switch--disabled': disabled }]" @click="toggleState">
<div class="van-switch__node van-hairline-surround">
<van-loading v-if="loading" class="van-switch__loading" />
</div>
<div class="van-switch__bg"></div>
</div>
@ -35,17 +35,6 @@ export default {
this.checked = val;
}
},
computed: {
switchStates: function() {
const switchStates = ['van-switch--' + (this.checked ? 'on' : 'off')];
if (this.disabled) {
switchStates.push('van-switch--disabled');
}
return switchStates;
}
},
methods: {
/*
* 开关状态交互

View File

@ -7,7 +7,7 @@
<div
v-for="(tab, index) in tabs"
:key="index"
class="van-tab"
class="van-tab van-hairline"
:class="{'van-tab--active': index === curActive}"
ref="tabkey"
@click="handleTabClick(index, tab)"
@ -26,7 +26,7 @@
<div
v-for="(tab, index) in tabs"
:key="index"
class="van-tab"
class="van-tab van-hairline"
:class="{'van-tab--active': index === curActive}"
ref="tabkey"
@click="handleTabClick(index, tab)"

View File

@ -1,5 +1,5 @@
<template>
<span :class="['van-tag', { [`van-tag--${type}`]: type, 'is-plain': plain, 'is-mark': mark }]">
<span :class="['van-tag', 'van-hairline--surround', { [`van-tag--${type}`]: type, 'is-plain': plain, 'is-mark': mark }]">
<slot></slot>
</span>
</template>

View File

@ -1,81 +1,57 @@
import Vue from 'vue';
import ToastComponent from './toast';
import VueToast from './toast';
const ToastConstructor = Vue.extend(ToastComponent);
let instance;
const getInstance = () => {
if (instance) instance.clear();
instance = new ToastConstructor({
el: document.createElement('div')
});
return instance;
};
const removeDom = event => {
/* istanbul ignore else */
if (event.target.parentNode) {
event.target.parentNode.removeChild(event.target);
const defaultOptions = {
visible: true,
type: 'text',
duration: 3000,
forbidClick: false,
clear: () => {
instance.visible = false;
}
};
var Toast = (options = {}) => {
const duration = options.duration || 3000;
const createInstance = () => {
if (!instance) {
const ToastConstructor = Vue.extend(VueToast);
instance = new ToastConstructor({
el: document.createElement('div')
});
document.body.appendChild(instance.$el);
}
};
const instance = getInstance();
const Toast = (options = {}) => {
createInstance();
options = typeof options === 'string' ? { message: options } : options;
options = { ...defaultOptions, ...options };
Object.assign(instance, options);
instance.closed = false;
clearTimeout(instance.timer);
instance.type = options.type ? options.type : 'text';
instance.message = typeof options === 'string' ? options : options.message;
instance.forbidClick = options.forbidClick ? options.forbidClick : false;
instance.clear = () => {
if (instance.closed) return;
instance.visible = false;
instance.$el.addEventListener('transitionend', removeDom);
instance.closed = true;
};
document.body.appendChild(instance.$el);
Vue.nextTick(function() {
instance.visible = true;
instance.$el.removeEventListener('transitionend', removeDom);
instance.timer = setTimeout(function() {
if (options.duration !== 0) {
instance.timer = setTimeout(() => {
instance.clear();
}, duration);
});
}, options.duration);
}
return instance;
};
Toast.loading = (options) => {
return new Toast({
type: 'loading',
...options
});
};
Toast.success = (options) => {
const message = typeof options === 'string' ? options : options.message;
return new Toast({
type: 'success',
message: message,
...options
});
};
Toast.fail = (options) => {
const message = typeof options === 'string' ? options : options.message;
return new Toast({
type: 'fail',
message: message,
...options
});
};
const createMethod = type => (options = {}) => Toast({
type,
message: typeof options === 'string' ? options : options.message,
...options
});
Toast.loading = createMethod('loading');
Toast.success = createMethod('success');
Toast.fail = createMethod('fail');
Toast.clear = () => {
/* istanbul ignore else */
if (instance) instance.clear();
instance && instance.clear();
};
export default Toast;

View File

@ -2,19 +2,18 @@
<transition name="van-toast-fade">
<div class="van-toast-wrapper" v-show="visible">
<div :class="['van-toast', 'van-toast--' + displayStyle]">
<!-- 只显示文字 -->
<!-- text only -->
<div v-if="displayStyle === 'text'" class="van-toast__text">{{ message }}</div>
<!-- 加载中 -->
<van-loading v-if="displayStyle === 'loading' && type === 'loading'" type="gradient-circle" color="white"></van-loading>
<!-- 图案加文字 -->
<div v-if="displayStyle === 'html'" class="van-toast__text" v-html="message" />
<!-- with icon -->
<template v-if="displayStyle === 'default'">
<van-icon class="van-toast__icon" :name="type"></van-icon>
<div class="van-toast__text">{{ message }}</div>
<van-loading v-if="type === 'loading'" color="white" />
<van-icon v-else class="van-toast__icon" :name="type" />
<div v-if="message" class="van-toast__text">{{ message }}</div>
</template>
<!-- 传入html -->
<div v-if="displayStyle === 'html'" class="van-toast__text" v-html="message"></div>
</div>
<div class="van-toast__overlay" v-if="forbidClick"></div>
<div class="van-toast__overlay" v-if="forbidClick" />
</div>
</transition>
</template>
@ -24,15 +23,8 @@ import Icon from '../icon';
import Loading from '../loading';
const TOAST_TYPES = ['text', 'html', 'loading', 'success', 'fail'];
const DEFAULT_STYLE_LIST = ['success', 'fail'];
/**
* van-toast
* @module components/toast
* @desc toast
* @param {string} [type=false] - 类型
* @param {string} [message] - 信息
*
*/
const DEFAULT_STYLE_LIST = ['success', 'fail', 'loading'];
export default {
name: 'van-toast',
@ -40,13 +32,12 @@ export default {
[Icon.name]: Icon,
[Loading.name]: Loading
},
props: {
type: {
type: String,
default: 'text',
validator(value) {
return TOAST_TYPES.indexOf(value) > -1;
}
validator: value => TOAST_TYPES.indexOf(value) > -1
},
message: {
type: String,
@ -57,14 +48,16 @@ export default {
default: false
}
},
data() {
return {
visible: false
};
},
computed: {
displayStyle() {
return DEFAULT_STYLE_LIST.indexOf(this.type) > -1 ? 'default' : this.type;
return DEFAULT_STYLE_LIST.indexOf(this.type) !== -1 ? 'default' : this.type;
}
}
};

View File

@ -1,6 +1,6 @@
{
"name": "vant-css",
"version": "0.8.9",
"version": "0.9.1",
"description": "vant css.",
"main": "lib/index.css",
"style": "lib/index.css",

View File

@ -1,19 +1,16 @@
@import './common/var.css';
@import './mixins/border_retina.css';
@import './popup.css';
.van-actionsheet {
position: fixed;
left: 0;
right: 0;
bottom: 0;
color: $c-black;
color: $text-color;
transition: .2s ease-out;
background-color: #e0e0e0;
backface-visibility: hidden;
background-color: $background-color;
&--withtitle {
background-color: $c-white;
background-color: $white;
}
&__item {
@ -21,17 +18,16 @@
line-height: 50px;
font-size: 16px;
text-align: center;
position: relative;
background-color: $c-white;
background-color: $white;
&::after {
@mixin border-retina (top);
&:active {
background-color: $active-color;
}
}
&__subname {
font-size: 12px;
color: $c-gray-darker;
color: $gray-darker;
}
&__loading {
@ -39,17 +35,12 @@
}
&__cancel {
margin-top: 5px;
margin-top: 10px;
}
&__header {
line-height: 44px;
text-align: center;
position: relative;
&::after {
@mixin border-retina (top, bottom);
}
.van-icon-close {
top: 11px;

View File

@ -1,49 +1,34 @@
@import './common/var.css';
@import './mixins/border_retina.css';
.van-badge {
display: block;
overflow: hidden;
position: relative;
padding: 20px 12px;
box-sizing: border-box;
line-height: 1.4;
background-color: $c-background;
color: $c-gray-darker;
font-size: 14px;
text-decoration: none;
line-height: 1.4;
box-sizing: border-box;
padding: 20px 12px 20px 9px;
color: $gray-darker;
background-color: $background-color;
word-break: break-all;
border-left: 3px solid transparent;
&:not(:last-child)::after {
border-bottom-width: 1px;
}
&-group {
position: relative;
width: 85px;
&::after {
@mixin border-retina (top);
}
}
&--select {
font-weight: bold;
color: $c-black;
background-color: $c-white;
.van-badge__active {
display: block;
}
&::after {
@mixin border-retina (top, right, left);
}
}
color: $text-color;
border-color: $red;
background-color: $white;
&__active {
display: none;
position: absolute;
left: 0;
top: 0;
width: 3px;
height: 100%;
background-color: #FF4444;
&::after {
border-right-width: 1px;
}
}
&__info {
@ -51,25 +36,14 @@
top: 2px;
right: 2px;
font-size: 10px;
transform:scale(0.8);
color: $white;
transform: scale(0.8);
text-align: center;
box-sizing: border-box;
padding: 0 6px;
min-width: 18px;
height: 18px;
line-height: 18px;
border-radius: 9px;
background-color: #FF4444;
color: $c-white;
}
&::after {
@mixin border-retina (bottom);
}
&:last-child {
&::after {
border-bottom: 0;
}
background-color: $red;
}
}

View File

@ -2,4 +2,7 @@
* 基本样式入口
*/
@import './reset.css';
@import "./common/var.css";
@import "./common/normalize.css";
@import "./common/hairline.css";

View File

@ -10,10 +10,9 @@
box-sizing: border-box;
font-size: 16px;
text-align: center;
outline: 0;
-webkit-appearance: none;
&::after {
&::before {
content: " ";
position: absolute;
top: 0;
@ -21,11 +20,11 @@
right: 0;
bottom: 0;
opacity: 0;
background-color: #000;
background-color: $black;
border-radius: inherit; /* inherit parent's border radius */
}
&:not(.is-disabled):active::after {
&:not(.is-disabled):active::before {
opacity: .3;
}
@ -39,7 +38,7 @@
border: 1px solid $button-default-border-color;
&:active {
color: $c-gray-dark;
color: $gray-dark;
}
}
@ -73,6 +72,12 @@
font-size: 12px;
}
&--loading {
.van-button__text {
display: none;
}
}
/* mini图标默认宽度50px文字不能超过4个 */
&--mini {
display: inline-block;
@ -108,7 +113,7 @@
background-color: $bottom-action-button-default-background-color;
&:active {
color: #fff;
color: $white;
}
&.van-button--primary {

View File

@ -1,7 +1,8 @@
@import './common/var.css';
@import './mixins/ellipsis.css';
.van-card {
color: #333;
color: $text-color;
height: 90px;
background: #fafafa;
position: relative;
@ -58,7 +59,7 @@
}
&__desc {
color: #666;
color: $gray-darker;
font-size: 12px;
max-height: 20px;
@mixin multi-ellipsis 1;
@ -77,7 +78,7 @@
}
&__num {
color: #666;
color: $gray-darker;
font-size: 12px;
}

View File

@ -1,3 +1,5 @@
@import './common/var.css';
.van-cell-swipe {
overflow: hidden;
position: relative;

View File

@ -1,38 +1,23 @@
@import './common/var.css';
@import './mixins/border_retina.css';
@import './icon.css';
.van-cell {
width: 100%;
display: table;
position: relative;
padding: 10px 15px 10px 0;
box-sizing: border-box;
line-height: 24px;
background-color: $c-white;
color: $c-black;
background-color: $white;
color: $text-color;
font-size: 14px;
text-decoration: none;
overflow: hidden;
&::after {
@mixin border-retina (bottom);
}
&:last-child {
&::after {
border-bottom: 0;
}
&:not(:last-child)::after {
border-bottom-width: 1px;
}
&-group {
padding-left: 15px;
position: relative;
background-color: #fff;
&::after {
@mixin border-retina (top, bottom);
}
background-color: $white;
}
&__title {
@ -47,7 +32,7 @@
display: block;
font-size: 12px;
line-height: 1.2;
color: $c-gray-darker;
color: $gray-darker;
}
&__value {
@ -73,12 +58,7 @@
position: absolute;
left: -7px;
font-size: 14px;
color: #f44;
}
.van-cell__title {
float: none;
display: inline-block;
color: $red;
}
}
@ -87,7 +67,7 @@
top: 50%;
right: 15px;
transform: translateY(-50%);
color: $c-gray-dark;
color: $gray-dark;
font-size: 12px;
}
}

View File

@ -9,11 +9,11 @@
}
.van-icon-checked {
color: $c-green;
color: $green;
}
.van-icon-check {
color: $c-gray-dark;
color: $gray-dark;
}
&--disabled {
@ -27,7 +27,6 @@
height: 22px;
margin-right: 15px;
float: left;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
&__control {
@ -43,7 +42,6 @@
&__label {
line-height: 22px;
margin-left: 37px;
display: block;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
display: block;
}
}

View File

@ -1,3 +1,5 @@
@import './common/var.css';
.van-col {
float: left;
box-sizing: border-box;

View File

@ -0,0 +1,41 @@
@import "../mixins/border_retina.css";
.van-hairline {
&,
&--top,
&--left,
&--right,
&--bottom,
&--top-bottom,
&--surround {
position: relative;
&::after {
@mixin hairline;
}
}
&--top::after {
border-top-width: 1px;
}
&--left::after {
border-left-width: 1px;
}
&--right::after {
border-right-width: 1px;
}
&--bottom::after {
border-bottom-width: 1px;
}
&--top-bottom::after {
border-width: 1px 0;
}
&--surround::after {
border-width: 1px;
}
}

View File

@ -0,0 +1,27 @@
/**
* 基本样式入口
*/
html {
-webkit-tap-highlight-color: transparent;
}
a {
text-decoration: none;
}
a,
input,
button,
textarea {
&:focus {
outline: none;
}
}
ol,
ul {
margin: 0;
padding: 0;
list-style: none;
}

View File

@ -1,41 +1,37 @@
/* UI标准色 */
$c-white: #fff;
$c-black: #333;
$c-green: #06bf04;
$c-green-wx: #4b0;
$c-red: #ed5050;
$c-gray: #c9c9c9;
$c-gray-light: #e5e5e5;
$c-gray-darker: #666;
$c-gray-dark: #999;
$c-yellow: #f09000;
$c-yellow-light: #fcff00;
$c-orange: #f60;
$c-orange-dark: #f15a0c;
$c-blue: #38f;
$c-active: #e8e8e8;
/* color variables */
$black: #000;
$white: #fff;
$red: #f44;
$green: #06bf04;
$green-wx: #4b0;
$gray: #c9c9c9;
$gray-light: #e5e5e5;
$gray-darker: #666;
$gray-dark: #999;
$yellow: #f09000;
$orange: #f60;
$blue: #38f;
$c-background: #f8f8f8;
/* default colors */
$text-color: #333;
$border-color: #ccc;
$active-color: #e8e8e8;
$background-color: #f8f8f8;
/* 按钮颜色 */
$button-primary-color: $c-white;
$button-primary-background-color: $c-green-wx;
/* button */
$button-primary-color: $white;
$button-primary-background-color: $green-wx;
$button-primary-border-color: #0a0;
$button-default-color: $c-black;
$button-default-background-color: $c-white;
$button-default-border-color: #ccc;
$button-danger-color: $c-white;
$button-danger-background-color: #f44;
$button-default-color: $text-color;
$button-default-background-color: $white;
$button-default-border-color: $border-color;
$button-danger-color: $white;
$button-danger-background-color: $red;
$button-danger-border-color: #e33;
$button-disabled-color: $c-gray-dark;
$button-disabled-background-color: $c-gray-light;
$button-disabled-color: $gray-dark;
$button-disabled-background-color: $gray-light;
$button-disabled-border-color: #cacaca;
$bottom-action-button-default-color: $c-white;
$bottom-action-button-default-color: $white;
$bottom-action-button-default-background-color: #f85;
$bottom-action-button-primary-color: $c-white;
$bottom-action-button-primary-background-color: #f44;
$bottom-action-button-primary-color: $white;
$bottom-action-button-primary-background-color: $red;

View File

@ -9,24 +9,23 @@
&__nav {
width: 143px;
/*float: left;*/
position: absolute;
left: 0;
top: 0;
bottom: 0;
overflow: scroll;
background-color: $c-white;
background-color: $white;
-webkit-overflow-scrolling: touch;
}
&__nitem {
line-height: 44px;
padding: 0 15px;
background-color: $c-white;
background-color: $white;
@mixin multi-ellipsis 1;
&--active {
background-color: $c-background;
background-color: $background-color;
}
}
@ -52,7 +51,7 @@
&__selected {
float: right;
position: absolute;
right: 0px;
right: 0;
top: 0;
bottom: 0;
}

View File

@ -1,5 +1,4 @@
@import './mixins/border_retina.css';
@import './popup.css';
@import './common/var.css';
.van-dialog {
position: fixed;
@ -10,11 +9,9 @@
overflow: hidden;
transition: .2s;
border-radius: 4px;
background-color: #fff;
backface-visibility: hidden;
background-color: $white;
transform: translate3d(-50%, -50%, 0);
&__header {
padding: 15px 0 0;
text-align: center;
@ -22,10 +19,9 @@
&__content {
padding: 15px 20px;
position: relative;
&::after {
@mixin border-retina (bottom);
border-bottom-width: 1px;
}
}
@ -33,7 +29,7 @@
line-height: 1.5;
&--withtitle {
color: #999;
color: $gray-dark;
font-size: 14px;
}
}
@ -47,15 +43,6 @@
.van-button {
flex: 1;
}
.van-dialog__cancel {
position: relative;
&::before {
@mixin border-retina (right);
left: -2px;
}
}
}
}

View File

@ -1,9 +1,11 @@
@import './common/var.css';
.van-express-way {
padding: 0;
&__fee,
&__type {
color: #666;
color: $gray-darker;
line-height: 1.5;
}
@ -35,7 +37,7 @@
padding-left: 30px;
p {
color: #999;
color: $gray-dark;
font-size: 12px;
line-height: 16px;
}
@ -52,7 +54,7 @@
}
&__warn {
color: #f09000;
color: $yellow;
}
}
}

View File

@ -1,7 +1,4 @@
@import './common/var.css';
@import './mixins/border_retina.css';
@import './cell.css';
@import './icon.css';
.van-field {
@ -44,7 +41,7 @@
&--disabled {
.van-field__control {
color: $c-gray-dark;
color: $gray-dark;
}
}
@ -52,7 +49,7 @@
.van-field__control {
&,
&::placeholder {
color: $c-red;
color: $red;
}
}
}
@ -64,17 +61,12 @@
&::after {
border-radius: 2px;
@mixin border-retina (top, right, bottom, left);
}
&:last-child::after {
@mixin border-retina (bottom);
}
}
&--autosize {
.van-field__control {
min-height: 0px;
min-height: 0;
}
}
@ -93,7 +85,6 @@
display: block;
width: 100%;
resize: none;
outline: 0;
}
&__icon {

View File

@ -1,5 +1,4 @@
@import './common/var.css';
@import './mixins/border_retina.css';
.van-goods-action {
left: 0;
@ -13,29 +12,26 @@
}
&__mini-btn {
color: #666;
color: $gray-darker;
display: flex;
height: 50px;
font-size: 10px;
min-width: 15%;
position: relative;
text-align: center;
background-color: #fff;
background-color: $white;
flex-direction: column;
justify-content: center;
&::after {
@mixin border-retina (top, left), #cacaca;
border-width: 1px 0 0 1px;
}
&:first-child {
&::after {
border-left-width: 0;
}
&:first-child::after {
border-left-width: 0;
}
&:active {
background-color: $c-active;
background-color: $active-color;
}
}

View File

@ -1,4 +1,4 @@
@import './swipe.css';
@import './common/var.css';
.van-image-preview {
position: fixed;
@ -9,7 +9,6 @@
overflow: auto;
&__image {
display: block;
position: absolute;
left: 0;

View File

@ -1,40 +1,53 @@
/**
css组件库入口组装成css组件库
* style entry
*/
/* base */
@import './base.css';
@import './reset.css';
/* common components */
@import './col.css';
@import './row.css';
@import './badge.css';
@import './button.css';
@import './cell.css';
@import './cell-swipe.css';
@import './card.css';
@import './deep-select.css';
@import './dialog.css';
@import './field.css';
@import './icon.css';
@import './loading.css';
@import './picker.css';
@import './popup.css';
@import './radio.css';
@import './switch.css';
@import './badge.css';
@import './search.css';
@import './panel.css';
@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';
@import './toast.css';
@import './uploader.css';
@import './swipe.css';
@import './notice-bar.css';
@import './switch-cell.css';
/* form components */
@import './checkbox.css';
@import './field.css';
@import './radio.css';
@import './switch.css';
@import './uploader.css';
/* action components */
@import './actionsheet.css';
@import './dialog.css';
@import './picker.css';
@import './pull-refresh.css';
@import './toast.css';
/* business components */
@import './deep-select.css';
@import './express-way.css';
@import './pay-order.css';
@import './order-goods.css';
@import './invalid-goods.css';
@import './goods-action.css';
@import './invalid-goods.css';
@import './notice-bar.css';
@import './order-coupon.css';
@import './order-goods.css';
@import './pay-order.css';
@import './switch-cell.css';

View File

@ -1,3 +1,4 @@
@import './common/var.css';
@import "./mixins/ellipsis.css";
$van-invalid-goods-photo-size: 90px;
@ -7,7 +8,7 @@ $van-invalid-goods-photo-size: 90px;
margin: 10px 0;
&__title {
color: #999;
color: $gray-dark;
font-size: 12px;
text-align: center;
margin-bottom: 10px;
@ -42,11 +43,11 @@ $van-invalid-goods-photo-size: 90px;
top: 0;
right: 0;
width: 80px;
color: #666;
color: $gray-darker;
font-size: 14px;
padding-right: 8px;
line-height: calc($van-invalid-goods-photo-size + 10px);
background-color: #fff;
background-color: $white;
text-align: right;
span {
@ -62,7 +63,7 @@ $van-invalid-goods-photo-size: 90px;
}
&-invalid-goods-card {
color: #999;
color: $gray-dark;
margin: 10px 0;
padding: 5px 10px;
background-color: #fafafa;
@ -73,7 +74,7 @@ $van-invalid-goods-photo-size: 90px;
left: 0;
top: 70px;
width: $van-invalid-goods-photo-size;
color: #fff;
color: $white;
font-size: 12px;
line-height: 20px;
text-align: center;
@ -108,14 +109,14 @@ $van-invalid-goods-photo-size: 90px;
}
&__desc {
color: #f60;
color: $orange;
font-size: 12px;
margin-top: 5px;
}
}
.van-icon-arrow {
color: #666;
color: $gray-darker;
font-size: 10px;
}
}

View File

@ -36,8 +36,8 @@
box-sizing: border-box;
&.van-loading__spinner--black {
border-color: $c-gray;
border-top-color: $c-gray-darker;
border-color: $gray;
border-top-color: $gray-darker;
}
&.van-loading__spinner--white {

View File

@ -1,20 +1,34 @@
@import '../common/var.css';
$border-poses: top, right, bottom, left;
@define-mixin border-retina $poses: $border-poses, $border-retina-color: #e5e5e5 {
@define-mixin border-retina $poses: $border-poses, $border-retina-color: $gray-light {
content: '';
position: absolute;
top: 0;
left: 0;
box-sizing: border-box;
width: 200%;
height: 200%;
transform: scale(.5);
transform-origin: left top;
-webkit-perspective: 1000;
-webkit-backface-visibility: hidden;
transform-origin: 0 0;
pointer-events: none;
box-sizing: border-box;
@each $pos in $poses {
border-$(pos): 1px solid $border-retina-color;
}
}
@define-mixin hairline $border-retina-color: $gray-light {
content: '';
position: absolute;
top: 0;
left: 0;
width: 200%;
height: 200%;
transform: scale(.5);
transform-origin: 0 0;
pointer-events: none;
box-sizing: border-box;
border: 0 solid $border-retina-color;
}

Some files were not shown because too many files have changed in this diff Show More