Applets framework WEpy documentation
DEMO of finished products
One is a standard demo generated using the wepy new demo command
One is a full demo of mobile phone recharge based on Wepy
One is based on the development of wepy open source imitation wechat chat interface (source code download)
The above three demos have been run on Android and IOS.
Quick start
Code specification:
1. Use camel name for variables and methods instead of starting with $. Methods or attributes that start with $are built-in methods or attributes and can be used. Please refer to the API documentation before using them.
2. Name entries, pages, and components with the suffix.wpy. External linked files can be other suffixes. Please refer to the WPY file description
3. Develop using ES6 syntax.
The framework was developed under ES6, so we also need to use ES6 to develop small programs. ES6 has a lot of syntax sugar to make our code more concise and efficient.
4. Use promises
The framework promises all apis provided by applets by default, and can even be developed directly with new features such as async/await.
Project creation and use
Install wepy
The following installations are installed through NPM
Note: In Tencent development website, NPM requires an agent. If you don’t use NPM agent, you are advised to use Tencent internal tool TNMP instead of NPM installation. For TNPM installation and use, please refer to alsotan G’s article.
1. Install the WEpy command line tool
npm install wepy-cli -g
Copy the code
2. Generate development DEMO in the development directory
wepy new myproject
Copy the code
3. Develop real-time builds
wepy build --watch
Copy the code
Project directory structure
dist
node_modules
src
components
com_a.wpy
com_b.wpy
pages
index.wpy
page2.wpy
app.wpy
package.json
Copy the code
Development instructions
1. Use wechat developer tools to create a project, and select dist directory for local development.
2. Wechat Developer Tools – > Project – > Close ES6 to ES5.
3. Run wepy build –watch in the local project root directory to enable real-time compilation.
Main problems solved:
1. Development mode transformation
In the original small program development mode of encapsulation, more close to the existing MVVM framework development mode. The framework was developed with reference to some of the features of the current framework and incorporated into it. Below is a comparison of the code before and after using Wepy.
Official DEMO code:
Var app = getApp() Page({data: {motto: 'Hello World', userInfo: {}}, function bindViewTap: {motto: 'Hello World', motto: 'Hello World', motto: 'Hello World', motto: 'Hello World', motto: 'Hello World', motto: 'Hello World', motto: 'Hello World', motto: 'Hello World', motto: 'Hello World', motto: 'Hello World') function() { console.log('button clicked') }, onLoad: function () { console.log('onLoad') } })Copy the code
Implementation based on Wepy:
import wepy from 'wepy'; export default class Index extends wepy.page { data = { motto: 'Hello World', userInfo: {} }; methods = { bindViewTap () { console.log('button clicked'); }}; onLoad() { console.log('onLoad'); }; }Copy the code
2. Support componentized development
See section: Components
Sample code:
// index.wpy <template> <view> <component id="pannel" path="pannel"></component> <component id="counter1" path="counter"></component> <component id="counter2" path="counter"></component> <component id="list" path="list"></component> </view> </template> <script> import wepy from 'wepy'; import List from '.. /components/list'; import Panel from '.. /components/panel'; import Counter from '.. /components/counter'; export default class Index extends wepy.page { config = { "navigationBarTitleText": "test" }; components = { panel: Panel, counter1: Counter, counter2: Counter, list: List }; } </script>Copy the code
3. Supports loading external NPM packages.
During compilation, require is recursively iterated through the code and the dependency files are copied from node_modules, and require is changed to a relative path to support external NPM packages. The diagram below:
4. Single-file mode, making the directory structure clearer.
Json, app.js, and app.wxss. The page has 4 files: index.json, index.js, index.wxml, and index.wxss. And the file must have the same name.
Therefore, the comparison of development directories before and after wepy development is as follows:
Official DEMO:
project
pages
index
index.json
index.js
index.wxml
index.wxss
log
log.json
log.wxml
log.js
log.wxss
app.js
app.json
app.wxss
Copy the code
Directory structure with the Wepy framework:
project
src
pages
index.wpy
log.wpy
app.wpy
Copy the code
Compiled using Babel by default, some new features of ES6/7 are supported.
Users can configure their familiar Babel environment for development by modifying the wepy.config.js configuration file. Default enabled uses new features like Promise, async/await, etc.
Sample code:
import wepy from 'wepy';
export default class Index extends wepy.page {
getData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({data: 123});
}, 3000);
});
};
async onLoad() {
let data = await this.getData();
console.log(data.data);
};
}
Copy the code
5. Optimize for native apis
Promise processing to the existing API, and fix some existing API flaws such as wx.request concurrency issues.
Original code:
onLoad = function () { var self = this; wx.login({ success: function (data) { wx.getUserInfo({ success: function (userinfo) { self.setData({userInfo: userinfo}); }}); }}); }Copy the code
Implementation code based on WEpy:
async onLoad() {
await wx.login();
this.userInfo = await wx.getUserInfo();
}
Copy the code
When testing 10 requests simultaneously:
Do not use wepy:
After using Wepy:
Advanced instructions
Wepy.config. js configuration file description
After wepy New Demo is executed, a similar configuration file is generated.
let prod = process.env.NODE_ENV === 'production'; module.exports = { "wpyExt": ".wpy", "babel": { "presets": [ "es2015", "stage-1" ], "plugins": [ "transform-export-extensions", "syntax-export-extensions", "transform-runtime" ] } }; Exports ['sass'] = {"outputStyle": "compressed"}; Exports [' exports '] = {" exports ": true}; // Compress js module.exports.plugins = {'UglifyJsPlugin': {filter: /\.js$/, config: {{compress: {warning: false } } }, 'TestPlugin': { filter: /\.wxml$/, config: { } } }; }Copy the code
WpyExt: The default value is’. Wpy ‘, the IDE does not highlight this file type by default, you can change all files to the. Vue suffix (because it is the same as vue highlighting rules), then change this option to. Vue to solve some IDE code highlighting problems.
Sass: SASS compilation and configuration, see here
Less: Less compilation and configuration. For details, see here
Babel: Babel compilation configuration, see here
Plugins: Plugins for 1.1.6 after the function, currently support JS compression and image compression, continuous development……
Wpy file description
The wpy file is compiled as follows:
A.wpy file is divided into three parts:
corresponds to the original WXSS
Template
corresponds to the original WXML
Code corresponds to the original JS
The entry file app.wpy does not require template, so it is ignored during compilation. All three tags support the type and SRC attributes. Type determines the compilation process of their code, and SRC determines whether to externalize the code. If the SRC attribute exists and is valid, the inlining code is ignored, as shown in the following example:
<style type="less" src="page1.less"></style>
<template type="wxml" src="page1.wxml"></template>
<script>
// some code
</script>
Copy the code
The label type values are as follows:
| | | tag type, a default value type support value | | -- - | -- - | -- - | | style | | CSS CSS, less and sass (pending) | | template | WXML | WXML, XML, HTML (pending) | | script | js | js, | TypeScript (pending)Copy the code
The script that
Program entry app.wpy
<style type="less">
/** less **/
</style>
<script>
import wepy from 'wepy';
export default class extends wepy.app {
config = {
"pages":[
"pages/index/index"
],
"window":{
"backgroundTextStyle": "light",
"navigationBarBackgroundColor": "#fff",
"navigationBarTitleText": "WeChat",
"navigationBarTextStyle": "black"
}
};
onLaunch() {
console.log(this);
}
}
</script>
Copy the code
The entry app.wpy inherits from wepy.app and contains a config property with its global properties, methods, and events. The config attribute corresponds to the original app.json file, which will be generated according to the config during compilation. If you need to modify the content in config, use the API provided by the system.
The index page. Wpy
<style type="less"> /** less **/ </style> <template type="wxml"> <view> </view> <component id="counter1" path="counter"></component> </template> <script> import wepy form 'wepy'; import Counter from '.. /components/counter'; export default class Index extends wepy.page { config = {}; components = {counter1: Counter}; data = {}; methods = {}; events = {}; onLoad() {}; // Other properties } </script>Copy the code
The page entry inherits from wepy.page and its main properties are described as follows:
Com components. Wpy
<style type="less">
/** less **/
</style>
<template type="wxml">
<view> </view>
</template>
<script>
import wepy form 'wepy';
export default class Com extends wepy.component {
components = {};
data = {};
methods = {};
events = {};
// Other properties
}
</script>
Copy the code
The page entry inherits from Wepy.component and has the same properties as the page properties, except that it does not require config and some page-specific applet events, etc.
component
In the small program, JS modularization and WXML template can be used to divide business modules to achieve the following effects:
However, different module code and event interactions are handled in the same page space. For example, if an ADD response event exists in moduleA and moduleB, it needs to be defined as moduleA_add in HTML and moduleB_add in JS. The complexity of business modules becomes difficult to develop and maintain.
In WEpy, this kind of problem can be solved by using the componentization feature, as shown below:
The data in between ComA and ComB are isolated from events, and each can have its own Add event.
A component reference
When a page or component needs to import a child component, assign the component a unique ID to the components in the page or script, and add a < Component > tag to the template, such as index.wpy
The Index page introduces three components A, B, and C, and components A and B have their own sub-components D, E, F, G, and H.
Component communication and interaction
The wepy.component.ponent class provides three methods: $broadcast, $emit, and $invoke, so any page or component can call these three methods to communicate and interact with each other.
$this.$emit('some-event', 1, 2, 3, 4);
Copy the code
The component’s event listener needs to be written under the Events property, as in:
import wepy form 'wepy';
export default class Com extends wepy.component {
components = {};
data = {};
methods = {};
events = {
'some-event': ($event, ...args) {
console.log(`${this.name} receive ${$event.name} from ${$event.source.name}`);
}
};
// Other properties
}
Copy the code
1. The $broadcast $broadcast event is initiated by the parent component. All child components receive the broadcast event unless the event is manually cancelled. Events are broadcast in breadth-first search order. If Page_Index initiates A $broadcast event, events are received in the order of A, B, C, D, E, F, G, and H. The diagram below:
2 .$emit
$emit is the opposite of $broadcast. The parent of the event emitting component receives $emit events in sequence, as shown in the figure above. If E initiates A $emit event, the event will be received in the order of A, Page_Index. The diagram below:
3 .$invoke
$invoke is a direct call from one component to another, finding the corresponding component through the component path passed in, and invoking its methods.
If you want to call A method of component A in Page_Index:
this.$invoke('ComA', 'someMethod', 'someArgs');
Copy the code
If you want to call A method of component G from component A:
this.$invoke('./.. /ComB/ComG', 'someMethod', 'someArgs');Copy the code
hybrid
Mixing can separate reusable portions between groups so that mixed data, events, and methods can be injected into a component when mixing is used in the component. Mixing is divided into two types:
-
Default blending
-
Compatible mixing
Default blending
Default blending is used for component data, components, events events, and other custom methods, that is, if the component does not declare the data, component, event, custom method, etc., then the options from the blending object are injected into the component. Options already declared for components are not affected.
// mixins/test.js
import wepy from 'wepy';
export default class TestMixin extends wepy.page {
data = {
foo: 'foo defined by page',
bar: 'bar defined by testMix'
};
methods: {
tap () {
console.log('mix tap');
}
}
}
// pages/index.wpy
import wepy from 'wepy';
import TestMixin from './mixins/test';
export default class Index extends wepy.mixin {
data = {
foo: 'foo defined by index'
};
mixins = [TestMixin ];
onShow() {
console.log(this.foo); // foo defined by index.
console.log(this.bar); // foo defined by testMix.
}
}
Copy the code
Compatible mixing
Compatibility mixing is adopted for component methods response events and applet page events, that is, responding to the response events of the component itself first, and then responding to the response events in the mixed object.
// mixins/test.js import wepy from 'wepy'; export default class TestMixin extends wepy.page { methods = { tap () { console.log('mix tap'); }}; onShow() { console.log('mix onshow'); } } // pages/index.wpy import wepy from 'wepy'; import TestMixin from './mixins/test'; export default class Index extends wepy.mixin { mixins = [TestMixin]; methods = { tap () { console.log('index tap'); }}; onShow() { console.log('index onshow'); } } // index onshow // mix onshow // ----- when tap // index tap // mix tapCopy the code
Data binding
Applets data binding mode
Applets use setData methods provided by Page to unbind data, such as:
this.setData({title: 'this is title'});
Copy the code
Because of the applets architecture itself, the page rendering layer and THE JS logic layer are separated, and the setData operation is actually the communication between the JS logic layer and the page rendering layer, so if the setData operation is executed several times in the same running cycle, then the number of communication is once or many times? After confirming with the small program team, we learned that multiple setData will execute multiple communications.
Wepy data binding
Wepy uses the dirty data check to encapsulate setData, and performs the dirty data check at the end of the function running cycle. On the one hand, it does not need to worry about whether setData will have performance problems on the page multiple times. On the other hand, it can be more concise to modify the data to achieve binding, and it does not need to write the setData method repeatedly. The code is as follows:
this.title = 'this is title';
Copy the code
Note, however, that modifying data in functions outside of the function’s run cycle requires a manual call to the $apply method. Such as:
setTimeout(() => {
this.title = 'this is title';
this.$apply();
}, 3000);
Copy the code
Wepy dirty data check process
When performing dirty data checks, this.? Phase identifies the current check status and ensures that only one dirty data check process is running in a concurrent process. The following is a flow chart for performing a dirty data check:
Other optimization details
1. Wx. request Accepts parameter modification
Click here for official documentation
Wx. request({url: 'XXX ', success: function (data) {console.log(data); }}); Wx.request (' XXXX '). Then ((d) => console.log(d));Copy the code
2. Optimize event parameter transmission
Click here for official documentation
<view id="tapTest" data-hi="WeChat" bindtap="tapName"> WeChat <view id="tapTest" data-hi="WeChat" bindtap="tapName"> </view> Page({ tapName: function(event) { console.log(event.currentTarget.hi)// output: WeChat } }); <view id="tapTest" data-wepy-params="1-wepy-something" bindtap="tapName"> Click me! </view> events: { tapName (event, id, title, other) { console.log(id, title, other)// output: 1, wepy, something } }Copy the code
3. Change the data binding mode
Retain the setData method, but do not recommend using setData to perform binding, fix the bug of passing undefined, and modify the input parameter support:
-
this.setData(target, value)
-
this.setData(object)
Click here for official documentation
OnLoad: function () {this.setData({message: 'hello world'}); } // wepy <view> {{ message }} </view> onLoad () { this.message = 'hello world'; }Copy the code
4. Components replace templates and modules
Click here for official documentation
Official / / <! -- item.wxml --> <template name="item"> <text>{{text}}</text> </template> <! -- index.wxml --> <import src="item.wxml"/> <template is="item" data="{{text: 'forbar'}}"/> <! -- index.js --> var item = require('item.js') // wepy <! -- /components/item.wpy --> <text>{{text}}</text> <! -- index.wpy --> <template> <component id="item"></component> </template> <script> import wepy from 'wepy'; import Item from '.. /components/item'; export default class Index extends wepy.page { components = { Item } } </script>Copy the code
API
wepy.event
wepy.component
wepy.page
wepy.app
CHANGELOG
1.3.1 (2016-12-16)
-
Added support for third-party Compiler
-
Added puG compiler
-
Reorganize the code structure to maintain different NPM packages using LerNA
-
Re-process the Plugins, again to a third-party package
-
Added logic to check if the dependent Compiler or Plugins are missing at compile-time and install them if they are missing
-
Added the cli tool version check function
1.1.9 (2016-12-14)
-
Added the wepy upgrade command to upgrade wepyJS
-
Added support for third-party components
-
Added third party components [wepy-com-toast]
-
Add the Toast component test to the template
1.1.8 (2016-12-08)
-
Fixed a BUG with script using SRC external chain
-
Fixed a BUG where LESS compilation would call SASS
-
Optimized event transmission parameters to support direct parameter transmission
-
Joined Travis-CI and Coveralls
-
Fix other detail bugs
1.1.7 (2016-12-06)
-
The script/template/style attributes support both type and lang
-
Add mixins support
1.1.6 (2016-12-02)
-
Fixed an issue where component IDS could not be identified in uppercase
-
Added support for all response events on applet pages
-
Modify wepy.config.js to support plugins
-
Add UglifyJsPlugin to compress all generated JS files at compile time
-
Add ImageMinPlugin(not recommended, problems with large images)
-
Add the wepy build –no-cache parameter to recompile all dependent files at compile time
-
When wepy new demo, instead of generating projects in the current directory, create a demo directory, and then regenerate projects
-
Update Generate Demo to support the latest functions
1.1.4 (2016-12-01)
-
Added support for other page events in applet
-
Change the default configuration file wepyrc to wepy.config.js for future extension. (Compatible with old configuration files)
1.1.3 (2016-11-28)
-
Fix SASS compilation exception cause watch end BUG
-
Fixed BUG where child component changes do not trigger parent component updates
-
Repair $invoke (‘.. Bugs/’)
-
Fix page onLoad event pass parameter BUG
1.1.1 (2016-11-23)
-
Added compilation support for SASS/SCSS
-
Wepyrc added support for less/ sASS configuration
-
Wepyrc adds the wpyExt option
-
Updating the Build template
Finally, thanks to @BrianLiu, @XMagicwu and other members of the team for their help in the development process.