WangShuXian6 / blog

FE-BLOG
https://wangshuxian6.github.io/blog/
MIT License
45 stars 10 forks source link

WePY开发微信小程序 #9

Open WangShuXian6 opened 6 years ago

WangShuXian6 commented 6 years ago

安装

npm install wepy-cli -g
wepy init standard my-project

更新

wepy upgrade

初始化项目后的注意事项:

关闭ES6转ES5,由WePY自动处理 关闭样式自动补全,由WePY自动处理 关闭代码压缩

安装util

否则可能报错 module "npm/lodash/_nodeUtil.js" is not defined

npm i util --save-dev

安装wepy-compiler-typescript

https://www.npmjs.com/package/wepy-compiler-typescript

npm install wepy-compiler-typescript --save-dev
<script lang="typescript" src ="./index.ts"></script>

安装less autoprefix

npm install less-plugin-autoprefix --save-dev

wepy.config.js


const LessPluginAutoPrefix = require('less-plugin-autoprefix');

//... //...

compilers: { less: { compress: true, plugins: [new LessPluginAutoPrefix({browsers: ['Android >= 2.3', 'Chrome > 20', 'iOS >= 6']})] }

#### wepy-async-function

npm install wepy-async-function --save

>
>wepy.config.js
```javascript
babel: {
            "presets": [
                "env"
            ],
            "plugins": [
                "transform-export-extensions",
                "syntax-export-extensions"
            ]
        }

app.wpy


import 'wepy-async-function'

export default class extends wepy.app {

constructor () {
    super();
    this.use('promisify');
}

}

wepy build --no-cache

>
#### promise-polyfill

npm install promise-polyfill --save

>app.wpy
```vue
import Promise from 'promise-polyfill'

export default class extends wepy.app {

    constructor () {
        super();
        this.use('promisify');
    }

}

详细说明 https://github.com/Tencent/wepy/wiki/升级指南

wepy 文件压缩插件

https://github.com/Tencent/wepy/tree/master/packages/wepy-plugin-filemin 支持css,xml,json的压缩

安装 npm install wepy-plugin-filemin --save-dev 配置wepy.config.js

module.exports.plugins = {
'filemin': {
filter: /\.(json|wxml|xml)$/
}
};

wepy生产文件去注释

配置wepy.config.js

module.exports.plugins = {
uglifyjs: {
filter: /\.js$/,
config: {
comments: false // 去注释
}
},
imagemin: {
filter: /\.(jpg|png|jpeg)$/,
config: {
jpg: {
quality: 80
},
png: {
quality: 80
}
}
},
'filemin': {
filter: /\.(json|wxml|xml)$/
}
}

快速开始配置

package.json


{
"name": "news",
"version": "0.0.2",
"description": "A WePY project",
"main": "dist/app.js",
"scripts": {
"dev": "wepy build --watch",
"build": "cross-env NODE_ENV=production wepy build --no-cache",
"dev:web": "wepy build --output web",
"clean": "find ./dist -maxdepth 1 -not -name 'project.config.json' -not -name 'dist' | xargs rm -rf",
"test": "echo \"Error: no test specified\" && exit 1"
},
"wepy": {
"module-a": false,
"./src/components/list": "./src/components/wepy-list.wpy"
},
"author": "王树贤 <airmusic@msn.com>",
"license": "MIT",
"dependencies": {
"crypto-js": "^3.1.9-1",
"promise-polyfill": "^8.0.0",
"redux": "^3.7.2",
"redux-actions": "^2.2.1",
"redux-promise": "^0.5.3",
"wepy-redux": "^1.5.3",
"wepy": "^1.6.0",
"wepy-async-function": "^1.4.4",
"wepy-com-toast": "^1.0.2"
},
"devDependencies": {
"babel-eslint": "^7.2.1",
"babel-plugin-transform-class-properties": "^6.24.1",
"babel-plugin-transform-decorators-legacy": "^1.3.4",
"babel-plugin-transform-export-extensions": "^6.22.0",
"babel-plugin-transform-object-rest-spread": "^6.26.0",
"babel-preset-env": "^1.6.1",
"cross-env": "^5.1.3",
"eslint": "^3.18.0",
"eslint-config-standard": "^7.1.0",
"eslint-friendly-formatter": "^2.0.7",
"eslint-plugin-html": "^2.0.1",
"eslint-plugin-promise": "^3.5.0",
"eslint-plugin-standard": "^2.0.1",
"less-plugin-autoprefix": "^1.5.1",
"util": "^0.11.0",
"wepy-compiler-babel": "^1.5.1",
"wepy-compiler-less": "^1.3.10",
"wepy-compiler-typescript": "^1.5.9",
"wepy-eslint": "^1.5.3",
"wepy-plugin-imagemin": "^1.5.3",
"wepy-plugin-uglifyjs": "^1.3.7"
}
}
>wepy.config.js
```javascript
const path = require('path');
var prod = process.env.NODE_ENV === 'production';
const LessPluginAutoPrefix = require('less-plugin-autoprefix');

module.exports = {
  wpyExt: '.wpy',
  eslint: true,
  cliLogs: !prod,
  build: {
    web: {
      htmlTemplate: path.join('src', 'index.template.html'),
      htmlOutput: path.join('web', 'index.html'),
      jsOutput: path.join('web', 'index.js')
    }
  },
  resolve: {
    alias: {
      counter: path.join(__dirname, 'src/components/counter'),
      '@': path.join(__dirname, 'src')
    },
    aliasFields: ['wepy', 'weapp'],
    modules: ['node_modules']
  },
  compilers: {
    less: {
      compress: true,
      plugins: [new LessPluginAutoPrefix({browsers: ['Android >= 2.3', 'Chrome > 20', 'iOS >= 6']})]
    },
    /*sass: {
      outputStyle: 'compressed'
    },*/
    babel: {
      sourceMap: true,
      presets: [
        'env'
      ],
      plugins: [
        'transform-class-properties',
        'transform-decorators-legacy',
        'transform-object-rest-spread',
        'transform-export-extensions',
        "syntax-export-extensions",
      ]
    }
  },
  plugins: {
  },
  appConfig: {
    noPromiseAPI: ['createSelectorQuery']
  }
}

if (prod) {

  // 压缩sass
  // module.exports.compilers['sass'] = {outputStyle: 'compressed'}

  // 压缩js
  module.exports.plugins = {
    uglifyjs: {
      filter: /\.js$/,
      config: {
      }
    },
    imagemin: {
      filter: /\.(jpg|png|jpeg)$/,
      config: {
        jpg: {
          quality: 80
        },
        png: {
          quality: 80
        }
      }
    }
  }
}

app.wpy


<style lang="less">
.container {
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
box-sizing: border-box;
}
</style>

***

>wepy d.ts 类型申明
>https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/wepy/index.d.ts
```bash
npm install --save-dev @types/wepy
WangShuXian6 commented 6 years ago

错误解决

1.6.0 module "npm/lodash/_nodeUtil.js" is not defined

npm i lodash@4.17.5 --save
wepy build --no-cache
npm install autoprefixer --save-dev
npm install wepy-compiler-babel --save-dev

wepy命令失效 重新安装wepy-cli

WangShuXian6 commented 6 years ago

解析

事件中默认传入事件对象,如果手动传入参数,则事件接受一个数组,数组前面位为参数,末位为事件对象

<view @tap="removeFromCart({{pid}})">-</view>

removeFromCart(arg) arg为数组。


组件内事件传参 需要更新父页面以强制刷新子组件

<template>
<repeat for="{{cates}}" key="key" index="index" item="item">
<view class="cate-container" @tap="handleCategory({{index}})">
<cateCard :info="item" class="cate-wrapper " />
</view>
</repeat>
</template>

import wepy from 'wepy'
import {connect} from 'wepy-redux'

@connect({},{}) export default class Card extends wepy.component { methods = { handleCategory(index,e){ console.log('handleCategory-e--',e) console.log('handleCategory-index--',index) } } }


***
WangShuXian6 commented 6 years ago

状态和dispatch动作在js里的调用

混入

@connect({
header(state){
return state.header
}
},{
select:SELECT_PERSON
})

dispatch Action

this.methods.select(info)

状态

console.log(this.header)
WangShuXian6 commented 6 years ago

vscode 插件

wpy-beautify

WangShuXian6 commented 6 years ago

小程序特殊情况处理

页面数据不实时更新

this.$apply()

引用组件时wx-if属性无效 例

<template>
<switchTabLine wx-if="{{true}}" :switchTitleList.sync="switchTitleList" />
</template>

不应该在wepy中循环自定义组件, 应该在组件内循环从父组件获取的列表数据


<!-- 错误使用 -->
// list.wpy
<view>{{test.name}}</view>

// index.wpy

// list.wpy

{{item.name}}

// index.wpy



<hr>

>scroll外层元素为固定或绝对货粘性定位时,无法滚动
>将固定定位设置在scroll元素上即可解决

<hr>

>input 的父元素不可以是固定定位,会使input无法使用
WangShuXian6 commented 6 years ago

编辑器

VSCode

扩展插件 同vue

代码格式化插件 wpy-beautify 快捷键 windows :: cmd+shift+f mac::windows键盘:Alt+shift+f


WangShuXian6 commented 6 years ago

请求方式

需大写-有效值:OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT 注意:没有PATCH

requestGet() {
wepy
.request({
url: '',
method: 'GET',
data: {
test: 'test'
},
header: {
'Content-Type': 'Application/json;charset=UTF-8'
}
})
.then(response => {
console.log('GET api---', response.data);
})
.catch(error => {
console.log('GET api error---', error);
});
}
requestPost() {
wepy
.request({
url: '',
method: 'POST',
data: {
test: 'test'
},
header: {
'Content-Type': 'Application/json;charset=UTF-8'
}
})
.then(response => {
console.log('POST api---', response.data);
})
.catch(error => {
console.log('POST api error---', error);
});
}
requestPut() {
wepy
.request({
url: '',
method: 'PUT',
data: {
test: 'test'
},
header: {
'Content-Type': 'Application/json;charset=UTF-8'
}
})
.then(response => {
console.log('PUT api---', response.data);
})
.catch(error => {
console.log('PUT api error---', error);
});
}
// 小程序http请求没有Patch方法,此方法将返回错误
requestPatch() {
wepy
.request({
url: '',
method: 'PATCH',
data: {
test: 'test'
},
header: {
'Content-Type': 'Application/json;charset=UTF-8'
}
})
.then(response => {
console.log('PATCH api---', response.data);
})
.catch(error => {
console.log('PATCH api error---', error);
});
}
requestDelete() {
wepy
.request({
url: '',
method: 'DELETE',
data: {
test: 'test'
},
header: {
'Content-Type': 'Application/json;charset=UTF-8'
}
})
.then(response => {
console.log('DELETE api---', response.data);
})
.catch(error => {
console.log('DELETE api error---', error);
});
}
requestOptions() {
wepy
.request({
url: '',
method: 'OPTIONS',
data: {
test: 'test'
},
header: {
'Content-Type': 'Application/json;charset=UTF-8'
}
})
.then(response => {
console.log('OPTIONS api---', response.data);
})
.catch(error => {
console.log('OPTIONS api error---', error);
});
}
requestHead() {
wepy
.request({
url: '',
method: 'HEAD',
data: {
test: 'test'
},
header: {
'Content-Type': 'Application/json;charset=UTF-8'
}
})
.then(response => {
console.log('HEAD api---', response.data);
})
.catch(error => {
console.log('HEAD api error---', error);
});
}

data 数据说明:

最终发送给服务器的数据是 String 类型,如果传入的 data 不是 String 类型,会被转换成 String 。转换规则如下:

对于 GET 方法的数据,会将数据转换成 query string(encodeURIComponent(k)=encodeURIComponent(v)&encodeURIComponent(k)=encodeURIComponent(v)...)

对于 POST 方法且 header['content-type'] 为 application/json 的数据,会对数据进行 JSON 序列化

对于 POST 方法且 header['content-type'] 为 application/x-www-form-urlencoded 的数据,会将数据转换成 query string (encodeURIComponent(k)=encodeURIComponent(v)&encodeURIComponent(k)=encodeURIComponent(v)...)

WangShuXian6 commented 6 years ago

组件

横向滚动tab 关键:.scroll{white-space: nowrap;} 关键:scroll直接子元素不能是flex


<style lang="less">
.navigation {
width: 100%;
height: 62rpx;
}
.scroll {
width: 100%;
height: 62rpx;
white-space: nowrap;
}
.item {
display: inline-block;
width: 124rpx;
height: 62rpx;
text-align: center;
line-height: 62rpx;
}
</style>
<hr>

>自定义swiper
```vue
<style lang="less">
    .carousel {
        width: 100%;
        height: 352rpx;
    }
    .swiper {
        width: 100%;
        height: 352rpx;
    }
    .slide-image {
        width: 632rpx;
        height: 352rpx;
        background-color: rgb(115, 192, 192);
        margin-left: 30rpx;
    }
    swiper-item {}
    .pre-image {
        background-color: rgb(192, 115, 188);
        transform: translate(20%, 0)
    }
    .next-image {
        background-color: rgb(192, 156, 115);
        transform: translate(-20%, 0)
    }
</style>

<template>
    <view class="carousel">
        <swiper previous-margin="30rpx" next-margin="30rpx" class="swiper" indicator-dots="true" autoplay="{{}}" interval="{{}}" duration="{{}}" current-item-id={{}} bindchange="changeItem">
            <repeat for="{{carousel}}" key="index" item="item">
                <swiper-item item-id="{{itemId}}">
                    <image mode="scaleToFill" src="{{}}" class="slide-image {{index===currentId-1 ? 'pre-image' : ''}} {{index===currentId+1 ? 'next-image' : ''}}" />
                </swiper-item>
            </repeat>
        </swiper>
    </view>
</template>

<script>
    import wepy from 'wepy'
    export default class Carousel extends wepy.component {
        data = {
            carousel: [1, 2, 3, 4, 5],
            itemId: 0,
            currentId: 0
        }
        methods = {
            changeItem(e) {
                console.log(e.detail.current)
                this.currentId = e.detail.current
            }
        }
    }
</script>

ca


滚动触底加载更多


<template>
<view class="cost-effective">
<scroll-view scroll-y class="cost-effective-scroll"
scroll-with-animation="true" @scrolltolower="loadMore">
</scroll-view>


<hr/>

#### 清除input值
```vue
<style lang="less">

</style>

<template>
  <view class="search">
    <input placeholder="喵小吖" focus="{{true}}" adjust-position="{{false}}"
               bindinput="bindKeyInput" value="{{keyword}}"
               placeholder-class="input-placeholder" type="text" confirm-type="search"/>
    <view @tap="deleteSearchValue" class="delete"></view>
  </view>
</template>

<script>
  export default class Search extends wepy.page {
    config = {
      navigationBarTitleText: '搜索'
    }
    components = {}
    data = {
      keyword: '' // 搜索关键词,
    }
    computed = {}
    methods = {
      deleteSearchValue() {
        this.keyword = ''
        this.$apply()
      },
      bindKeyInput(e) {
        this.keyword = e.detail.value
        this.$apply()
      }
    }
    events = {}

    onLoad() {
    }
  }
</script>

tab切换,内容区域滑动视图

tab


<style lang="less">
  @import (reference) '../../style/color';
  @import '../../style/line';
  @import '../../style/text';

  @mainFont: 30rpx;
  @width: 702rpx;
  @widthL2: 620rpx;
  @height: 84rpx;

  @image: 60rpx;

  @cardWidth: 702rpx;
  @contentWidth: 622rpx;

  @mainFont: 30rpx;
  @detailFont: 28rpx;

  .container {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background-color: @wildSand;

    & > .tab-wrapper {
      z-index: 2;
      position: fixed;
      top: 0;
      left: 0;
      display: flex;
      align-items: center;
      justify-content: space-around;
      width: 100%;
      height: @height;
      background-color: @white;
      & > .tab {
        position: relative;
        font-size: @mainFont;
        color: @dustyGrayL1;
        transition: all 0.15s linear;
      }
      .tab:after {
        content: '';
        display: flex;
        position: absolute;
        left: 50%;
        transform: translate(-50%, 0);
        bottom: -12rpx;
        width: 0rpx;
        height: 6rpx;
        border-radius: 6rpx;
        background-color: @dodgerBlue;
        transition: all 0.15s linear;
      }
      .tab.active:after {
        width: 50rpx;
      }
      .tab.active {
        color: @dodgerBlue;
      }
    }

    .swiper {
      z-index: 1;
      height: 100vh;
      .header-blank {
        display: flex;
        width: 100%;
        height: 100rpx;
      }

      .swiper-item {
        height: 100vh;
        .scroll {
          width: 100%;
          height: 100vh;
          background-color: @wildSand;
          .main-wrapper {
            width: 100%;
            display: flex;
            flex-direction: column;
            align-items: center;
            .card {
              display: flex;
              flex-direction: column;
              align-items: center;
              width: @cardWidth;
              margin-bottom: 30rpx;
              background-color: @white;
              border-radius: 10rpx;
              box-shadow: @boxShadowL2;
              & > .head,
              & > .main,
              & > .time-wrapper,
              & > .foot {
                display: flex;
                width: @contentWidth;
              }

              & > .head {
                align-items: center;
                position: relative;
                margin-top: 30rpx;
                & > .name {
                  font-size: @mainFont;
                  color: @mineShaft;
                  margin-right: 46rpx;
                }
                & > .phone {
                  font-size: @mainFont;
                  color: @mineShaft;
                }
                & > .air-logo {
                  position: absolute;
                  top: 0;
                  right: 0;
                }
              }
              & > .main {
                flex-direction: column;
                align-items: center;
                & > .top,
                & > .bottom {
                  display: flex;
                  width: @contentWidth;
                  margin-top: 20px;
                  & > image {
                    display: flex;
                    width: @image;
                    height: @image;
                    border-radius: 50%;
                    margin-right: 40rpx;
                  }
                  & > text {
                    font-size: @detailFont;
                    color: @mineShaft;
                    line-height: @detailFont*1.2;
                  }
                }
              }
              & > .time-wrapper {
                position: relative;
                justify-content: flex-end;
                align-items: center;
                margin-top: 54rpx;
                margin-bottom: 20rpx;
                & > .time {
                  position: absolute;
                  top: 0;
                  left: 0;
                  align-items: center;
                  color: @mineShaft;
                  font-size: @detailFont;
                }
                & > .expedited {
                  color: @pink;
                  font-size: 32rpx;
                }
                & > image {
                  display: flex;
                  width: 18rpx;
                  height: 30rpx;
                  margin-left: 16rpx;
                }
              }

              & > .foot {
                align-items: center;
                height: 100rpx;
                justify-content: space-between;
                border-top: 2rpx solid @galleryGray;
                & > .status {
                  color: @dodgerBlue;
                  font-size: 32rpx;
                }
                & > .air-evaluation {

                }
              }
            }
          }
        }
      }
    }
  }
</style>

<template>
  <view class="container">
    <view class="tab-wrapper">
      <text @tap="changeTab(0)" class="tab {{currentTab===0 ? 'active' : ''}}">全部</text>
      <text @tap="changeTab(1)" class="tab {{currentTab===1 ? 'active' : ''}}">待完成</text>
      <text @tap="changeTab(2)" class="tab {{currentTab===2 ? 'active' : ''}}">未评价</text>
      <text @tap="changeTab(3)" class="tab {{currentTab===3 ? 'active' : ''}}">已完成</text>
    </view>

    <swiper indicator-dots="{{false}}" autoplay="{{false}}" bindchange="changeSwiper"
            class="swiper" current="{{currentTab}}">
      <repeat for="{{tabList}}" key="key" item="item" index="index">
        <swiper-item class="swiper-item">
          <scroll-view scroll-y class="scroll"
                       scroll-with-animation="true" @scrolltolower="loadMore">
            <view class="main-wrapper">
              <view class="header-blank"></view>
              <repeat for="{{cardList}}" key="cardKey" item="cardItem" index="cardIndex">
                <view class="card">
                  <view class="head">
                    <text class="name">王力宏</text>
                    <text class="phone">15512345678</text>
                    <view class="air-logo">淘宝</view>
                  </view>
                  <view class="main">
                    <view class="top">
                      <image lazy-load="true" mode="scaleToFill" src="{{pickupAddressImage}}"/>
                      <text class="content">[取件地址] 石家庄职业技术学院西门菜鸟驿站</text>
                    </view>
                    <view class="bottom">
                      <image lazy-load="true" mode="scaleToFill" src="{{deliveryAddressImage}}"/>
                      <text class="content">[送件地址] 石家庄职业技术学院西门菜鸟驿站</text>
                    </view>
                  </view>
                  <view class="time-wrapper">
                    <text class="time">送件时间:9月3日 15:30~18:30</text>
                    <text class="expedited">加急</text>
                    <image lazy-load="true" mode="scaleToFill" src="{{expeditedImage}}"/>
                  </view>

                  <view class="foot">
                    <text class="status">已完成</text>
                    <text class="air-evaluation">评价</text>
                  </view>
                </view>
              </repeat>
            </view>
          </scroll-view>
        </swiper-item>
      </repeat>
    </swiper>
  </view>
</template>

<script>
  import wepy from 'wepy'
  import {connect} from 'wepy-redux'
  import commonMixin from '@/mixins/common'
  import {SUCCESS, FAIL} from '@/constant/request'

  @connect({}, {})
  export default class AllOrders extends wepy.page {
    config = {
      navigationBarTitleText: ''
    }
    components = {}
    mixins = [commonMixin]
    data = {
      weChatPaymentImage: '../../icon/delivery/weChatPayment.png',
      currentTab: 0,
      pickupAddressImage: '../../icon/delivery/pickupAddress.png',
      deliveryAddressImage: '../../icon/delivery/deliveryAddress.png',
      tabList: [
        {},
        {},
        {},
        {}
      ],
      cardList: [
        {},
        {},
        {},
        {},
        {},
        {},
        {},
        {},
        {},
        {},
        {},
        {},
        {},
        {},
        {},
        {}
      ]
    }
    computed = {}
    methods = {
      changeTab(tab) {
        this.currentTab = +tab
      },
      changeSwiper(e){
        this.currentTab=e.detail.current
      },
      loadMore(){

      }
    }
    events = {}

    async onLoad() {

    }

    onShow() {
    }

  }
</script>

通用滚动容器

<style lang="less">
  @import (reference) '../../style/color';
  @import '../../style/icon';

  @width: 702rpx;
  @widthL2: 444rpx;
  @image: 60rpx;

  @mainFont: 34rpx;
  @mainFontL2: 30rpx;
  @detailFont: 28rpx;
  @detailFontL2: 20rpx;

  .container {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background-color: @wildSand;
    color: @mineShaft;
    .release-order-scroll {
      z-index: 1;
      width: 100%;
      height: 100vh;
      background-color: @wildSand;
      .main-wrapper {
        width: 100%;
        display: flex;
        flex-direction: column;
        align-items: center;
      }
    }
  }
</style>

<template>
  <view class="container">
    <scroll-view scroll-y class="release-order-scroll"
                 scroll-with-animation="true" @scrolltolower="loadMore">
      <view class="main-wrapper">

      </view>

    </scroll-view>
  </view>
</template>

<script>
  import wepy from 'wepy'
  import {connect} from 'wepy-redux'
  import commonMixin from '@/mixins/common'
  import {SUCCESS, FAIL} from '@/constant/request'

  @connect({}, {})
  export default class Team extends wepy.page {
    config = {
      navigationBarTitleText: '我的团队'
    }
    components = {}
    mixins = [commonMixin]
    data = {
      pickupAddressImage: '../../icon/delivery/pickupAddress.png',
    }
    computed = {}
    methods = {}
    events = {}

    async onLoad() {

    }

    onShow() {
    }
  }
</script>

标签

jietu20181011-231528

cateCard.wpy


<style lang="less">
@import (reference) '../../style/color';
@import (reference) '../../style/size';

@width:156rpx; @height:114rpx;

.cate-card{ overflow: hidden; position: relative; display: flex; flex-direction: column; align-items: center; justify-content: center; width: @width; height: @height; border-radius: 6rpx; background-color: @bgColorL2; &>.cate-name{ font-size: @mainSize; color: @mainColor; } &>.food-name{ font-size: @detailSize; color: @regularColor; } &>.hot-label{ position: absolute; top: 0rpx; right: -28rpx; display: flex; align-items: center; justify-content: center; width: 100rpx; height: 40rpx; font-size: @mainSize; color: @white; transform: rotate(45deg); background-color: @dangerColor; } }

>color.less
```less
@white: #fff;

/*阴影*/
@boxShadow: 0rpx 6rpx 6rpx 4rpx rgba(0, 0, 0, 0.05);
@boxShadowL2: 0rpx 4rpx 4rpx 6rpx rgba(0, 0, 0, 0.05);
@boxShadowTop: -6rpx 0rpx 6rpx 4rpx rgba(0, 0, 0, 0.05);
@boxShadowTopDark: -6rpx 0rpx 6rpx 4rpx rgba(0, 0, 0, 0.2);
@boxShadowBlue: 0rpx 0rpx 10rpx 8rpx rgba(68, 158, 255, 0.5);

/*主色 主要品牌颜色*/
@blue: #409EFF;
@yellow: #f4ea2a;

/*辅助色 除了主色外的场景色,需要在不同的场景中使用(例如危险色表示危险的操作)*/
@successColor: #67C23A;
@warningColor: #E6A23C;
@dangerColor: #F56C6C;
@infoColor: #909399;

/*中性色 用于文本、背景和边框颜色。通过运用不同的中性色,来表现层次结构*/

/*主要文字*/
@mainColor: #303133;

/*常规文字*/
@regularColor: #606266;

/*次要文字*/
@secondaryColor: #909399;

/*占位文字*/
@placeholderColor: #C0C4CC;

/*边框*/

/*一级边框*/
@borderL1: #DCDFE6;

/*二级边框*/
@borderL2: #E4E7ED;

/*三级边框*/
@borderL3: #EBEEF5;

/*四级边框*/
@borderL4: #F2F6FC;

/* 背景色 */
@bgColor: #F4F4F4;
@bgColorL2: #F5F6F8;

父子互动组件

父组件


<style lang="less">

>
```typescript
import wepy from 'wepy'
import {connect} from 'wepy-redux'
import Content from '@/components/purchaseOrder/content'
import Tip from '@/components/common/tip'

@connect({
}, {
})

export default class PurchaseOrder extends wepy.page {
  config = {
    navigationBarTitleText: '填写订单',
    usingComponents: {
    }
  }

  components = {
    tip:Tip
  }

  mixins = []

  data = {
  }

  computed = {
  }

  methods = {
    handleTipSubmit(value,e){
      console.log('pa111-','su')
      console.log('value-',value)
    },
    toggleTip(){
      console.log('toggleTip')
      this.$invoke('tip', 'showTip', '');
    }
  }

  events = {
  }

  onLoad() {
  }
}

子组件


<style lang="less">
@import (reference) '../../style/color';
@import '../../style/size';

@labelWidth:214rpx; @labelHeight:70rpx;

@width:710rpx;

.air-tip{ position: fixed; left: 0; bottom: 0; display: flex; flex-direction: column; align-items: center; width: 100%; background-color: @white; box-shadow: @boxShadowTop; padding-bottom: 50rpx; transition: all 0.2s linear; &>.title-wrapper{ display: flex; align-items: center; justify-content: space-between; width: 100%; height: @regularHeight; border-bottom: 2rpx solid @borderL4; &>.label{ display: flex; font-size: @mainSize; color: @regularColor; } &>.cancel{ margin-left: @regularMargin; } &>.submit{ margin-right: @regularMargin; } }

&>.tip-wrapper-air{
  display: flex;
  flex-wrap: wrap;
  justify-content: space-around;
  width: 100%;
  padding-top: 50rpx;
  font-size: @mainSize;
  color: @mainColor;
  &>.tip-item{
    display: flex;
    align-items: center;
    justify-content: center;
    width:@labelWidth;
    height: @labelHeight;
    border: 2rpx solid @borderL4;
    border-radius: 6rpx;
    margin-bottom: @regularMargin;
  }
  &>.active{
    border: 2rpx solid @blue;
    color: @blue;
  }
}

&>.tip-other{
  display: flex;
  align-items: center;
  justify-content: center;
  width: @width;
  height: @labelHeight;
  border: 2rpx solid @borderL4;
  border-radius: 6rpx;
  font-size: @mainSize;
  color: @mainColor;
  &>.tip-label{
    display: flex;
    align-items: center;
  }
  &>.tip-input{
    width: 100rpx;
    font-size: @mainSize;
    color: @mainColor;
  }
}
&>.active{
  border: 2rpx solid @blue;
  color: @blue;
}

} .air-tip.hide{ bottom: -50vh; }

>
```typescript
import wepy from 'wepy'
import {connect} from 'wepy-redux'
import commonMixin from '@/mixins/common'

// 小费卡片
@connect({}, {})

export default class Tip extends wepy.component {

  components={

  }

  mixins = [commonMixin]

  props = {
    tipList:{
      type:Array,
      default:[
        {
          price:2
        }
      ]
    }
  }

  data = {
    tipOther:'',
    toggle:false
  }

  events = {}

  watch = {}

  methods = {
    bindKeyInput(e) {
      this.setData({
        inputValue: e.detail.value
      })
    },
    handleCancel(value,e){
      this.toggle=false
      console.log('pa-','ca')
      console.log('value-',value)
    },
    handleSubmit(value,e){
      this.$emit('tipSubmit')
      this.toggle=false
      console.log('pa-','su')
      console.log('value-',value)
    },
    showTip(){
      this.toggle=true
      console.log('this.toggle--',this.toggle)
    }
  }

}
WangShuXian6 commented 6 years ago

示例

多个动态class样式

<template>
<image mode="scaleToFill" src=""
class="slide-image {{index===currentId-1 ? 'pre-image' : ''}} {{index===currentId+1 ? 'next-image' : ''}}"/>
</template>

input 输入框 input的父元素不可以是固定定位


<style lang="less">
@placeholderColor: #d9d9d9;
.input-placeholder {
font-size: 28rpx;
color: @placeholderColor;
}

<hr>

>左滑显示右侧隐藏按钮
```vue
<style lang="less">
  .test {
    width: 100%;
    & > .move-area {
      width: 200rpx;
      height: 50rpx;
      background-color: antiquewhite;
      & > .move-view {
        z-index: 5;
        width: 50rpx;
        height: 50rpx;
        background-color: aquamarine;
      }
      & > .delete {
        z-index: -1;
        position: absolute;
        right: 0;
        top: 0;
        width: 50rpx;
        height: 50rpx;
        background-color: blueviolet;
        opacity: 0;
        transition: all 0.2s linear;
      }
      .delete.active {
        z-index: 0;
        opacity: 1;
      }
    }

    & > .move-area-2 {
      width: 200rpx;
      height: 50rpx;
      background-color: antiquewhite;
      & > .move-view {
        z-index: 5;
        width: 250rpx;
        height: 50rpx;
        background-color: aquamarine;
      }
      & > .delete {
        z-index: -1;
        position: absolute;
        right: -50rpx;
        top: 0;
        width: 50rpx;
        height: 50rpx;
        background-color: blueviolet;
        opacity: 0;
        transition: all 0.2s linear;
      }
      .delete.active {
        z-index: 0;
        opacity: 1;
      }
    }
  }
</style>

<template>
  <view class="test">
    <view class="section__title">movable-view区域小于movable-area</view>
    <movable-area class="move-area">
      <movable-view inertia="true" direction="horizontal" friction="0.1" damping="20" bindchange="handleLeftmove"
                    animation="true" x="150rpx" y="" class="move-view">
      </movable-view>
      <view class="delete {{shouldShowDelete ? 'active' : ''}}"></view>
    </movable-area>

    <view class="section__title">movable-view区域大于movable-area</view>
    <movable-area class="move-area-2">
      <movable-view inertia="true" direction="horizontal" friction="0.1" damping="20" bindchange="handleLeftmoveBottom"
                    animation="true" x="" y="" class="move-view">
      </movable-view>
      <view class="delete {{shouldShowDeleteBottom ? 'active' : ''}}"></view>
    </movable-area>
  </view>
</template>

<script>
  import wepy from 'wepy'
  import {
    connect
  } from 'wepy-redux'

  @connect({}, {})
  export default class Test extends wepy.page {
    config = {
      navigationBarTitleText: 'test'
    }
    components = {}
    mixins = []
    data = {
      shouldShowDelete: false,
      shouldShowDeleteBottom: false
    }
    computed = {}
    methods = {
      handleLeftmove(e) {
        console.log('handleLeftmove---x--', e.detail.x)
        if (e.detail.x === 0) {
          this.shouldShowDelete = true
        } else {
          this.shouldShowDelete = false
        }
      },
      handleLeftmoveBottom(e) {
        console.log('handleLeftmove---x--', e.detail.x)
        if (e.detail.x === -25) {
          this.shouldShowDeleteBottom = true
        } else {
          this.shouldShowDeleteBottom = false
        }
      }
    }
    events = {}

    onLoad() {
    }
  }
</script>

wechatimg4 wechatimg5


懒加载

<image lazy-load="true" class="image" mode="scaleToFill" src="{{item.src}}" @tap="food({{index}},{{itemIndex}})"></image>
WangShuXian6 commented 6 years ago

轮播图


<style lang="less">
// 主轮播图,第一轮播图
@bgColor: #F5F5F5;
@boxShadow: 6rpx 8rpx 8rpx rgba(0, 0, 0, 0.16);
@dotsBgColor: #DCDCDC;
@dotActiveColor: #D94E4E;
@defaultColor: rgb(115, 192, 192);
.carousel {
position: relative;
width: 100%;
height: 414rpx;
background-color: @bgColor;
padding-top: 36rpx;
}

.swiper { width: 100%; height: 352rpx; }

.slide-image { width: 632rpx; height: 352rpx; transform: scale(0.95); background-color: @defaultColor; margin-left: 30rpx; border: none; border-radius: 8rpx; box-shadow: @boxShadow; }

.pre-image { background-color: rgb(192, 115, 188); transform: translate(20%, 0) scale(0.9); border-radius: 8rpx; }

.next-image { background-color: rgb(192, 156, 115); transform: translate(-20%, 0) scale(0.9); border-radius: 8rpx; }

.dots { box-sizing: border-box; display: flex; position: absolute; top: 402rpx; left: 50%; transform: translate(-50%, 0); height: 24rpx; background-color: @dotsBgColor; border: none; border-radius: 24rpx; }

.dot { display: inline-block; flex: 1; width: 10rpx; height: 10rpx; border: none; border-radius: 50%; margin-top: 7rpx; margin-left: 12rpx; background-color: #fff; }

// .dot:first-child {} .dot:last-child { margin-right: 12rpx; }

.active-dot { background-color: @dotActiveColor; }

WangShuXian6 commented 6 years ago

事件

https://developers.weixin.qq.com/miniprogram/dev/framework/view/wxml/event.html 小程序不支持e.stopPropagation()用以阻止捕获或冒泡的进一步传播 小程序使用catch:tap="handleClickInner"代替e.stopPropagation()


<style lang="less">

WangShuXian6 commented 6 years ago

wepy分包

截止2018-7-23 无分包:小程序限制大小为2MB。 有分包:主包限制2MB,单个分包限制2MB,整个小程序所有分包大小不超过 8M. 在src下建立分包目录 src/packageTest/pages/pTest.wpy app.js配置的config字段为

config = {
pages: [
'pages/test'
],
subPackages:[
{
root:'packageTest',
pages:[
'pages/pTest'
]
}
],
window: {
backgroundTextStyle: 'light',
navigationBarBackgroundColor: '#fff',
navigationBarTitleText: 'WeChat',
navigationBarTextStyle: 'black'
}
}

主包内点击按钮跳转到分包内的方法

navToPack(){
wx.navigateTo({
url:'../packageTest/pages/pTest' // 相对路径
// url:'/packageTest/pages/pTest' // 绝对路径
})
}
WangShuXian6 commented 6 years ago

小程序使用节流函数


methods = {
handleLeftmove: debounce((key, e) => {

}, 500, false)

WangShuXian6 commented 6 years ago

tabBar

app.wpy 注意:pages数组的第一项必须是tabBar的list数组的一员


config = {
pages: [
'pages/index',
'pages/get',
'pages/tab',
'pages/pageA',
'pages/pageB'
  ],
  window: {
    backgroundTextStyle: 'light',
    navigationBarBackgroundColor: '#fff',
    navigationBarTitleText: 'WeChat',
    navigationBarTextStyle: 'black'
  },
  tabBar: {
    color: '#000',
    selectedColor: '#ff4777',
    backgroundColor: '#fff',
    borderStyle: 'white',
    position: 'bottom',
    list: [
      {
        pagePath: 'pages/index',
        text: '第0个',
        iconPath: './icon/a.jpg',
        selectedIconPath: './icon/s.jpg'
      },
      {
        pagePath: 'pages/pageA',
        text: '第一个',
        iconPath: './icon/a.jpg',
        selectedIconPath: './icon/s.jpg'
      },
      {
        pagePath: 'pages/pageB',
        text: '第二个',
        iconPath: './icon/b.jpg',
        selectedIconPath: './icon/s.jpg'
      }
    ]
  }
}
WangShuXian6 commented 5 years ago

watch 监听器

import wepy from 'wepy'
import {connect} from 'wepy-redux'

@connect({}, {})

export default class ShippingAddress extends wepy.component {

  components = {}

  props = {
    info: {
      type: Object,
      default: {
        distance: '',
        title: '',
        detail: '',
        name: '',
        phone: ''
      }
    }
  }

  data = {
    hasAddress: false
  }

  events = {}

  watch = {
    info(newValue, oldValue) {
      if (newValue.title) {
        this.hasAddress = true
      } else {
        this.hasAddress = false
      }
      this.$apply()
    }
  }

  methods = {
    toggleAddress(toggleAddress) {
      this.toggleAddress = toggleAddress
    }
  }
}
WangShuXian6 commented 5 years ago

wepy 重的页面跳转

// 跳转到指定页面,可以反回
  goPageCanBack = (url, params = {}) => {
    if (!url) {
      wx.navigateTo({
        url: '/pages/error'
      })
    } else if (typeof url !== 'string') {
      console.warn('页面地址应为字符串格式')
      return false
    } else if (params && !isEmptyObject(params)) {
      const paramsString = buildParamsString(params)
      wx.navigateTo({
        url: `${url}?${paramsString}`
      })
    } else if (!params || isEmptyObject(params)) {
      wx.navigateTo({
        url: url
      })
    }
  }

  // 跳转到指定页面,不可以反回
  goPage = (url, params = {}) => {
    if (!url) {
      wx.redirectTo({
        url: '/pages/error'
      })
    } else if (typeof url !== 'string') {
      console.warn('页面地址应为字符串格式')
      return false
    } else if (params && !isEmptyObject(params)) {
      const paramsString = buildParamsString(params)
      wx.redirectTo({
        url: `${url}?${paramsString}`
      })
    } else if (!params || isEmptyObject(params)) {
      wx.redirectTo({
        url: url
      })
    }
  }
this.goPage('/packageRider/pages/rider', {source: PURCHASE})
this.goPageCanBack('error', {source: PURCHASE})
WangShuXian6 commented 5 years ago

父子组件通信

父组件调用子组件方法


#### 在子组件内读取自身属性值 props
```vue
this.props // 无有效值
WangShuXian6 commented 5 years ago

页面内发起微信分享

注意:分享路径为 path: 'pages/index?member_id='+this.memberId 不同于原生小程序路径

<view class="share-wrapper">
<text class="air-long-button blue invite-button">立即邀请</text>
<button open-type="share" class="share"></button>
</view>

.air-long-button{
display: flex;
align-items: center;
justify-content: center;
width: @widthL3;
height: @height;
border-radius: @height;
background-color: @white;
box-shadow: @boxShadow;
font-size: @mainSize;
line-height: normal;
color: @mainColor;
border: 2rpx solid @borderL1;
}

.air-long-button.blue{ background-color: @blue; border: 2rpx solid @blue; }

&>.share-wrapper{ position: relative; display: flex; align-items: center; justify-content: center; width: 100%; &>.share{ position: absolute; top: 0; left: 0; right: 0; bottom: 0; opacity: 0; } }

```typescript
methods = {
    /**
     * 用户点击右上角或页面分享按钮分享
     */
    onShareAppMessage: function () {
      return {
        title: this.title,
        path: 'pages/index?member_id='+this.memberId
      }
    }
  }

WangShuXian6 commented 5 years ago

wepy 小程序 使用富文本

wepy-html

https://github.com/beiliao-web-frontend/wepy-html