├── .gitignore
├── LICENSE
├── README.md
└── examples
├── address-book
├── .eslintrc.js
├── app.js
├── app.json
├── app.wxss
├── components
│ ├── address-book
│ │ ├── index.js
│ │ ├── index.json
│ │ ├── index.wxml
│ │ └── index.wxss
│ └── navigation-bar
│ │ ├── index.js
│ │ ├── index.json
│ │ ├── index.wxml
│ │ └── index.wxss
├── pages
│ └── index
│ │ ├── data.js
│ │ ├── index.js
│ │ ├── index.json
│ │ ├── index.wxml
│ │ └── index.wxss
├── project.config.json
├── project.private.config.json
└── sitemap.json
├── album
├── app.js
├── app.json
├── app.wxss
├── components
│ ├── album
│ │ ├── album-image
│ │ │ ├── index.js
│ │ │ ├── index.json
│ │ │ ├── index.wxml
│ │ │ └── index.wxss
│ │ ├── index.js
│ │ ├── index.json
│ │ ├── index.wxml
│ │ ├── index.wxss
│ │ └── route.js
│ ├── navigation-bar
│ │ ├── index.js
│ │ ├── index.json
│ │ ├── index.wxml
│ │ └── index.wxss
│ └── previewer
│ │ ├── index.js
│ │ ├── index.json
│ │ ├── index.wxml
│ │ ├── index.wxss
│ │ ├── preview-home
│ │ ├── index.js
│ │ ├── index.json
│ │ ├── index.wxml
│ │ └── index.wxss
│ │ ├── preview-image
│ │ ├── index.js
│ │ ├── index.json
│ │ ├── index.wxml
│ │ └── index.wxss
│ │ └── preview-list
│ │ ├── index.js
│ │ ├── index.json
│ │ ├── index.wxml
│ │ └── index.wxss
├── pages
│ ├── album
│ │ ├── index.js
│ │ ├── index.json
│ │ ├── index.wxml
│ │ └── index.wxss
│ └── preview
│ │ ├── index.js
│ │ ├── index.json
│ │ ├── index.wxml
│ │ └── index.wxss
├── project.config.json
├── project.private.config.json
├── resources
│ └── back.png
├── sitemap.json
└── utils
│ ├── event-bus.js
│ ├── store.js
│ └── worklet.js
├── app-bar
├── .eslintrc.js
├── app-bar
│ ├── index.js
│ ├── index.json
│ ├── index.wxml
│ └── index.wxss
├── app.js
├── app.json
├── app.wxss
├── assets
│ ├── arrow-down.png
│ ├── next.png
│ └── play.png
├── components
│ └── navigation-bar
│ │ ├── navigation-bar.js
│ │ ├── navigation-bar.json
│ │ ├── navigation-bar.wxml
│ │ └── navigation-bar.wxss
├── pages
│ ├── detail
│ │ ├── index.js
│ │ ├── index.json
│ │ ├── index.wxml
│ │ └── index.wxss
│ └── index
│ │ ├── index.js
│ │ ├── index.json
│ │ ├── index.wxml
│ │ └── index.wxss
├── project.config.json
├── project.private.config.json
└── sitemap.json
├── associated-scroll-view
├── .eslintrc.js
├── app.js
├── app.json
├── app.wxss
├── components
│ └── category-list
│ │ ├── category-list.js
│ │ ├── category-list.json
│ │ ├── category-list.wxml
│ │ └── category-list.wxss
├── pages
│ └── index
│ │ ├── index.js
│ │ ├── index.json
│ │ ├── index.wxml
│ │ └── index.wxss
├── project.config.json
├── project.private.config.json
├── sitemap.json
└── util.js
├── card_transition
├── app.js
├── app.json
├── app.wxss
├── components
│ ├── card
│ │ ├── card.js
│ │ ├── card.json
│ │ ├── card.wxml
│ │ └── card.wxss
│ └── navigation-bar
│ │ ├── index.js
│ │ ├── index.json
│ │ ├── index.wxml
│ │ └── index.wxss
├── pages
│ ├── detail
│ │ ├── detail.js
│ │ ├── detail.json
│ │ ├── detail.wxml
│ │ └── detail.wxss
│ └── list
│ │ ├── list.js
│ │ ├── list.json
│ │ ├── list.wxml
│ │ ├── list.wxss
│ │ ├── route.js
│ │ └── utils.js
├── project.config.json
├── project.private.config.json
└── sitemap.json
├── expanded-scroll-view
├── .eslintrc.js
├── app.js
├── app.json
├── app.wxss
├── pages
│ └── index
│ │ ├── index.js
│ │ ├── index.json
│ │ ├── index.wxml
│ │ └── index.wxss
├── project.config.json
├── project.private.config.json
├── sitemap.json
└── util.js
├── half-screen
├── .eslintrc.js
├── app.js
├── app.json
├── app.wxss
├── pages
│ └── index
│ │ ├── comment-data.js
│ │ ├── index.js
│ │ ├── index.json
│ │ ├── index.wxml
│ │ └── index.wxss
├── project.config.json
├── project.private.config.json
└── sitemap.json
├── product-list
├── .eslintrc.js
├── app.js
├── app.json
├── app.wxss
├── components
│ └── navigation-bar
│ │ ├── index.js
│ │ ├── index.json
│ │ ├── index.wxml
│ │ └── index.wxss
├── images
│ └── search.png
├── pages
│ └── index
│ │ ├── index.js
│ │ ├── index.json
│ │ ├── index.wxml
│ │ └── index.wxss
├── project.config.json
├── project.private.config.json
├── sitemap.json
└── util.js
├── refresher-two-level
├── app.js
├── app.json
├── app.wxss
├── components
│ └── navigation-bar
│ │ ├── index.js
│ │ ├── index.json
│ │ ├── index.wxml
│ │ └── index.wxss
├── goods.less
├── goods.wxml
├── goods
│ ├── index.json
│ ├── index.less
│ ├── index.ts
│ └── index.wxml
├── images
│ ├── back_delete.png
│ └── search.png
├── index
│ ├── index.json
│ ├── index.less
│ ├── index.ts
│ └── index.wxml
├── project.config.json
└── util.js
├── segmented-half-screen
├── .eslintrc.js
├── app.js
├── app.json
├── app.wxss
├── pages
│ └── index
│ │ ├── comment-data.js
│ │ ├── index.js
│ │ ├── index.json
│ │ ├── index.wxml
│ │ └── index.wxss
├── project.config.json
├── project.private.config.json
└── sitemap.json
└── tab-indicator
├── .eslintrc.js
├── app.js
├── app.json
├── app.wxss
├── components
└── navigation-bar
│ ├── index.js
│ ├── index.json
│ ├── index.wxml
│ └── index.wxss
├── pages
└── index
│ ├── index.js
│ ├── index.json
│ ├── index.wxml
│ └── index.wxss
├── project.config.json
├── project.private.config.json
└── sitemap.json
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 wechat-miniprogram
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # awesome-skyline
2 |
3 | Skyline 是微信小程序推出的新渲染引擎,用于替代 WebView 渲染,其能够带来更好的渲染性能,并且添加了诸多增强特性,让小程序拥有更接近原生的交互体验。更多细节可查看[文档](https://developers.weixin.qq.com/miniprogram/dev/framework/runtime/skyline/introduction.html)。
4 |
5 | ## 示例集
6 |
7 | - [通讯录](./examples/address-book)
8 | - [相册](./examples/album)
9 | - [卡片转场](./examples/card_transition)
10 | - [半屏弹窗](./examples/half-screen)
11 | - [分段式半屏](./examples/segmented-half-screen)
12 | - [Tab 指示条](./examples/tab-indicator)
13 | - [搜索栏吸附](./examples/product-list)
14 | - [沉浸式商品浏览](./examples/expanded-scroll-view)
15 | - [分类列表联动](./examples/associated-scroll-view)
16 |
--------------------------------------------------------------------------------
/examples/address-book/.eslintrc.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Eslint config file
3 | * Documentation: https://eslint.org/docs/user-guide/configuring/
4 | * Install the Eslint extension before using this feature.
5 | */
6 | module.exports = {
7 | env: {
8 | es6: true,
9 | browser: true,
10 | node: true,
11 | },
12 | ecmaFeatures: {
13 | modules: true,
14 | },
15 | parserOptions: {
16 | ecmaVersion: 2018,
17 | sourceType: 'module',
18 | },
19 | globals: {
20 | wx: true,
21 | App: true,
22 | Page: true,
23 | getCurrentPages: true,
24 | getApp: true,
25 | Component: true,
26 | requirePlugin: true,
27 | requireMiniProgram: true,
28 | },
29 | // extends: 'eslint:recommended',
30 | rules: {},
31 | }
32 |
--------------------------------------------------------------------------------
/examples/address-book/app.js:
--------------------------------------------------------------------------------
1 | // app.js
2 | App({})
3 |
--------------------------------------------------------------------------------
/examples/address-book/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "pages": [
3 | "pages/index/index"
4 | ],
5 | "window": {
6 | "backgroundTextStyle": "light",
7 | "navigationBarBackgroundColor": "#fff",
8 | "navigationBarTitleText": "Weixin",
9 | "navigationBarTextStyle": "black"
10 | },
11 | "style": "v2",
12 | "renderer": "skyline",
13 | "rendererOptions": {
14 | "skyline": {
15 | "defaultDisplayBlock": true,
16 | "disableABTest": true,
17 | "sdkVersionBegin": "3.0.0",
18 | "sdkVersionEnd": "15.255.255"
19 | }
20 | },
21 | "lazyCodeLoading": "requiredComponents",
22 | "componentFramework": "glass-easel",
23 | "sitemapLocation": "sitemap.json"
24 | }
--------------------------------------------------------------------------------
/examples/address-book/app.wxss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wechat-miniprogram/awesome-skyline/25e2d93c2daf3f78d0908ff53ea305147d0c8978/examples/address-book/app.wxss
--------------------------------------------------------------------------------
/examples/address-book/components/address-book/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {},
4 | "addGlobalClass": false,
5 | "componentFramework": "glass-easel"
6 | }
--------------------------------------------------------------------------------
/examples/address-book/components/address-book/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
12 |
13 | {{item.alpha}}
14 |
15 |
16 |
17 | {{subItem.name}}
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | {{alpha}}
32 |
33 | {{alpha}}
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/examples/address-book/components/address-book/index.wxss:
--------------------------------------------------------------------------------
1 | .wx-flex {
2 | display: flex;
3 | align-items: center
4 | }
5 |
6 | .scroll-view {
7 | height: 100%;
8 | }
9 |
10 | .thin-border-bottom {
11 | position: relative
12 | }
13 |
14 | .thin-border-top {
15 | position: relative
16 | }
17 |
18 | .square-tag {
19 | color: #9a9a9a;
20 | text-align: center;
21 | height: 30px;
22 | line-height: 30px;
23 | box-sizing: border-box;
24 | border-radius: 2px;
25 | background-color: #f7f7f7;
26 | font-size: 12px;
27 | position: relative
28 | }
29 |
30 | .square-tag.selected {
31 | background: rgba(26, 173, 25, 0.1);
32 | color: #1AAD19
33 | }
34 |
35 | .select-city__hd {
36 | padding: 0 15px;
37 | position: fixed;
38 | height: 50px;
39 | background-color: #fff;
40 | left: 0;
41 | right: 0;
42 | z-index: 990
43 | }
44 |
45 | .current-city__name {
46 | display: inline-block;
47 | margin-right: 10px;
48 | margin-left: 11px
49 | }
50 |
51 | .city-group_part .city-group__title {
52 | padding-bottom: 12px
53 | }
54 |
55 | .city-group__title {
56 | padding: 12px 12px 11px
57 | }
58 |
59 | .square-tag {
60 | width: 100px;
61 | display: inline-block;
62 | margin-right: 12px;
63 | margin-bottom: 12px;
64 | height: 40px;
65 | line-height: 40px;
66 | font-size: 15px;
67 | color: #000;
68 | background-color: rgba(0, 0, 0, 0.02);
69 | overflow: hidden;
70 | white-space: nowrap;
71 | text-overflow: ellipsis
72 | }
73 |
74 | .city-group__item {
75 | padding: 15px 12px;
76 | font-size: 15px
77 | }
78 |
79 | .city-group_all {
80 | padding-bottom: 50px
81 | }
82 |
83 | .fixed__top {
84 | position: fixed;
85 | top: 0
86 | }
87 |
88 | .anchor-bar__wrp {
89 | position: fixed;
90 | top: 0;
91 | bottom: 0;
92 | right: 0;
93 | width: 30px;
94 | z-index: 999
95 | }
96 |
97 | .anchor-item {
98 | font-size: 0;
99 | text-align: center;
100 | position: relative
101 | }
102 |
103 | .anchor-item__inner {
104 | line-height: 10px;
105 | height: 14px;
106 | width: 14px;
107 | border-radius: 50%;
108 | display: flex;
109 | align-items: center;
110 | justify-content: center;
111 | font-size: 10px;
112 | margin: 1px 0;
113 | font-weight: 500
114 | }
115 |
116 | .tapped .anchor-item__pop {
117 | display: flex;
118 | }
119 |
120 | .anchor-item__pop {
121 | position: absolute;
122 | font-size: 50px;
123 | width: 55px;
124 | height: 55px;
125 | line-height: 45px;
126 | color: #fff;
127 | background-color: #C9C9C9;
128 | border-radius: 50%;
129 | border: 5px solid transparent;
130 | right: 40px;
131 | top: 50%;
132 | transform: translateY(-50%);
133 | display: none;
134 | box-sizing: border-box;
135 | align-items: center;
136 | justify-content: center;
137 | }
138 |
139 | .anchor-item__pop_after {
140 | position: absolute;
141 | width: 0;
142 | height: 0;
143 | left: 42px;
144 | border: 20px solid;
145 | border-color: transparent transparent transparent #C9C9C9;
146 | top: 50%;
147 | transform: translateY(-50%)
148 | }
149 |
150 | .anchor-item.selected .anchor-item__inner {
151 | color: #fff;
152 | background-color: #1aad19
153 | }
154 |
155 | .right-directory {
156 | position: absolute;
157 | top: 0;
158 | right: 0;
159 | z-index: 1;
160 | width: 30px;
161 | height: 100vh;
162 | justify-content: center;
163 | flex-direction: column;
164 | }
165 | .anchor-bar {
166 | display: flex;
167 | flex-direction: column;
168 | align-items: center;
169 | width: 30px;
170 | }
171 |
172 | .tips-color {
173 | color: #5d5d5d;
174 | background-color: #EAEAEA;
175 | font-weight: bold;
176 | }
177 |
178 | sticky-header {
179 | position: sticky;
180 | top: 0;
181 | z-index: 1;
182 | display: block;
183 | }
184 |
--------------------------------------------------------------------------------
/examples/address-book/components/navigation-bar/index.js:
--------------------------------------------------------------------------------
1 | Component({
2 | options: {
3 | multipleSlots: true // 在组件定义时的选项中启用多slot支持
4 | },
5 | /**
6 | * 组件的属性列表
7 | */
8 | properties: {
9 | extClass: {
10 | type: String,
11 | value: ''
12 | },
13 | title: {
14 | type: String,
15 | value: ''
16 | },
17 | background: {
18 | type: String,
19 | value: ''
20 | },
21 | color: {
22 | type: String,
23 | value: ''
24 | },
25 | back: {
26 | type: Boolean,
27 | value: true
28 | },
29 | loading: {
30 | type: Boolean,
31 | value: false
32 | },
33 | animated: {
34 | // 显示隐藏的时候opacity动画效果
35 | type: Boolean,
36 | value: true
37 | },
38 | show: {
39 | // 显示隐藏导航,隐藏的时候navigation-bar的高度占位还在
40 | type: Boolean,
41 | value: true,
42 | observer: '_showChange'
43 | },
44 | // back为true的时候,返回的页面深度
45 | delta: {
46 | type: Number,
47 | value: 1
48 | }
49 | },
50 | /**
51 | * 组件的初始数据
52 | */
53 | data: {
54 | displayStyle: ''
55 | },
56 | attached() {
57 | const rect = wx.getMenuButtonBoundingClientRect()
58 | wx.getSystemInfo({
59 | success: (res) => {
60 | this.setData({
61 | statusBarHeight: res.statusBarHeight,
62 | innerPaddingRight: `padding-right:${res.windowWidth - rect.left}px`,
63 | leftWidth: `width:${res.windowWidth - rect.left}px`,
64 | navBarHeight: rect.bottom + rect.top - res.statusBarHeight,
65 | })
66 | }
67 | })
68 | },
69 | /**
70 | * 组件的方法列表
71 | */
72 | methods: {
73 | _showChange(show) {
74 | const animated = this.data.animated
75 | let displayStyle = ''
76 | if (animated) {
77 | displayStyle = `opacity: ${show ? '1' : '0'};transition: opacity 0.5s;`
78 | } else {
79 | displayStyle = `display: ${show ? '' : 'none'}`
80 | }
81 | this.setData({
82 | displayStyle
83 | })
84 | },
85 | back() {
86 | const data = this.data
87 | if (data.delta) {
88 | wx.navigateBack({
89 | delta: data.delta
90 | })
91 | }
92 | this.triggerEvent('back', { delta: data.delta }, {})
93 | }
94 | }
95 | })
96 |
--------------------------------------------------------------------------------
/examples/address-book/components/navigation-bar/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {},
4 | "addGlobalClass": true,
5 | "componentFramework": "glass-easel"
6 | }
--------------------------------------------------------------------------------
/examples/address-book/components/navigation-bar/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | {{title}}
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/examples/address-book/components/navigation-bar/index.wxss:
--------------------------------------------------------------------------------
1 | .weui-navigation-bar {
2 | overflow: hidden;
3 | color: rgba(0, 0, 0, .9);
4 | width: 100vw;
5 | }
6 |
7 | .weui-navigation-bar__placeholder {
8 | background: #f7f7f7;
9 | position: relative;
10 | }
11 |
12 | .weui-navigation-bar__inner, .weui-navigation-bar__inner .weui-navigation-bar__left {
13 | display: flex;
14 | align-items: center;
15 | flex-direction: row;
16 | }
17 |
18 | .weui-navigation-bar__inner {
19 | position: relative;
20 | padding-right: 95px;
21 | width: 100vw;
22 | box-sizing: border-box;
23 | }
24 |
25 | .weui-navigation-bar__inner .weui-navigation-bar__left {
26 | position: relative;
27 | width: 95px;
28 | padding-left: 16px;
29 | box-sizing: border-box;
30 | }
31 |
32 | .weui-navigation-bar__btn_goback_wrapper {
33 | padding: 11px 18px 11px 16px;
34 | margin: -11px -18px -11px -16px;
35 | }
36 |
37 | .weui-navigation-bar__inner .weui-navigation-bar__left .navigation-bar__btn_goback {
38 | font-size: 12px;
39 | width: 12px;
40 | height: 24px;
41 | background: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='24' viewBox='0 0 12 24'%3E %3Cpath fill-opacity='.9' fill-rule='evenodd' d='M10 19.438L8.955 20.5l-7.666-7.79a1.02 1.02 0 0 1 0-1.42L8.955 3.5 10 4.563 2.682 12 10 19.438z'/%3E%3C/svg%3E") no-repeat 50% 50%;
42 | background-size: cover;
43 | }
44 |
45 | .weui-navigation-bar__inner .weui-navigation-bar__center {
46 | font-size: 17px;
47 | text-align: center;
48 | position: relative;
49 | flex: 1;
50 | display: flex;
51 | flex-direction: column;
52 | align-items: center;
53 | justify-content: center;
54 | font-weight: bold;
55 | }
56 |
57 | @media(prefers-color-scheme: dark) {
58 | .weui-navigation-bar {
59 | color: hsla(0, 0%, 100%, .8);
60 | }
61 | .weui-navigation-bar__inner {
62 | background-color: #1f1f1f;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/examples/address-book/pages/index/index.js:
--------------------------------------------------------------------------------
1 | import {cityData} from './data'
2 |
3 | Component({
4 | data: {
5 | list: [],
6 | },
7 | lifetimes: {
8 | attached() {
9 | const cities = cityData
10 | // 按拼音排序
11 | cities.sort((c1, c2) => {
12 | const pinyin1 = c1.pinyin.join('')
13 | const pinyin2 = c2.pinyin.join('')
14 | return pinyin1.localeCompare(pinyin2)
15 | })
16 | // 添加首字母
17 | const map = new Map()
18 | for (const city of cities) {
19 | const alpha = city.pinyin[0].charAt(0).toUpperCase()
20 | if (!map.has(alpha)) map.set(alpha, [])
21 | map.get(alpha).push({ name: city.fullname })
22 | }
23 |
24 | const keys = []
25 | for (const key of map.keys()) {
26 | keys.push(key)
27 | }
28 | keys.sort()
29 |
30 | const list = []
31 | for (const key of keys) {
32 | list.push({
33 | alpha: key,
34 | subItems: map.get(key)
35 | })
36 | }
37 |
38 | console.log('address-book list:', list)
39 | this.setData({ list })
40 | },
41 | },
42 | })
43 |
--------------------------------------------------------------------------------
/examples/address-book/pages/index/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "usingComponents": {
3 | "navigation-bar": "../../components/navigation-bar",
4 | "address-book": "../../components/address-book"
5 | },
6 | "disableScroll": true,
7 | "navigationStyle": "custom"
8 | }
--------------------------------------------------------------------------------
/examples/address-book/pages/index/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Address Book
7 | 类通讯录列表
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/examples/address-book/pages/index/index.wxss:
--------------------------------------------------------------------------------
1 | page {
2 | display: flex;
3 | flex-direction: column;
4 | align-items: flex-end;
5 | height: 100vh;
6 | background-color: #f7f7f7;
7 | }
8 |
9 | .page-container {
10 | width: 100vw;
11 | flex: 1;
12 | overflow: hidden;
13 | }
14 |
15 | .page {
16 | color: rgba(0, 0, 0, .9);
17 | font-size: 16px;
18 | font-family: -apple-system-font, Helvetica Neue, Helvetica, sans-serif;
19 | }
20 |
21 | .page__hd {
22 | padding: 40px
23 | }
24 |
25 | .page__bd {
26 | padding-bottom: 40px
27 | }
28 |
29 | .page__title {
30 | text-align: left;
31 | font-size: 20px;
32 | font-weight: 400
33 | }
34 |
35 | .page__desc {
36 | margin-top: 5px;
37 | color: rgba(0, 0, 0, .5);
38 | text-align: left;
39 | font-size: 14px
40 | }
41 |
42 | .header {
43 | height: 100px;
44 | }
45 |
46 | .cell {
47 | height: 50px;
48 | justify-content: center;
49 | align-items: center;
50 | }
--------------------------------------------------------------------------------
/examples/address-book/project.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "appid": "wxe5f52902cf4de896",
3 | "compileType": "miniprogram",
4 | "libVersion": "latest",
5 | "packOptions": {
6 | "ignore": [],
7 | "include": []
8 | },
9 | "setting": {
10 | "coverView": true,
11 | "es6": true,
12 | "postcss": true,
13 | "minified": true,
14 | "enhance": true,
15 | "showShadowRootInWxmlPanel": true,
16 | "packNpmRelationList": [],
17 | "babelSetting": {
18 | "ignore": [],
19 | "disablePlugins": [],
20 | "outputPath": ""
21 | },
22 | "condition": false,
23 | "skylineRenderEnable": true,
24 | "compileWorklet": true
25 | },
26 | "condition": {},
27 | "editorSetting": {
28 | "tabIndent": "insertSpaces",
29 | "tabSize": 2
30 | },
31 | "projectname": "address-book"
32 | }
--------------------------------------------------------------------------------
/examples/address-book/project.private.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html",
3 | "projectname": "address-book",
4 | "setting": {
5 | "compileHotReLoad": false,
6 | "skylineRenderEnable": true
7 | },
8 | "libVersion": "latest"
9 | }
--------------------------------------------------------------------------------
/examples/address-book/sitemap.json:
--------------------------------------------------------------------------------
1 | {
2 | "desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html",
3 | "rules": [{
4 | "action": "allow",
5 | "page": "*"
6 | }]
7 | }
--------------------------------------------------------------------------------
/examples/album/app.js:
--------------------------------------------------------------------------------
1 | App({})
2 |
--------------------------------------------------------------------------------
/examples/album/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "pages": [
3 | "pages/album/index",
4 | "pages/preview/index"
5 | ],
6 | "window": {
7 | "backgroundColor": "#ffffff",
8 | "backgroundTextStyle": "dark",
9 | "navigationBarBackgroundColor": "#ffffff",
10 | "navigationBarTitleText": "",
11 | "navigationBarTextStyle": "black"
12 | },
13 | "style": "v2",
14 | "sitemapLocation": "sitemap.json",
15 | "lazyCodeLoading": "requiredComponents",
16 | "componentFramework": "glass-easel",
17 | "renderer": "skyline",
18 | "rendererOptions": {
19 | "skyline": {
20 | "defaultDisplayBlock": true,
21 | "disableABTest": true,
22 | "sdkVersionBegin": "3.0.0",
23 | "sdkVersionEnd": "15.255.255"
24 | }
25 | }
26 | }
--------------------------------------------------------------------------------
/examples/album/app.wxss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wechat-miniprogram/awesome-skyline/25e2d93c2daf3f78d0908ff53ea305147d0c8978/examples/album/app.wxss
--------------------------------------------------------------------------------
/examples/album/components/album/album-image/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {},
4 | "componentFramework": "glass-easel"
5 | }
--------------------------------------------------------------------------------
/examples/album/components/album/album-image/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/examples/album/components/album/album-image/index.wxss:
--------------------------------------------------------------------------------
1 | .share-element {
2 | position: relative;
3 | width: 100%;
4 | height: 100%;
5 | }
6 |
7 | .img-cut-cnt {
8 | position: absolute;
9 | top: 0;
10 | left: 0;
11 | width: 100%;
12 | height: 100%;
13 | background-color: transparent;
14 | overflow: hidden;
15 | }
16 |
17 | .img {
18 | position: absolute;
19 | top: 50%;
20 | left: 50%;
21 | width: 100%;
22 | height: 100%;
23 | transform: translate(-50%, -50%);
24 | transform-origin: center;
25 | z-index: 5;
26 | }
27 |
--------------------------------------------------------------------------------
/examples/album/components/album/index.js:
--------------------------------------------------------------------------------
1 | import EventBus from '../../utils/event-bus'
2 | import { initRoute } from './route'
3 |
4 | function transformListToLineBlock(list, lineLimit) {
5 | const lineList = []
6 | for (let i = 0, len = list.length; i < len; i += lineLimit) {
7 | const line = { index: Math.floor(i / lineLimit), list: [] }
8 | for (let j = 0; j < lineLimit; j++) {
9 | const index = i + j
10 | const item = list[index]
11 | if (item) line.list.push({
12 | ...item,
13 | index,
14 | })
15 | }
16 | lineList.push(line)
17 | }
18 | return lineList
19 | }
20 |
21 | Component({
22 | properties: {
23 | list: {
24 | type: Array,
25 | value: [],
26 | },
27 |
28 | imageWidth: {
29 | type: Number,
30 | value: 0,
31 | },
32 |
33 | imageMargin: {
34 | type: Number,
35 | value: 0,
36 | },
37 |
38 | lineLimit: {
39 | type: Number,
40 | value: 3,
41 | },
42 | },
43 |
44 | data: {
45 | showList: [],
46 | scrollIntoView: '',
47 | },
48 |
49 | observers: {
50 | 'list, lineLimit'(list, lineLimit) {
51 | if (!list.length || !lineLimit) return
52 |
53 | // 调整为行结构,每行自己排版
54 | this.setData({
55 | showList: transformListToLineBlock(list, lineLimit),
56 | })
57 | },
58 | },
59 |
60 | lifetimes: {
61 | created() {
62 | EventBus.initWorkletEventBus(this.renderer) // 初始化 ui 线程的 eventBus
63 | initRoute() // 初始化自定义路由
64 | },
65 |
66 | attached() {
67 | // 预览页发生图片切换时,要将对应 image 滚动到到可视范围内
68 | const pageId = this.getPageId()
69 | let scrollIntoViewTimer = null
70 | this._onPreviewerChange = image => {
71 | const list = this.data.list
72 | const index = list.findIndex(item => item.id === image.id)
73 |
74 | if (index !== -1) {
75 | if (scrollIntoViewTimer) clearTimeout(scrollIntoViewTimer)
76 | scrollIntoViewTimer = setTimeout(() => {
77 | // 可能处于页面切换动画中,故加个延迟再滚动
78 | let lineIndex = Math.floor(index / this.data.lineLimit)
79 | this.setData({ scrollIntoView: `line-${lineIndex}` })
80 | }, 500)
81 | }
82 | }
83 | EventBus.on(`${pageId}PreviewerChange`, this._onPreviewerChange)
84 | },
85 |
86 | detached() {
87 | const pageId = this.getPageId()
88 | EventBus.off(`${pageId}PreviewerChange`, this._onPreviewerChange)
89 | },
90 | },
91 |
92 | methods: {
93 | onTapImage(evt) {
94 | const { index } = evt.currentTarget.dataset || {}
95 | const image = this.data.list[index]
96 | if (!image) return
97 |
98 | // 跳转到预览页
99 | wx.navigateTo({
100 | url: `../../pages/preview/index?imageid=${image.id}&sourcepageid=${this.getPageId()}`,
101 | routeType: 'fadeToggle',
102 | })
103 | },
104 | },
105 | })
106 |
--------------------------------------------------------------------------------
/examples/album/components/album/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {
4 | "album-image": "./album-image/index"
5 | },
6 | "componentFramework": "glass-easel"
7 | }
--------------------------------------------------------------------------------
/examples/album/components/album/index.wxml:
--------------------------------------------------------------------------------
1 |
9 |
17 |
18 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/examples/album/components/album/index.wxss:
--------------------------------------------------------------------------------
1 | .scroll-list {
2 | width: 100%;
3 | height: 100%;
4 | overflow: hidden;
5 | }
6 |
7 | .line {
8 | display: flex;
9 | flex-direction: row;
10 | justify-content: flex-start;
11 | }
12 |
13 | .album-image {
14 | width: 100%;
15 | height: 100%;
16 | }
17 |
--------------------------------------------------------------------------------
/examples/album/components/album/route.js:
--------------------------------------------------------------------------------
1 | const fastOutSlowIn = wx.worklet.Easing.bezier(0.4, 0.0, 0.2, 1.0).factory()
2 |
3 | export function initRoute() {
4 | wx.router.addRouteBuilder('fadeToggle', ({ primaryAnimation }) => {
5 | const handlePrimaryAnimation = () => {
6 | 'worklet'
7 | return {
8 | opacity: fastOutSlowIn(primaryAnimation.value),
9 | }
10 | }
11 |
12 | return {
13 | opaque: false,
14 | handlePrimaryAnimation,
15 | transitionDuration: 300,
16 | reverseTransitionDuration: 300,
17 | canTransitionTo: false,
18 | canTransitionFrom: false,
19 | }
20 | })
21 | }
22 |
--------------------------------------------------------------------------------
/examples/album/components/navigation-bar/index.js:
--------------------------------------------------------------------------------
1 | Component({
2 | options: {
3 | multipleSlots: true // 在组件定义时的选项中启用多slot支持
4 | },
5 | /**
6 | * 组件的属性列表
7 | */
8 | properties: {
9 | extClass: {
10 | type: String,
11 | value: ''
12 | },
13 | title: {
14 | type: String,
15 | value: ''
16 | },
17 | background: {
18 | type: String,
19 | value: ''
20 | },
21 | color: {
22 | type: String,
23 | value: ''
24 | },
25 | back: {
26 | type: Boolean,
27 | value: true
28 | },
29 | loading: {
30 | type: Boolean,
31 | value: false
32 | },
33 | animated: {
34 | // 显示隐藏的时候opacity动画效果
35 | type: Boolean,
36 | value: true
37 | },
38 | show: {
39 | // 显示隐藏导航,隐藏的时候navigation-bar的高度占位还在
40 | type: Boolean,
41 | value: true,
42 | observer: '_showChange'
43 | },
44 | // back为true的时候,返回的页面深度
45 | delta: {
46 | type: Number,
47 | value: 1
48 | }
49 | },
50 | /**
51 | * 组件的初始数据
52 | */
53 | data: {
54 | displayStyle: ''
55 | },
56 | attached() {
57 | const rect = wx.getMenuButtonBoundingClientRect()
58 | wx.getSystemInfo({
59 | success: (res) => {
60 | this.setData({
61 | statusBarHeight: res.statusBarHeight,
62 | innerPaddingRight: `padding-right:${res.windowWidth - rect.left}px`,
63 | leftWidth: `width:${res.windowWidth - rect.left}px`,
64 | navBarHeight: rect.bottom + rect.top - res.statusBarHeight,
65 | })
66 | }
67 | })
68 | },
69 | /**
70 | * 组件的方法列表
71 | */
72 | methods: {
73 | _showChange(show) {
74 | const animated = this.data.animated
75 | let displayStyle = ''
76 | if (animated) {
77 | displayStyle = `opacity: ${show ? '1' : '0'};transition: opacity 0.5s;`
78 | } else {
79 | displayStyle = `display: ${show ? '' : 'none'}`
80 | }
81 | this.setData({
82 | displayStyle
83 | })
84 | },
85 | back() {
86 | const data = this.data
87 | if (data.delta) {
88 | wx.navigateBack({
89 | delta: data.delta
90 | })
91 | }
92 | this.triggerEvent('back', { delta: data.delta }, {})
93 | }
94 | }
95 | })
96 |
--------------------------------------------------------------------------------
/examples/album/components/navigation-bar/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {},
4 | "addGlobalClass": true,
5 | "componentFramework": "glass-easel"
6 | }
--------------------------------------------------------------------------------
/examples/album/components/navigation-bar/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | {{title}}
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/examples/album/components/navigation-bar/index.wxss:
--------------------------------------------------------------------------------
1 | .weui-navigation-bar {
2 | overflow: hidden;
3 | color: rgba(0, 0, 0, .9);
4 | width: 100vw;
5 | }
6 |
7 | .weui-navigation-bar__placeholder {
8 | background: #f7f7f7;
9 | position: relative;
10 | }
11 |
12 | .weui-navigation-bar__inner, .weui-navigation-bar__inner .weui-navigation-bar__left {
13 | display: flex;
14 | align-items: center;
15 | flex-direction: row;
16 | }
17 |
18 | .weui-navigation-bar__inner {
19 | position: relative;
20 | padding-right: 95px;
21 | width: 100vw;
22 | box-sizing: border-box;
23 | }
24 |
25 | .weui-navigation-bar__inner .weui-navigation-bar__left {
26 | position: relative;
27 | width: 95px;
28 | padding-left: 16px;
29 | box-sizing: border-box;
30 | }
31 |
32 | .weui-navigation-bar__btn_goback_wrapper {
33 | padding: 11px 18px 11px 16px;
34 | margin: -11px -18px -11px -16px;
35 | }
36 |
37 | .weui-navigation-bar__inner .weui-navigation-bar__left .weui-navigation-bar__btn_goback {
38 | font-size: 12px;
39 | width: 12px;
40 | height: 24px;
41 | background: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='24' viewBox='0 0 12 24'%3E %3Cpath fill-opacity='.9' fill-rule='evenodd' d='M10 19.438L8.955 20.5l-7.666-7.79a1.02 1.02 0 0 1 0-1.42L8.955 3.5 10 4.563 2.682 12 10 19.438z'/%3E%3C/svg%3E") no-repeat 50% 50%;
42 | background-size: cover;
43 | }
44 |
45 | .weui-navigation-bar__inner .weui-navigation-bar__center {
46 | font-size: 17px;
47 | text-align: center;
48 | position: relative;
49 | flex: 1;
50 | display: flex;
51 | flex-direction: column;
52 | align-items: center;
53 | justify-content: center;
54 | font-weight: bold;
55 | }
56 |
57 | @media(prefers-color-scheme: dark) {
58 | .weui-navigation-bar {
59 | color: hsla(0, 0%, 100%, .8);
60 | }
61 | .weui-navigation-bar__inner {
62 | background-color: #1f1f1f;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/examples/album/components/previewer/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {
4 | "preview-home": "./preview-home/index"
5 | },
6 | "componentFramework": "glass-easel"
7 | }
--------------------------------------------------------------------------------
/examples/album/components/previewer/index.wxml:
--------------------------------------------------------------------------------
1 |
7 |
15 |
--------------------------------------------------------------------------------
/examples/album/components/previewer/index.wxss:
--------------------------------------------------------------------------------
1 | .preview-home {
2 | width: 100%;
3 | height: 100%;
4 | display: block;
5 | }
6 |
--------------------------------------------------------------------------------
/examples/album/components/previewer/preview-home/index.js:
--------------------------------------------------------------------------------
1 | import EventBus from '../../../utils/event-bus'
2 |
3 | Component({
4 | properties: {
5 | imageId: {
6 | type: String,
7 | value: '',
8 | },
9 | sourcePageId: {
10 | type: String,
11 | value: '',
12 | },
13 | list: {
14 | type: Array,
15 | value: [],
16 | },
17 | },
18 |
19 | data: {
20 | index: 0,
21 | tempIndex: -1,
22 | pretty: false,
23 | },
24 |
25 | observers: {
26 | tempIndex(tempIndex) {
27 | // 切换图片时会影响前一个页面的图片
28 | const { list, sourcePageId } = this.data
29 | const image = list[tempIndex]
30 | if (image) EventBus.emit(`${sourcePageId}PreviewerChange`, image)
31 | },
32 | },
33 |
34 | lifetimes: {
35 | attached() {
36 | const imageId = this.data.imageId
37 | const list = this.data.list
38 | let index = 0
39 | if (imageId) {
40 | const currentIndex = list.findIndex(item => item.id === imageId)
41 | if (currentIndex !== -1) index = currentIndex
42 | }
43 |
44 | this.setData({ index })
45 | },
46 |
47 | detached() {
48 | // 告诉前一个页面 previewer 将要销毁
49 | EventBus.emit(`${this.data.sourcePageId}PreviewerDestroy`)
50 | },
51 | },
52 |
53 | methods: {
54 | onBeforeRender(evt) {
55 | const { index } = evt.detail
56 |
57 | this.data.index = index // 切换可能来自 preview-list 里面,为避免造成循环触发 beforeRender,此处只改 data 不进行 setData
58 | this.setData({ tempIndex: index }) // 先更新快速预览栏
59 | },
60 |
61 | onTapImage() {
62 | this.setData({ pretty: !this.data.pretty })
63 | },
64 |
65 | onBack(evt) {
66 | this.triggerEvent('back', evt.detail)
67 | },
68 | },
69 | })
70 |
--------------------------------------------------------------------------------
/examples/album/components/previewer/preview-home/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {
4 | "preview-list": "../preview-list/index",
5 | "navigation-bar": "../../navigation-bar/index"
6 | },
7 | "componentFramework": "glass-easel"
8 | }
--------------------------------------------------------------------------------
/examples/album/components/previewer/preview-home/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
16 |
17 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/examples/album/components/previewer/preview-home/index.wxss:
--------------------------------------------------------------------------------
1 | .preview-cnt {
2 | position: absolute;
3 | left: 0;
4 | top: 0;
5 | width: 100vw;
6 | height: 100vh;
7 | z-index: 5;
8 | }
9 |
10 | .preview-list {
11 | width: 100vw;
12 | height: 100vh;
13 | background-color: #fff;
14 | }
15 |
16 | .need-hide-on-back {
17 | position: absolute;
18 | top: 0;
19 | left: 0;
20 | width: 100vw;
21 | height: 100vh;
22 | }
23 |
24 | .share-element-image {
25 | position: absolute;
26 | top: 0;
27 | left: 0;
28 | width: 100vw;
29 | height: 100vh;
30 | z-index: -1;
31 | background-color: transparent;
32 | }
33 |
34 | .share-element-image .temp-image {
35 | background-color: transparent;
36 | height: 100%;
37 | width: 100%;
38 | }
39 |
40 | .share-element-image .temp-image image {
41 | width: 100%;
42 | height: 100%;
43 | }
44 |
45 | .preview-middle-self {
46 | position: absolute;
47 | height: 100vh;
48 | width: 100vw;
49 | z-index: 0;
50 | background-color: #fff;
51 | }
52 |
53 | .navigation-bar-cnt {
54 | position: absolute;
55 | top: 0;
56 | left: 0;
57 | width: 100%;
58 | z-index: 10;
59 | transition: transform .3s ease, opacity .3s ease;
60 | }
61 |
62 | .navigation-bar-cnt.show {
63 | transform: none;
64 | opacity: 1;
65 | }
66 |
67 | .navigation-bar-cnt.hide {
68 | transform: translateY(-50px);
69 | opacity: 0;
70 | }
71 |
72 | .navigation-bar {
73 | position: absolute;
74 | top: 0;
75 | left: 0;
76 | width: 100%;
77 | z-index: 5;
78 | }
79 |
--------------------------------------------------------------------------------
/examples/album/components/previewer/preview-image/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {},
4 | "componentFramework": "glass-easel"
5 | }
--------------------------------------------------------------------------------
/examples/album/components/previewer/preview-image/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/examples/album/components/previewer/preview-image/index.wxss:
--------------------------------------------------------------------------------
1 | .double-tap-gesture-handler {
2 | display: block;
3 | width: 100%;
4 | height: 100%;
5 | }
6 |
7 | .image-wrapper {
8 | position: absolute;
9 | left: 0;
10 | top: 0;
11 | width: 100%;
12 | height: 100%;
13 | transform-origin: center;
14 | will-change: transform;
15 | }
16 |
17 | .image {
18 | width: 100%;
19 | height: 100%;
20 | }
21 |
--------------------------------------------------------------------------------
/examples/album/components/previewer/preview-list/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {
4 | "preview-image": "../preview-image/index"
5 | },
6 | "componentFramework": "glass-easel"
7 | }
--------------------------------------------------------------------------------
/examples/album/components/previewer/preview-list/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
17 |
18 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/examples/album/components/previewer/preview-list/index.wxss:
--------------------------------------------------------------------------------
1 |
2 | .image-previewer {
3 | width: 100vw;
4 | height: 100vh;
5 | overflow: hidden;
6 | }
7 |
8 | .swiper-cnt {
9 | display: flex;
10 | flex-direction: row;
11 | position: absolute;
12 | left: 0;
13 | top: 0;
14 | width: 100vw;
15 | height: 100vh;
16 | z-index: 20;
17 | }
18 |
19 | .image {
20 | display: block;
21 | width: 100%;
22 | height: 100%;
23 | }
24 |
--------------------------------------------------------------------------------
/examples/album/pages/album/index.js:
--------------------------------------------------------------------------------
1 | import { getAlbum } from '../../utils/store'
2 |
3 | Page({
4 | data: {
5 | imageWidth: 0,
6 | imageMargin: 12, // 图片间距
7 | lineLimit: 3, // 每行多少张图片
8 | list: [],
9 | },
10 |
11 | onLoad() {
12 | const { imageMargin, lineLimit } = this.data
13 | const { screenWidth } = wx.getSystemInfoSync()
14 | this.setData({
15 | imageWidth: (screenWidth - imageMargin * 4) / lineLimit, // 图片宽度
16 | list: getAlbum(),
17 | })
18 | },
19 | })
--------------------------------------------------------------------------------
/examples/album/pages/album/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "usingComponents": {
3 | "navigation-bar": "../../components/navigation-bar/index",
4 | "album": "../../components/album/index"
5 | },
6 | "disableScroll": true,
7 | "navigationStyle": "custom"
8 | }
--------------------------------------------------------------------------------
/examples/album/pages/album/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/examples/album/pages/album/index.wxss:
--------------------------------------------------------------------------------
1 | .cnt {
2 | position: absolute;
3 | top: 0;
4 | width: 100%;
5 | height: 100%;
6 | display: flex;
7 | flex-direction: column;
8 | }
9 |
10 | .album {
11 | height: 0;
12 | flex: 1;
13 | margin-bottom: 12px;
14 | }
15 |
16 | .safe-area-inset-bottom {
17 | height: env(safe-area-inset-bottom);
18 | }
19 |
--------------------------------------------------------------------------------
/examples/album/pages/preview/index.js:
--------------------------------------------------------------------------------
1 | import { getAlbum } from '../../utils/store'
2 |
3 | Component({
4 | properties: {
5 | imageid: {
6 | type: String,
7 | value: '',
8 | },
9 | sourcepageid: {
10 | type: String,
11 | value: '',
12 | },
13 | },
14 |
15 | data: {
16 | imageId: '',
17 | sourcePageId: '',
18 | list: [],
19 | },
20 |
21 | lifetimes: {
22 | attached() {
23 | // 因为页面的 onLoad 太迟,所以选用 component 构造器的 attached 生命周期来设置 shareKey,确保 share-element 动画正常执行
24 | const query = this.data
25 | const imageId = decodeURIComponent(query.imageid || '')
26 | const sourcePageId = decodeURIComponent(query.sourcepageid || '')
27 | const list = getAlbum()
28 | this.setData({ imageId, sourcePageId, list })
29 | },
30 | },
31 | })
32 |
--------------------------------------------------------------------------------
/examples/album/pages/preview/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "usingComponents": {
3 | "previewer": "../../components/previewer/index"
4 | },
5 | "navigationStyle": "custom",
6 | "backgroundColorContent": "#00000000",
7 | "disableScroll": true,
8 | "componentFramework": "glass-easel",
9 | "renderer": "skyline"
10 | }
11 |
--------------------------------------------------------------------------------
/examples/album/pages/preview/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/examples/album/pages/preview/index.wxss:
--------------------------------------------------------------------------------
1 | page {
2 | background-color: transparent;
3 | }
4 |
5 | .box-cotainer {
6 | width: 100vw;
7 | height: 100vh;
8 | position: relative;
9 | }
10 |
11 | .previewer {
12 | width: 100%;
13 | height: 100%;
14 | }
15 |
--------------------------------------------------------------------------------
/examples/album/project.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "项目配置文件",
3 | "packOptions": {
4 | "ignore": [],
5 | "include": []
6 | },
7 | "setting": {
8 | "bundle": false,
9 | "userConfirmedBundleSwitch": false,
10 | "urlCheck": true,
11 | "scopeDataCheck": false,
12 | "coverView": true,
13 | "es6": true,
14 | "postcss": true,
15 | "compileHotReLoad": false,
16 | "lazyloadPlaceholderEnable": false,
17 | "preloadBackgroundData": false,
18 | "minified": true,
19 | "autoAudits": false,
20 | "newFeature": false,
21 | "uglifyFileName": false,
22 | "uploadWithSourceMap": true,
23 | "useIsolateContext": true,
24 | "nodeModules": false,
25 | "enhance": true,
26 | "useMultiFrameRuntime": true,
27 | "useApiHook": true,
28 | "useApiHostProcess": true,
29 | "showShadowRootInWxmlPanel": true,
30 | "packNpmManually": false,
31 | "enableEngineNative": false,
32 | "packNpmRelationList": [],
33 | "minifyWXSS": true,
34 | "showES6CompileOption": false,
35 | "minifyWXML": true,
36 | "babelSetting": {
37 | "ignore": [],
38 | "disablePlugins": [],
39 | "outputPath": ""
40 | },
41 | "condition": false,
42 | "skylineRenderEnable": false,
43 | "compileWorklet": true
44 | },
45 | "compileType": "miniprogram",
46 | "libVersion": "latest",
47 | "appid": "wxe5f52902cf4de896",
48 | "projectname": "album-demo",
49 | "condition": {},
50 | "editorSetting": {
51 | "tabIndent": "insertSpaces",
52 | "tabSize": 2
53 | }
54 | }
--------------------------------------------------------------------------------
/examples/album/project.private.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html",
3 | "projectname": "album",
4 | "setting": {
5 | "compileHotReLoad": false,
6 | "skylineRenderEnable": true
7 | },
8 | "libVersion": "latest"
9 | }
--------------------------------------------------------------------------------
/examples/album/resources/back.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wechat-miniprogram/awesome-skyline/25e2d93c2daf3f78d0908ff53ea305147d0c8978/examples/album/resources/back.png
--------------------------------------------------------------------------------
/examples/album/sitemap.json:
--------------------------------------------------------------------------------
1 | {
2 | "desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html",
3 | "rules": [{
4 | "action": "allow",
5 | "page": "*"
6 | }]
7 | }
--------------------------------------------------------------------------------
/examples/album/utils/event-bus.js:
--------------------------------------------------------------------------------
1 | import { getRunOnUI } from './worklet'
2 |
3 | const map = {}
4 |
5 | function on(eventName, handler) {
6 | map[eventName] = map[eventName] || []
7 | map[eventName].push(handler)
8 | }
9 |
10 | function off(eventName, handler) {
11 | const handlerList = map[eventName]
12 | if (!handlerList || !handlerList.length) return
13 |
14 | const index = handlerList.indexOf(handler)
15 | if (index !== -1) handlerList.splice(index, 1)
16 | }
17 |
18 | function emit(eventName, ...args) {
19 | const handlerList = map[eventName]
20 | if (!handlerList || !handlerList.length) return
21 |
22 | for (let i = handlerList.length - 1; i >= 0; i--) {
23 | handlerList[i](...args)
24 | }
25 | }
26 |
27 | function initWorkletEventBus(renderer) {
28 | getRunOnUI(renderer)(() => {
29 | 'worklet'
30 | if (!globalThis.temp) globalThis.temp = {}
31 | if (!globalThis.eventBus) {
32 | const eventBus = {
33 | map: {},
34 | on(eventName, handler) {
35 | eventBus.map[eventName] = eventBus.map[eventName] || []
36 | eventBus.map[eventName].push(handler)
37 | },
38 | off(eventName, handler) {
39 | const handlerList = eventBus.map[eventName]
40 | if (!handlerList || !handlerList.length) return
41 |
42 | const index = handlerList.indexOf(handler)
43 | if (index !== -1) handlerList.splice(index, 1)
44 | },
45 | emit(eventName, args) {
46 | const handlerList = eventBus.map[eventName]
47 | if (!handlerList || !handlerList.length) return
48 |
49 | for (let i = handlerList.length - 1; i >= 0; i--) {
50 | handlerList[i](args)
51 | }
52 | },
53 | }
54 | globalThis.eventBus = eventBus
55 | }
56 | })()
57 | }
58 |
59 | export default {
60 | on,
61 | off,
62 | emit,
63 | initWorkletEventBus,
64 | }
65 |
--------------------------------------------------------------------------------
/examples/album/utils/worklet.js:
--------------------------------------------------------------------------------
1 | export function getShared(renderer) {
2 | if (renderer === 'skyline') return wx.worklet.shared
3 | else return val => ({ value: val })
4 | }
5 |
6 | export function getTiming(renderer) {
7 | 'worklet'
8 | if (renderer === 'skyline') return wx.worklet.timing
9 | else return (target, options, callback) => {
10 | if (typeof callback === 'function') setTimeout(callback, 0)
11 | return target
12 | }
13 | }
14 |
15 | export function getRunOnUI(renderer) {
16 | if (renderer === 'skyline') return wx.worklet.runOnUI
17 | else return func => func
18 | }
19 |
20 | export function getRunOnJS(renderer) {
21 | 'worklet'
22 | if (renderer === 'skyline') return wx.worklet.runOnJS
23 | else return func => func
24 | }
25 |
--------------------------------------------------------------------------------
/examples/app-bar/.eslintrc.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Eslint config file
3 | * Documentation: https://eslint.org/docs/user-guide/configuring/
4 | * Install the Eslint extension before using this feature.
5 | */
6 | module.exports = {
7 | env: {
8 | es6: true,
9 | browser: true,
10 | node: true,
11 | },
12 | ecmaFeatures: {
13 | modules: true,
14 | },
15 | parserOptions: {
16 | ecmaVersion: 2018,
17 | sourceType: 'module',
18 | },
19 | globals: {
20 | wx: true,
21 | App: true,
22 | Page: true,
23 | getCurrentPages: true,
24 | getApp: true,
25 | Component: true,
26 | requirePlugin: true,
27 | requireMiniProgram: true,
28 | },
29 | // extends: 'eslint:recommended',
30 | rules: {},
31 | }
32 |
--------------------------------------------------------------------------------
/examples/app-bar/app-bar/index.js:
--------------------------------------------------------------------------------
1 | // components/app-bar/index.js
2 |
3 | const { shared, timing, Easing } = wx.worklet
4 |
5 | export const GestureState = {
6 | POSSIBLE: 0,
7 | BEGIN: 1,
8 | ACTIVE: 2,
9 | END: 3,
10 | CANCELLED: 4,
11 | }
12 |
13 | export const lerp = function (begin, end, t) {
14 | 'worklet'
15 | return begin + (end - begin) * t
16 | }
17 |
18 | export const clamp = function (cur, lowerBound, upperBound) {
19 | 'worklet'
20 | if (cur > upperBound) return upperBound
21 | if (cur < lowerBound) return lowerBound
22 | return cur
23 | }
24 |
25 | const systemInfo = wx.getSystemInfoSync()
26 | const { statusBarHeight, screenHeight, screenWidth, safeArea } = systemInfo
27 | console.info('@@@ systemInfo', systemInfo)
28 | Component({
29 | properties: {
30 |
31 | },
32 |
33 | data: {
34 | maxCoverSize: 0,
35 | statusBarHeight: 0,
36 | musicCover: 'https://res.wx.qq.com/op_res/Nu9XXzXcXnD1j5EgWQ2ElxNcl1yMvnKypRo4MTbjOv7FC3saigGoOBTZibyESC7EXaClnPYhB6pvfb-IRmso6g'
37 | },
38 |
39 | lifetimes: {
40 | attached() {
41 | const progress = shared(0)
42 | const initCoverSize = 60 // 初始图片大小
43 | const pagePadding = 24
44 | const maxCoverSize = screenWidth - 2 * pagePadding
45 | const safeAreaInsetBottom = screenHeight - safeArea.bottom
46 | const isIOS = systemInfo.system.indexOf('iOS') >= 0
47 | this.setData({ statusBarHeight, maxCoverSize })
48 |
49 | this.applyAnimatedStyle('.cover', () => {
50 | 'worklet'
51 | const height = initCoverSize + (maxCoverSize - initCoverSize) * progress.value
52 | return {
53 | width: `${height}px`,
54 | height:`${height}px`,
55 | }
56 | })
57 |
58 | this.applyAnimatedStyle('.expand-container', () => {
59 | 'worklet'
60 | const t = progress.value
61 | const maxRadius = 30
62 | const radius = isIOS ? maxRadius * t : 0
63 | const initBarHeight = initCoverSize + 8 * 2 + safeAreaInsetBottom
64 | return {
65 | top: `${(screenHeight - initBarHeight) * (1 - t)}px`,
66 | borderRadius: `${radius}px ${radius}px 0px 0px`
67 | }
68 | })
69 |
70 | this.applyAnimatedStyle('.title-wrap', () => {
71 | 'worklet'
72 | return {
73 | opacity: 1 - progress.value
74 | }
75 | })
76 |
77 | const navBarHeight = statusBarHeight + (isIOS ? 40 : 44)
78 | this.applyAnimatedStyle('.nav-bar', () => {
79 | 'worklet'
80 | const t = progress.value
81 | const threshold = 0.8
82 | const opacity = t < threshold ? 0 : (t - threshold) / (1 - threshold)
83 |
84 | return {
85 | opacity,
86 | height: `${navBarHeight * progress.value}px`
87 | }
88 | })
89 |
90 | this.progress = progress
91 | }
92 | },
93 |
94 | methods: {
95 | close() {
96 | this.progress.value = timing(0, {
97 | duration: 250,
98 | easing: Easing.ease
99 | })
100 | },
101 |
102 | expand() {
103 | this.progress.value = timing(1, {
104 | duration: 250,
105 | easing: Easing.ease
106 | })
107 | },
108 |
109 | handleDragUpdate(delta) {
110 | 'worklet'
111 | const curValue = this.progress.value
112 | const newVal = curValue - delta
113 | this.progress.value = clamp(newVal, 0.0, 1.0)
114 | },
115 |
116 | handleDragEnd(velocity) {
117 | 'worklet'
118 | const t = this.progress.value
119 | let animateForward = false
120 | if (Math.abs(velocity) >= 1) {
121 | animateForward = velocity <= 0
122 | } else {
123 | animateForward = t > 0.7
124 | }
125 | const animationCurve = Easing.out(Easing.ease)
126 | if (animateForward) {
127 | this.progress.value = timing(
128 | 1.0, {
129 | duration: 200,
130 | easing: animationCurve,
131 | })
132 | } else {
133 | this.progress.value = timing(
134 | 0.0, {
135 | duration: 250,
136 | easing: animationCurve,
137 | })
138 | }
139 | },
140 |
141 | handleVerticalDrag(evt) {
142 | 'worklet'
143 | if (evt.state === GestureState.ACTIVE) {
144 | const delta = evt.deltaY / screenHeight
145 | this.handleDragUpdate(delta)
146 | } else if (evt.state === GestureState.END) {
147 | const velocity = evt.velocityY / screenHeight
148 | this.handleDragEnd(velocity)
149 | } else if (evt.state === GestureState.CANCELLED) {
150 | this.handleDragEnd(0.0)
151 | }
152 | },
153 | },
154 |
155 | })
--------------------------------------------------------------------------------
/examples/app-bar/app-bar/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {}
4 | }
--------------------------------------------------------------------------------
/examples/app-bar/app-bar/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | Skyline 渲染框架入门与实践
24 | 小程序技术专员 - binnie
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 | 微信学堂
37 | 88 人在学
38 |
39 |
40 |
41 |
42 | Skyline 渲染框架入门与实践
43 | 小程序技术专员 - binnie
44 |
45 |
46 |
47 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/examples/app-bar/app-bar/index.wxss:
--------------------------------------------------------------------------------
1 | .expand-container {
2 | position: absolute;
3 | top: 0;
4 | right: 0;
5 | bottom: 0;
6 | left: 0;
7 | padding: 0 24px;
8 | padding-bottom: env(safe-area-inset-bottom);
9 | pointer-events: auto;
10 | overflow: hidden;
11 | background-color: #e9f8f7;
12 | color: #7e8081;
13 | }
14 |
15 | .hide {
16 | display: none;
17 | }
18 |
19 | .nav-bar {
20 | overflow: hidden;
21 | box-sizing: border-box;
22 | }
23 |
24 | .icon--back {
25 | width: 30px;
26 | height: 30px;
27 | }
28 |
29 | .title {
30 | margin-left: 10px;
31 | min-width: 160px;
32 | flex: 1;
33 | }
34 | .title .name {
35 | margin-top: 4px;
36 | font-size: 12px;
37 | }
38 |
39 | .title-wrap {
40 | flex: 1;
41 | min-width: 240px;
42 | }
43 |
44 | .footer {
45 | padding: 0 24px;
46 | }
47 |
48 | .footer .icon {
49 | width: 40px;
50 | height: 40px;
51 | }
52 |
53 | .expand-cover {
54 | width: 100%;
55 | height: 100%;
56 | }
57 |
58 | .music-title {
59 | margin-top: 48px;
60 | font-size: 20px;
61 | font-weight: bold;
62 | color: #07c160;
63 | }
64 | .music-title .name {
65 | margin-top: 12px;
66 | font-size: 14px;
67 | font-weight: 200;
68 | color: #b1b2b3;
69 | }
70 |
71 | .cover-area {
72 | margin: 8px 0;
73 | width: 100%;
74 | aspect-ratio: 1 / 1;
75 | overflow: hidden;
76 | }
77 |
78 | .cover {
79 | /* aspect-ratio: 1 / 1; */
80 | flex-shrink: 0;
81 | }
82 |
83 | .icon {
84 | width: 18px;
85 | height: 18px;
86 | }
87 |
88 | .row {
89 | display: flex;
90 | flex-direction: row;
91 | align-items: center;
92 | }
93 |
94 | .row-between {
95 | display: flex;
96 | flex-direction: row;
97 | justify-content: space-between;
98 | align-items: center;
99 | }
100 |
101 | .column {
102 | display: flex;
103 | flex-direction: column;
104 | }
105 |
106 | .column-main-center {
107 | display: flex;
108 | flex-direction: column;
109 | justify-content: center;
110 | }
111 |
112 | .column-cross-center {
113 | display: flex;
114 | flex-direction: column;
115 | align-items: center;
116 | }
117 |
118 | .center {
119 | display: flex;
120 | align-items: center;
121 | justify-content: center;
122 | }
123 |
124 | .circle {
125 | width: 100%;
126 | height: 100%;
127 | overflow: hidden;
128 | border-radius: 50%;
129 | }
--------------------------------------------------------------------------------
/examples/app-bar/app.js:
--------------------------------------------------------------------------------
1 | // app.js
2 | App({})
3 |
--------------------------------------------------------------------------------
/examples/app-bar/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "pages": [
3 | "pages/index/index",
4 | "pages/detail/index"
5 | ],
6 | "window": {
7 | "navigationBarTextStyle": "black",
8 | "navigationStyle": "custom"
9 | },
10 | "style": "v2",
11 | "renderer": "skyline",
12 | "appBar": {},
13 | "rendererOptions": {
14 | "skyline": {
15 | "defaultDisplayBlock": true,
16 | "defaultContentBox": true,
17 | "disableABTest": true,
18 | "sdkVersionBegin": "3.0.0",
19 | "sdkVersionEnd": "15.255.255"
20 | }
21 | },
22 | "componentFramework": "glass-easel",
23 | "sitemapLocation": "sitemap.json",
24 | "lazyCodeLoading": "requiredComponents"
25 | }
--------------------------------------------------------------------------------
/examples/app-bar/app.wxss:
--------------------------------------------------------------------------------
1 | /**app.wxss**/
2 | .container {
3 | height: 100%;
4 | display: flex;
5 | flex-direction: column;
6 | align-items: center;
7 | justify-content: space-between;
8 | padding: 200rpx 0;
9 | box-sizing: border-box;
10 | }
11 |
--------------------------------------------------------------------------------
/examples/app-bar/assets/arrow-down.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wechat-miniprogram/awesome-skyline/25e2d93c2daf3f78d0908ff53ea305147d0c8978/examples/app-bar/assets/arrow-down.png
--------------------------------------------------------------------------------
/examples/app-bar/assets/next.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wechat-miniprogram/awesome-skyline/25e2d93c2daf3f78d0908ff53ea305147d0c8978/examples/app-bar/assets/next.png
--------------------------------------------------------------------------------
/examples/app-bar/assets/play.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wechat-miniprogram/awesome-skyline/25e2d93c2daf3f78d0908ff53ea305147d0c8978/examples/app-bar/assets/play.png
--------------------------------------------------------------------------------
/examples/app-bar/components/navigation-bar/navigation-bar.js:
--------------------------------------------------------------------------------
1 | Component({
2 | options: {
3 | multipleSlots: true // 在组件定义时的选项中启用多slot支持
4 | },
5 | /**
6 | * 组件的属性列表
7 | */
8 | properties: {
9 | extClass: {
10 | type: String,
11 | value: ''
12 | },
13 | title: {
14 | type: String,
15 | value: ''
16 | },
17 | background: {
18 | type: String,
19 | value: ''
20 | },
21 | color: {
22 | type: String,
23 | value: ''
24 | },
25 | back: {
26 | type: Boolean,
27 | value: true
28 | },
29 | loading: {
30 | type: Boolean,
31 | value: false
32 | },
33 | animated: {
34 | // 显示隐藏的时候opacity动画效果
35 | type: Boolean,
36 | value: true
37 | },
38 | show: {
39 | // 显示隐藏导航,隐藏的时候navigation-bar的高度占位还在
40 | type: Boolean,
41 | value: true,
42 | observer: '_showChange'
43 | },
44 | // back为true的时候,返回的页面深度
45 | delta: {
46 | type: Number,
47 | value: 1
48 | }
49 | },
50 | /**
51 | * 组件的初始数据
52 | */
53 | data: {
54 | displayStyle: ''
55 | },
56 | attached() {
57 | const isSupport = !!wx.getMenuButtonBoundingClientRect
58 | const rect = wx.getMenuButtonBoundingClientRect
59 | ? wx.getMenuButtonBoundingClientRect()
60 | : null
61 | wx.getSystemInfo({
62 | success: (res) => {
63 | const ios = !!(res.system.toLowerCase().search('ios') + 1)
64 | this.setData({
65 | ios,
66 | statusBarHeight: res.statusBarHeight,
67 | navBarHeight: rect.bottom - rect.top + 10,
68 | innerWidth: isSupport ? `width:${rect.left}px` : '',
69 | innerPaddingRight: isSupport
70 | ? `padding-right:${res.windowWidth - rect.left}px`
71 | : '',
72 | leftWidth: isSupport ? `width:${res.windowWidth - rect.left}px` : '',
73 | theme: res.theme || 'light',
74 | })
75 | }
76 | })
77 |
78 | if (wx.onThemeChange) {
79 | wx.onThemeChange(({theme}) => {
80 | this.setData({theme})
81 | })
82 | }
83 | },
84 | detached() {
85 | if (wx.offThemeChange) {
86 | wx.offThemeChange()
87 | }
88 | },
89 | /**
90 | * 组件的方法列表
91 | */
92 | methods: {
93 | _showChange(show) {
94 | const animated = this.data.animated
95 | let displayStyle = ''
96 | if (animated) {
97 | displayStyle = `opacity: ${
98 | show ? '1' : '0'
99 | };-webkit-transition:opacity 0.5s;transition:opacity 0.5s;`
100 | } else {
101 | displayStyle = `display: ${show ? '' : 'none'}`
102 | }
103 | this.setData({
104 | displayStyle
105 | })
106 | },
107 | back() {
108 | const data = this.data
109 | console.log('---------222',getCurrentPages().length)
110 | if (data.delta) {
111 | wx.navigateBack({
112 | delta: data.delta
113 | })
114 | }
115 | // 如果是直接打开的,就默认回首页
116 | if (getCurrentPages().length == 1) {
117 | console.log('---------333')
118 | wx.switchTab({
119 | url: '/page/component/index',
120 | complete: (res) => {
121 | console.log(res)
122 | }
123 | })
124 | }
125 | this.triggerEvent('back', { delta: data.delta }, {})
126 | }
127 | }
128 | })
129 |
--------------------------------------------------------------------------------
/examples/app-bar/components/navigation-bar/navigation-bar.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {},
4 | "componentFramework": "glass-easel",
5 | "renderer": "skyline",
6 | "styleIsolation": "apply-shared"
7 | }
8 |
--------------------------------------------------------------------------------
/examples/app-bar/components/navigation-bar/navigation-bar.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
30 |
31 |
32 | {{title}}
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/examples/app-bar/components/navigation-bar/navigation-bar.wxss:
--------------------------------------------------------------------------------
1 | .weui-navigation-bar {
2 | display: flex;
3 | overflow: hidden;
4 | color: rgba(0, 0, 0, .9);
5 | width: 100vw;
6 | }
7 |
8 | .weui-navigation-bar__placeholder {
9 | background: #f7f7f7;
10 | position: relative;
11 | }
12 |
13 | .weui-navigation-bar__inner, .weui-navigation-bar__inner .weui-navigation-bar__left {
14 | display: flex;
15 | align-items: center;
16 | flex-direction: row;
17 | }
18 |
19 | .weui-navigation-bar__inner {
20 | position: relative;
21 | padding-right: 95px;
22 | width: 100vw;
23 | }
24 |
25 | .weui-navigation-bar__inner .weui-navigation-bar__left {
26 | position: relative;
27 | width: 95px;
28 | padding-left: 16px;
29 | }
30 |
31 | .weui-navigation-bar__btn_goback_wrapper {
32 | padding: 11px 18px 11px 16px;
33 | margin: -11px -18px -11px -16px;
34 | }
35 |
36 | .weui-navigation-bar__inner .weui-navigation-bar__left .weui-navigation-bar__btn_goback {
37 | font-size: 12px;
38 | width: 12px;
39 | height: 24px;
40 | background: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='24' viewBox='0 0 12 24'%3E %3Cpath fill-opacity='.9' fill-rule='evenodd' d='M10 19.438L8.955 20.5l-7.666-7.79a1.02 1.02 0 0 1 0-1.42L8.955 3.5 10 4.563 2.682 12 10 19.438z'/%3E%3C/svg%3E") no-repeat 50% 50%;
41 | background-color: currentColor;
42 | background-size: cover;
43 | }
44 |
45 | .weui-navigation-bar__inner .weui-navigation-bar__center {
46 | font-size: 17px;
47 | text-align: center;
48 | position: relative;
49 | flex: 1;
50 | display: flex;
51 | align-items: center;
52 | justify-content: center;
53 | font-weight: bold;
54 | }
55 |
56 | [data-weui-theme=dark].weui-navigation-bar {
57 | color: hsla(0, 0%, 100%, .8);
58 | }
59 | [data-weui-theme=dark] .weui-navigation-bar__inner {
60 | background-color: #1f1f1f;
61 | }
62 |
--------------------------------------------------------------------------------
/examples/app-bar/pages/detail/index.js:
--------------------------------------------------------------------------------
1 | // pages/detail/index.js
2 | const musicList = [
3 | {
4 | id: 0,
5 | coverImg: 'https://res.wx.qq.com/op_res/Nu9XXzXcXnD1j5EgWQ2ElxNcl1yMvnKypRo4MTbjOv7FC3saigGoOBTZibyESC7EXaClnPYhB6pvfb-IRmso6g',
6 | title: 'Skyline 渲染框架'
7 | },
8 | {
9 | id: 1,
10 | coverImg: 'https://res.wx.qq.com/op_res/Nu9XXzXcXnD1j5EgWQ2El3JJ3FgQX_YP9sI6kJD_nLjnkdN19yZ5nLtS3cqtNUx621vrni0Kjy5uoX_QMlBJgQ',
11 | title: '小程序性能优化'
12 | },
13 | {
14 | id: 2,
15 | coverImg: 'https://res.wx.qq.com/op_res/Nu9XXzXcXnD1j5EgWQ2ElwWbBogi5f0NNRBkuJWfE8HQzysKxBaoCJ-YBr7irwn_uE37dHQTWcHK2uOHIWsQ3Q',
16 | title: '医疗行业实践'
17 | },
18 |
19 | ]
20 | Page({
21 | data: {
22 | music: musicList[0],
23 | albumMusicList: [
24 | {
25 | id: 0,
26 | coverImg: 'https://res.wx.qq.com/op_res/Nu9XXzXcXnD1j5EgWQ2ElxNcl1yMvnKypRo4MTbjOv7FC3saigGoOBTZibyESC7EXaClnPYhB6pvfb-IRmso6g',
27 | name: 'Skyline 渲染框架',
28 | author: '小程序技术专员 - binnie'
29 | },
30 | {
31 | id: 1,
32 | coverImg: 'https://res.wx.qq.com/op_res/Nu9XXzXcXnD1j5EgWQ2El3JJ3FgQX_YP9sI6kJD_nLjnkdN19yZ5nLtS3cqtNUx621vrni0Kjy5uoX_QMlBJgQ',
33 | name: '小程序性能优化',
34 | author: '小程序性能优化专家'
35 | },
36 | {
37 | id: 2,
38 | coverImg: 'https://res.wx.qq.com/op_res/Nu9XXzXcXnD1j5EgWQ2ElwWbBogi5f0NNRBkuJWfE8HQzysKxBaoCJ-YBr7irwn_uE37dHQTWcHK2uOHIWsQ3Q',
39 | name: '医疗行业实践',
40 | author: '小程序医疗行业专家'
41 | },
42 | ]
43 | },
44 |
45 | onLoad(query) {
46 | const idx = query.idx
47 | if (idx) {
48 | this.setData({
49 | music: musicList[idx]
50 | })
51 | }
52 | },
53 |
54 | onReady() {
55 |
56 | },
57 |
58 |
59 | onShow() {
60 |
61 | },
62 | })
--------------------------------------------------------------------------------
/examples/app-bar/pages/detail/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "usingComponents": {
3 | "navigation-bar": "../../components/navigation-bar/navigation-bar"
4 | }
5 | }
--------------------------------------------------------------------------------
/examples/app-bar/pages/detail/index.wxml:
--------------------------------------------------------------------------------
1 |
7 |
13 |
14 |
15 |
16 |
17 | 为你推荐
18 |
19 |
20 |
21 | {{item.name}}
22 | {{item.author}}
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/examples/app-bar/pages/detail/index.wxss:
--------------------------------------------------------------------------------
1 | page {
2 | display: flex;
3 | flex-direction: column;
4 | height: 100vh;
5 | }
6 |
7 | .scroll-area {
8 | flex: 1;
9 | overflow-y: hidden;
10 | padding: 0 24px;
11 | box-sizing: border-box;
12 | margin-bottom: calc(84px + env(safe-area-inset-bottom));
13 | }
14 |
15 | .intro {
16 | padding: 30px;
17 | text-align: center;
18 | }
19 |
20 | .cover {
21 | width: 250px;
22 | height: 250px;
23 | }
24 |
25 | .album-music {
26 | padding: 16px 0;
27 | border-top: 0.5px solid #f1e9e9;
28 | }
29 |
30 | .album-music-cover {
31 | width: 48px;
32 | height: 48px;
33 | margin-right: 16px;
34 | }
35 |
36 | .row {
37 | display: flex;
38 | flex-direction: row;
39 | }
40 |
41 | .row-between {
42 | display: flex;
43 | flex-direction: row;
44 | justify-content: space-between;
45 | align-items: center;
46 | }
47 |
48 | .column {
49 | display: flex;
50 | flex-direction: column;
51 | }
52 |
53 | .column-main-center {
54 | display: flex;
55 | flex-direction: column;
56 | justify-content: center;
57 | }
58 |
59 | .column-cross-center {
60 | display: flex;
61 | flex-direction: column;
62 | align-items: center;
63 | }
64 |
65 | .center {
66 | display: flex;
67 | align-items: center;
68 | justify-content: center;
69 | }
70 |
71 | .circle {
72 | width: 100%;
73 | height: 100%;
74 | overflow: hidden;
75 | border-radius: 50%;
76 | }
77 | .author {
78 | font-size: 12px;
79 | color: #7e8081;
80 | margin-top: 6px;
81 | }
82 |
--------------------------------------------------------------------------------
/examples/app-bar/pages/index/index.js:
--------------------------------------------------------------------------------
1 | const app = getApp()
2 |
3 | Page({
4 | data: {
5 | back: false,
6 | maxCoverSize: 0,
7 | musicList: [
8 | {
9 | id: 0,
10 | coverImg: 'https://res.wx.qq.com/op_res/Nu9XXzXcXnD1j5EgWQ2ElxNcl1yMvnKypRo4MTbjOv7FC3saigGoOBTZibyESC7EXaClnPYhB6pvfb-IRmso6g',
11 | title: 'Skyline 渲染框架'
12 | },
13 | {
14 | id: 1,
15 | coverImg: 'https://res.wx.qq.com/op_res/Nu9XXzXcXnD1j5EgWQ2El3JJ3FgQX_YP9sI6kJD_nLjnkdN19yZ5nLtS3cqtNUx621vrni0Kjy5uoX_QMlBJgQ',
16 | title: '小程序性能优化'
17 | },
18 | {
19 | id: 2,
20 | coverImg: 'https://res.wx.qq.com/op_res/Nu9XXzXcXnD1j5EgWQ2ElwWbBogi5f0NNRBkuJWfE8HQzysKxBaoCJ-YBr7irwn_uE37dHQTWcHK2uOHIWsQ3Q',
21 | title: '医疗行业实践'
22 | },
23 |
24 | ]
25 | },
26 | onLoad() {
27 | // 在小程序示例中展示返回按钮
28 | if (this.route.includes('packageSkylineExamples/examples/')) {
29 | this.setData({
30 | back: true
31 | })
32 | }
33 | },
34 | onShow() {
35 | // 仅在 app-bar demo 页面展示
36 | if (typeof this.getAppBar === 'function' ) {
37 | const appBarComp = this.getAppBar()
38 | // component.getAppBar 在 Skyline 中返回 appBar 组件实例,在 webview 中返回 null
39 | if (appBarComp !== null) {
40 | appBarComp.setData({
41 | showAppbar: true
42 | })
43 | }
44 | }
45 | },
46 |
47 | goDetail(e) {
48 | const idx = e.currentTarget.dataset.idx
49 | wx.navigateTo({
50 | url: `../detail/index?idx=${idx}`,
51 | })
52 | }
53 | })
54 |
--------------------------------------------------------------------------------
/examples/app-bar/pages/index/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "usingComponents": {
3 | "navigation-bar": "../../components/navigation-bar/navigation-bar"
4 | }
5 | }
--------------------------------------------------------------------------------
/examples/app-bar/pages/index/index.wxml:
--------------------------------------------------------------------------------
1 |
7 |
13 | 本月课程上新
14 |
15 |
22 |
23 | {{item.title}}
24 |
25 |
26 | 最近学过
27 |
28 |
35 |
36 | {{item.title}}
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/examples/app-bar/pages/index/index.wxss:
--------------------------------------------------------------------------------
1 | page {
2 | display: flex;
3 | flex-direction: column;
4 | height: 100vh;
5 | }
6 |
7 | .scroll-area {
8 | flex: 1;
9 | overflow-y: hidden;
10 | padding: 0 8px;
11 | box-sizing: border-box;
12 | margin-bottom: calc(84px + env(safe-area-inset-bottom));
13 | }
14 |
15 | .intro {
16 | padding: 30px;
17 | text-align: center;
18 | }
19 |
20 | .app-bar {
21 | position: absolute;
22 | width: 100vw;
23 | height: 100vh;
24 | pointer-events: none;
25 | }
26 |
27 | .title {
28 | margin-top: 16px;
29 | margin-left: 8px;
30 | font-size: 20px;
31 | font-weight: 600;
32 | }
33 |
34 | .cards {
35 | /* margin: 24px 0; */
36 | display: flex;
37 | flex-direction: row;
38 | flex-wrap: wrap;
39 | }
40 |
41 | .card {
42 | display: flex;
43 | justify-content: center;
44 | flex-direction: column;
45 | margin: 8px;
46 | }
47 |
48 | .cover {
49 | width: 43vw;
50 | height: 43vw;
51 | margin-bottom: 10px;
52 | }
--------------------------------------------------------------------------------
/examples/app-bar/project.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "appid": "wxe5f52902cf4de896",
3 | "compileType": "miniprogram",
4 | "libVersion": "3.3.2",
5 | "packOptions": {
6 | "ignore": [],
7 | "include": []
8 | },
9 | "setting": {
10 | "coverView": true,
11 | "es6": true,
12 | "postcss": true,
13 | "minified": true,
14 | "enhance": true,
15 | "showShadowRootInWxmlPanel": true,
16 | "packNpmRelationList": [],
17 | "babelSetting": {
18 | "ignore": [],
19 | "disablePlugins": [],
20 | "outputPath": ""
21 | },
22 | "compileWorklet": true
23 | },
24 | "condition": {},
25 | "editorSetting": {
26 | "tabIndent": "auto",
27 | "tabSize": 4
28 | }
29 | }
--------------------------------------------------------------------------------
/examples/app-bar/project.private.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html",
3 | "projectname": "app-bar",
4 | "setting": {
5 | "compileHotReLoad": true,
6 | "skylineRenderEnable": true
7 | },
8 | "libVersion": "3.3.3"
9 | }
--------------------------------------------------------------------------------
/examples/app-bar/sitemap.json:
--------------------------------------------------------------------------------
1 | {
2 | "desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html",
3 | "rules": [{
4 | "action": "allow",
5 | "page": "*"
6 | }]
7 | }
--------------------------------------------------------------------------------
/examples/associated-scroll-view/.eslintrc.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Eslint config file
3 | * Documentation: https://eslint.org/docs/user-guide/configuring/
4 | * Install the Eslint extension before using this feature.
5 | */
6 | module.exports = {
7 | env: {
8 | es6: true,
9 | browser: true,
10 | node: true,
11 | },
12 | ecmaFeatures: {
13 | modules: true,
14 | },
15 | parserOptions: {
16 | ecmaVersion: 2018,
17 | sourceType: 'module',
18 | },
19 | globals: {
20 | wx: true,
21 | App: true,
22 | Page: true,
23 | getCurrentPages: true,
24 | getApp: true,
25 | Component: true,
26 | requirePlugin: true,
27 | requireMiniProgram: true,
28 | },
29 | // extends: 'eslint:recommended',
30 | rules: {},
31 | }
32 |
--------------------------------------------------------------------------------
/examples/associated-scroll-view/app.js:
--------------------------------------------------------------------------------
1 | // app.js
2 | App({})
3 |
--------------------------------------------------------------------------------
/examples/associated-scroll-view/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "pages": [
3 | "pages/index/index"
4 | ],
5 | "window": {
6 | "backgroundTextStyle": "light",
7 | "navigationBarBackgroundColor": "#fff",
8 | "navigationBarTitleText": "Weixin",
9 | "navigationBarTextStyle": "black"
10 | },
11 | "style": "v2",
12 | "lazyCodeLoading": "requiredComponents",
13 | "renderer": "skyline",
14 | "rendererOptions": {
15 | "skyline": {
16 | "defaultDisplayBlock": true,
17 | "disableABTest": true,
18 | "sdkVersionBegin": "3.0.0",
19 | "sdkVersionEnd": "15.255.255"
20 | }
21 | },
22 | "componentFramework": "glass-easel",
23 | "sitemapLocation": "sitemap.json"
24 | }
25 |
--------------------------------------------------------------------------------
/examples/associated-scroll-view/app.wxss:
--------------------------------------------------------------------------------
1 | /**app.wxss**/
2 | .container {
3 | height: 100%;
4 | display: flex;
5 | flex-direction: column;
6 | align-items: center;
7 | justify-content: space-between;
8 | padding: 200rpx 0;
9 | box-sizing: border-box;
10 | }
11 |
--------------------------------------------------------------------------------
/examples/associated-scroll-view/components/category-list/category-list.js:
--------------------------------------------------------------------------------
1 | const { shared } = wx.worklet
2 |
3 | const GestureState = {
4 | POSSIBLE: 0, // 0 此时手势未识别,如 panDown等
5 | BEGIN: 1, // 1 手势已识别
6 | ACTIVE: 2, // 2 连续手势活跃状态
7 | END: 3, // 3 手势终止
8 | CANCELLED: 4, // 4 手势取消,
9 | }
10 |
11 | Component({
12 | options: {
13 | virtualHost: true,
14 | },
15 | properties: {
16 | products: {
17 | type: Object,
18 | value: [],
19 | },
20 | max: {
21 | type: Number,
22 | value: 0,
23 | },
24 | index: {
25 | type: Number,
26 | value: 0,
27 | },
28 | },
29 | lifetimes: {
30 | created() {
31 | this._swiping = shared(false)
32 | this._canSwipe = shared(false)
33 | this._scrollTop = shared(0)
34 | this._scrollHeight = shared(100)
35 | this._height = shared(0)
36 | },
37 | attached() {
38 | this.createSelectorQuery().select('.product-list').boundingClientRect(rect => {
39 | this._height.value = rect.height
40 | this._scrollHeight.value = rect.height + 1 // 可滚动高度总是比滚动区域高一点
41 | }).exec()
42 | },
43 | },
44 | methods: {
45 | getCanSwipe() {
46 | return this._canSwipe
47 | },
48 | setSwipingValue(swiping) {
49 | this._swiping = swiping
50 | },
51 | shouldScrollViewResp(e) {
52 | 'worklet'
53 | // 前者是判断到顶往下拉,后者反之
54 | this._canSwipe.value = this._scrollTop.value <= 0 && e.deltaY > 0 && this.properties.index !== 0 ||
55 | this._scrollTop.value + this._height.value >= this._scrollHeight.value && e.deltaY < 0 && this.properties.index !== this.properties.max
56 | // 滑动 swiper 期间 scroll-view 不可滚动
57 | return !this._swiping.value && !this._canSwipe.value
58 | },
59 | handleScroll(e) {
60 | 'worklet'
61 | this._scrollTop.value = e.detail.scrollTop
62 | this._scrollHeight.value = e.detail.scrollHeight
63 | },
64 | },
65 | })
66 |
--------------------------------------------------------------------------------
/examples/associated-scroll-view/components/category-list/category-list.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {}
4 | }
--------------------------------------------------------------------------------
/examples/associated-scroll-view/components/category-list/category-list.wxml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
10 |
11 | {{item.name}}
12 |
13 | {{item.sales}}人学过好评度100%
14 |
15 | ¥
16 | {{item.price}}
17 | 起
18 |
19 |
20 | +
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/examples/associated-scroll-view/components/category-list/category-list.wxss:
--------------------------------------------------------------------------------
1 | .product-list {
2 | height: 100%;
3 | }
4 | .product-item {
5 | display: flex;
6 | flex-direction: row;
7 | padding: 8px;
8 | }
9 | .product-item:first-child {
10 | padding-top: 16px;
11 | }
12 | .product-item:last-child {
13 | padding-bottom: 16px;
14 | border-bottom: 1px solid #F9F9F9;
15 | }
16 | .product-image {
17 | width: 133px;
18 | height: 100px;
19 | border-radius: 5px;
20 | }
21 | .product-info {
22 | flex: 1;
23 | padding: 0 8px;
24 | font-size: 10px;
25 | }
26 | .product-info view, .product-info text {
27 | margin-bottom: 3px;
28 | }
29 | .product-name {
30 | font-size: 16px;
31 | }
32 | .product-comment {
33 | display: flex;
34 | flex-direction: row;
35 | }
36 | .product-comment text {
37 | background-color: #EEE;
38 | border-radius: 3px;
39 | padding: 1px 3px;
40 | }
41 | .product-data {
42 | display: flex;
43 | flex-direction: row;
44 | color: gray;
45 | }
46 | .product-data text {
47 | margin-right: 20px;
48 | }
49 | .product-discount {
50 | display: flex;
51 | flex-direction: row;
52 | }
53 | .product-discount text {
54 | color: red;
55 | border: 0.3px solid red;
56 | padding: 0 3px;
57 | border-radius: 3px;
58 | }
59 | .product-price {
60 | color: red;
61 | vertical-align: baseline;
62 | }
63 | .product-add-to-cart {
64 | position: absolute;
65 | right: 12px;
66 | bottom: 12px;
67 | border-radius: 6px;
68 | color: #fff;
69 | background-color: #44b549;
70 | width: 20px;
71 | height: 20px;
72 | line-height: 16px;
73 | font-weight: 500;
74 | text-align: center;
75 | }
76 |
--------------------------------------------------------------------------------
/examples/associated-scroll-view/pages/index/index.js:
--------------------------------------------------------------------------------
1 | import { getCategories, getProducts } from "../../util"
2 |
3 | const { shared } = wx.worklet
4 |
5 | Component({
6 | data: {
7 | categories: getCategories(),
8 | selected: 0,
9 | products: getProducts(),
10 | },
11 | lifetimes: {
12 | created() {
13 | this._swiping = shared(false)
14 | this._canSwipe = []
15 | this._selected = shared(0)
16 | this._lastIndex = shared(0)
17 | },
18 | attached() {
19 | this._canSwipe = this.selectAllComponents('.category-list').map(comp => {
20 | comp.setSwipingValue(this._swiping)
21 | return comp.getCanSwipe()
22 | })
23 | },
24 | },
25 | methods: {
26 | shouldSwiperResp() {
27 | 'worklet'
28 | if (this._lastIndex.value !== this._selected.value) {
29 | this._lastIndex.value = this._selected.value
30 | // 每次切换 swiper item 时重置,优先给滚动
31 | this._canSwipe[this._selected.value].value = false
32 | }
33 | return this._canSwipe[this._selected.value].value
34 | },
35 | onSwiperStart() {
36 | 'worklet'
37 | this._swiping.value = true
38 | },
39 | onSwiperEnd() {
40 | 'worklet'
41 | this._swiping.value = false
42 | },
43 | onChange(e) {
44 | const {current} = e.detail
45 | this.setData({
46 | selected: current,
47 | })
48 | this._selected.value = current
49 | wx.vibrateShort({
50 | type: 'light',
51 | })
52 | },
53 | },
54 | })
55 |
--------------------------------------------------------------------------------
/examples/associated-scroll-view/pages/index/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "usingComponents": {
3 | "category-list": "../../components/category-list/category-list"
4 | },
5 | "disableScroll": true,
6 | "navigationStyle": "custom"
7 | }
--------------------------------------------------------------------------------
/examples/associated-scroll-view/pages/index/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ㄑ
5 | 请输入课程名称
6 |
7 |
8 |
9 |
10 |
16 |
17 |
18 | {{item.name}}
19 |
20 |
21 |
22 |
23 |
24 | {{item.name}}
25 |
26 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/examples/associated-scroll-view/pages/index/index.wxss:
--------------------------------------------------------------------------------
1 | view {
2 | position: relative;
3 | box-sizing: border-box;
4 | }
5 | page {
6 | background-color: #F9F9F9;
7 | display: flex;
8 | flex-direction: column;
9 | height: 100vh;
10 | }
11 |
12 | .navigation-bar {
13 | width: 100%;
14 | padding-top: calc(env(safe-area-inset-top) + 0.001px);
15 | }
16 | .navigation-bar-content {
17 | height: 44px;
18 | display: flex;
19 | flex-direction: row;
20 | justify-content: center;
21 | align-items: center;
22 | font-size: 20px;
23 | }
24 | .navigation-bar-content.white {
25 | color: white;
26 | }
27 | .navigation-bar-content.black {
28 | color: black;
29 | }
30 | .navigation-bar-content .back, .navigation-bar-content .more {
31 | width: 44px;
32 | text-align: center;
33 | }
34 | .navigation-bar-content .search {
35 | flex: 1;
36 | margin-right: 60px;
37 | margin-top: 7px;
38 | align-self: flex-start;
39 | }
40 | .navigation-bar-content .search-input {
41 | position: absolute;
42 | right: 0;
43 | width: 100%;
44 | height: 30px;
45 | line-height: 30px;
46 | padding-left: 20px;
47 | border: 0.5px solid #44b549;
48 | border-radius: 15px;
49 | font-size: 12px;
50 | background-color: #F8F8F8;
51 | color: #AAA;
52 | }
53 |
54 | .first-category {
55 | height: 100px;
56 | }
57 | .first-category-list {
58 | height: 100%;
59 | display: flex;
60 | flex-direction: row;
61 | }
62 | .first-category-item {
63 | padding: 10px;
64 | flex-shrink: 0;
65 | }
66 | .first-category-item-image {
67 | width: 50px;
68 | height: 50px;
69 | border-radius: 100%;
70 | border: 2px solid white;
71 | }
72 | .first-category-item-name {
73 | font-size: 12px;
74 | text-align: center;
75 | width: 50px;
76 | margin-top: 6px;
77 | }
78 |
79 | .main {
80 | flex: 1;
81 | display: flex;
82 | flex-direction: row;
83 | }
84 | .second-category {
85 | font-size: 12px;
86 | background-color: #F9F9F9;
87 | }
88 | .second-category-item {
89 | padding: 15px 5px;
90 | width: 80px;
91 | transition: ease .3s;
92 | transition-property: font-size;
93 | text-align: center;
94 | }
95 | .second-category-item.selected {
96 | background-color: white;
97 | font-size: 14px;
98 | font-weight: bold;
99 | color: #44b549;
100 | }
101 |
102 | .product-list-wrapper {
103 | flex: 1;
104 | background-color: white;
105 | height: auto;
106 | }
107 |
--------------------------------------------------------------------------------
/examples/associated-scroll-view/project.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "appid": "wxe5f52902cf4de896",
3 | "compileType": "miniprogram",
4 | "libVersion": "latest",
5 | "packOptions": {
6 | "ignore": [],
7 | "include": []
8 | },
9 | "setting": {
10 | "coverView": true,
11 | "es6": true,
12 | "postcss": true,
13 | "minified": true,
14 | "enhance": true,
15 | "showShadowRootInWxmlPanel": true,
16 | "packNpmRelationList": [],
17 | "babelSetting": {
18 | "ignore": [],
19 | "disablePlugins": [],
20 | "outputPath": ""
21 | },
22 | "condition": false,
23 | "skylineRenderEnable": true,
24 | "compileWorklet": true
25 | },
26 | "condition": {},
27 | "editorSetting": {
28 | "tabIndent": "auto",
29 | "tabSize": 4
30 | }
31 | }
--------------------------------------------------------------------------------
/examples/associated-scroll-view/project.private.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html",
3 | "projectname": "associated-scroll-view",
4 | "setting": {
5 | "compileHotReLoad": false,
6 | "skylineRenderEnable": true
7 | },
8 | "libVersion": "latest",
9 | "condition": {}
10 | }
--------------------------------------------------------------------------------
/examples/associated-scroll-view/sitemap.json:
--------------------------------------------------------------------------------
1 | {
2 | "desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html",
3 | "rules": [{
4 | "action": "allow",
5 | "page": "*"
6 | }]
7 | }
--------------------------------------------------------------------------------
/examples/associated-scroll-view/util.js:
--------------------------------------------------------------------------------
1 | export function getCategories() {
2 | const categories = [
3 | '中小商户',
4 | '商超零售',
5 | '品牌服饰',
6 | '餐饮',
7 | '医疗',
8 | '酒旅',
9 | '政务',
10 | '开发技术',
11 | '产品能力',
12 | '运营规范',
13 | ]
14 | const images = [
15 | 'https://res.wx.qq.com/op_res/RBwYn_b7VGuWuLJ2qBChU_LhYxhaP5JTy7TWgezsDY7RW_l_e04fR7oG7sCKmS8hc8mVeZaY6eUWT3nk-ww_ZQ',
16 | 'https://res.wx.qq.com/op_res/RBwYn_b7VGuWuLJ2qBChU-O3axOjUJGFgutF9Xc1JL1uxXFWYdW85mWG0Zvm5nv7rvP18CJ0q6-RRFM0xWLLog',
17 | 'https://res.wx.qq.com/op_res/RBwYn_b7VGuWuLJ2qBChU3ywQmrV-rSREDwo0Hp9m7iIZZ7Njvjq_TlOg_0ss0cgQL0pfKOuB2NRpAcwfALxvw',
18 | 'https://res.wx.qq.com/op_res/RBwYn_b7VGuWuLJ2qBChU1GROxmiPIBOCoA5Es44GxjN0KuCQQsoxEH33l05TCgk04n0dssHAIPxIV2ycSlSJA',
19 | 'https://res.wx.qq.com/op_res/RBwYn_b7VGuWuLJ2qBChU68wmBQzYcfQfuIAh1IKWq7OyG0EWxdWGhotYHFh-k-JpmkJ1Otq-mYUT8Dp3iucvg',
20 | 'https://res.wx.qq.com/op_res/UxKgRAAdvQE0sTh7eCEwT1ASo_fbE3TppPoza_9I7U7OreGNv8F8ltq80gqQSzxa-86bt-gWalLtgPDAhflj-w',
21 | 'https://res.wx.qq.com/op_res/UxKgRAAdvQE0sTh7eCEwT-SSHr1ULMcspj1yPw2dBQkxDV-Y_fOHodKNyHbS2JwBEVLnVKF2X_TPOhwZG9m0hQ',
22 | 'https://res.wx.qq.com/op_res/Zmvv0fisUjaMjuqWLhWWkuzGktaXJEQt46EaKsCKeT06Z4tROseXN0joI7h2qwzqyx2FUy57cveZL-8iArI8_Q',
23 | 'https://res.wx.qq.com/op_res/mGK9l-4vYzVgHuIz_uFeJitcJIfp9P4VSWxi3126XeiyZ2BnnH0xg-oIXAUgHBgaHjBMwxzSjSkEkTMRqzlKZw',
24 | 'https://res.wx.qq.com/op_res/mGK9l-4vYzVgHuIz_uFeJnw5zq4f_XW3swKAowexqAbziuojU5W9v4CJixA-NDJShkfS0ne3KWY_6SB56yqb3g',
25 | ]
26 | return categories.map((name, i) => {
27 | return {name, image: images[i]}
28 | })
29 | }
30 |
31 | export function getProducts() {
32 | let products = [
33 | '小程序性能优化课程',
34 | '小程序直播企业实践案例',
35 | '微信客服轻松配置,入门必修',
36 | '小程序如何帮助传统医院数字化?',
37 | '帮你快速掌握小商店经营秘诀',
38 | '了解小程序开发动态,听官方为你解读新能力',
39 | '快速了解微信小程序在医疗行业的应用',
40 | '解析常见小程序违规类型',
41 | '想做互联网的生意,可以通过微信怎么经营呢?',
42 | '政务行业小程序实践'
43 | ]
44 | let images = [
45 | 'https://res.wx.qq.com/op_res/RBwYn_b7VGuWuLJ2qBChU_LhYxhaP5JTy7TWgezsDY7RW_l_e04fR7oG7sCKmS8hc8mVeZaY6eUWT3nk-ww_ZQ',
46 | 'https://res.wx.qq.com/op_res/RBwYn_b7VGuWuLJ2qBChU-O3axOjUJGFgutF9Xc1JL1uxXFWYdW85mWG0Zvm5nv7rvP18CJ0q6-RRFM0xWLLog',
47 | 'https://res.wx.qq.com/op_res/RBwYn_b7VGuWuLJ2qBChU3ywQmrV-rSREDwo0Hp9m7iIZZ7Njvjq_TlOg_0ss0cgQL0pfKOuB2NRpAcwfALxvw',
48 | 'https://res.wx.qq.com/op_res/RBwYn_b7VGuWuLJ2qBChU1GROxmiPIBOCoA5Es44GxjN0KuCQQsoxEH33l05TCgk04n0dssHAIPxIV2ycSlSJA',
49 | 'https://res.wx.qq.com/op_res/RBwYn_b7VGuWuLJ2qBChU68wmBQzYcfQfuIAh1IKWq7OyG0EWxdWGhotYHFh-k-JpmkJ1Otq-mYUT8Dp3iucvg',
50 | 'https://res.wx.qq.com/op_res/UxKgRAAdvQE0sTh7eCEwT1ASo_fbE3TppPoza_9I7U7OreGNv8F8ltq80gqQSzxa-86bt-gWalLtgPDAhflj-w',
51 | 'https://res.wx.qq.com/op_res/UxKgRAAdvQE0sTh7eCEwT-SSHr1ULMcspj1yPw2dBQkxDV-Y_fOHodKNyHbS2JwBEVLnVKF2X_TPOhwZG9m0hQ',
52 | 'https://res.wx.qq.com/op_res/Zmvv0fisUjaMjuqWLhWWkuzGktaXJEQt46EaKsCKeT06Z4tROseXN0joI7h2qwzqyx2FUy57cveZL-8iArI8_Q',
53 | 'https://res.wx.qq.com/op_res/mGK9l-4vYzVgHuIz_uFeJitcJIfp9P4VSWxi3126XeiyZ2BnnH0xg-oIXAUgHBgaHjBMwxzSjSkEkTMRqzlKZw',
54 | 'https://res.wx.qq.com/op_res/mGK9l-4vYzVgHuIz_uFeJnw5zq4f_XW3swKAowexqAbziuojU5W9v4CJixA-NDJShkfS0ne3KWY_6SB56yqb3g',
55 | ]
56 | products = products.concat(products).map((name, id) => ({
57 | id,
58 | name,
59 | image: images[(id % products.length)],
60 | comment: '一如既往的好',
61 | sales: 6500,
62 | discount: 0.01,
63 | price: 0.01
64 | }))
65 | return products
66 | }
67 |
--------------------------------------------------------------------------------
/examples/card_transition/app.js:
--------------------------------------------------------------------------------
1 | App({})
2 |
--------------------------------------------------------------------------------
/examples/card_transition/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "pages": [
3 | "pages/list/list",
4 | "pages/detail/detail"
5 | ],
6 | "window": {
7 | "backgroundTextStyle": "light",
8 | "navigationBarBackgroundColor": "#fff",
9 | "navigationBarTitleText": "Weixin",
10 | "navigationBarTextStyle": "black"
11 | },
12 | "style": "v2",
13 | "sitemapLocation": "sitemap.json",
14 | "renderer": "skyline",
15 | "rendererOptions": {
16 | "skyline": {
17 | "defaultDisplayBlock": true,
18 | "disableABTest": true,
19 | "sdkVersionBegin": "3.0.0",
20 | "sdkVersionEnd": "15.255.255"
21 | }
22 | },
23 | "componentFramework": "glass-easel",
24 | "lazyCodeLoading": "requiredComponents"
25 | }
--------------------------------------------------------------------------------
/examples/card_transition/app.wxss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wechat-miniprogram/awesome-skyline/25e2d93c2daf3f78d0908ff53ea305147d0c8978/examples/card_transition/app.wxss
--------------------------------------------------------------------------------
/examples/card_transition/components/card/card.js:
--------------------------------------------------------------------------------
1 | const { shared } = wx.worklet
2 |
3 | const FlightDirection = {
4 | PUSH: 0,
5 | POP: 1,
6 | }
7 |
8 | Component({
9 | options: {
10 | virtualHost: true,
11 | },
12 | properties: {
13 | index: {
14 | type: Number,
15 | value: -1,
16 | },
17 | item: {
18 | type: Object,
19 | value: {},
20 | },
21 | cardWidth: {
22 | type: Number,
23 | value: 0
24 | },
25 | },
26 | lifetimes: {
27 | created() {
28 | this.scale = shared(1)
29 | this.opacity = shared(0)
30 | this.direction = shared(0)
31 | this.srcWidth = shared('100%')
32 | this.radius = shared(5)
33 |
34 | const beginRect = shared(undefined)
35 | const endRect = shared(undefined)
36 | wx.worklet.runOnUI(() => {
37 | 'worklet'
38 | globalThis['RouteCardSrcRect'] = beginRect
39 | globalThis['RouteCardDestRect'] = endRect
40 | })()
41 | },
42 | attached() {
43 | this.applyAnimatedStyle(
44 | '.card_wrap',
45 | () => {
46 | 'worklet'
47 | return {
48 | width: this.srcWidth.value,
49 | transform: `scale(${this.scale.value})`,
50 | }
51 | },
52 | {
53 | immediate: false,
54 | flush: 'sync'
55 | },
56 | () => {},
57 | )
58 |
59 | this.applyAnimatedStyle(
60 | '.card_img',
61 | () => {
62 | 'worklet'
63 | return {
64 | opacity: this.opacity.value,
65 | borderTopRightRadius: this.radius.value, // 不带单位默认是 px
66 | borderTopLeftRadius: this.radius.value,
67 | }
68 | },
69 | {
70 | immediate: false,
71 | flush: 'sync'
72 | },
73 | () => {},
74 | )
75 |
76 | this.applyAnimatedStyle(
77 | '.card_desc',
78 | () => {
79 | 'worklet'
80 | return {
81 | opacity: this.opacity.value,
82 | }
83 | },
84 | {
85 | immediate: false,
86 | flush: 'sync'
87 | },
88 | () => {},
89 | )
90 | },
91 | },
92 |
93 | methods: {
94 | navigateTo(e) {
95 | const { index, url, content, ratio, nickname } = e.currentTarget.dataset
96 | const urlContent = `../../pages/detail/detail?index=${index}&url=${encodeURIComponent(url)}&content=${content}&ratio=${ratio}&nickname=${nickname}`
97 | wx.navigateTo({
98 | url: urlContent,
99 | routeType: 'CardScaleTransition',
100 | })
101 | },
102 | handleFrame(data) {
103 | 'worklet'
104 | this.direction.value = data.direction
105 | if (data.direction === FlightDirection.PUSH) { // 进入
106 | // 飞跃过程中,卡片从 100% 改为固定宽度,通过 scale 手动控制缩放
107 | this.srcWidth.value = `${data.begin.width}px`
108 | this.scale.value = data.current.width / data.begin.width
109 | this.opacity.value = 1 - data.progress
110 | this.radius.value = 0
111 | // this.shareImgHeight.value = data.begin.height
112 |
113 | } else if (data.direction === FlightDirection.POP) { // 返回
114 | this.scale.value = data.current.width / data.end.width
115 | this.opacity.value = data.progress
116 | this.radius.value = 5
117 | }
118 |
119 | // globalThis 是 UI 线程的全局变量,将 share-element 初始和目标尺寸保存起来,用于下一页面的缩放动画的计算
120 | // TODO: 后续计划优化这里的接口设计
121 | if (globalThis['RouteCardSrcRect'] && globalThis['RouteCardSrcRect'].value == undefined) {
122 | globalThis['RouteCardSrcRect'].value = data.begin
123 | }
124 | if (globalThis['RouteCardDestRect'] && globalThis['RouteCardDestRect'].value == undefined) {
125 | globalThis['RouteCardDestRect'].value = data.end
126 | }
127 | },
128 | },
129 | })
130 |
--------------------------------------------------------------------------------
/examples/card_transition/components/card/card.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {},
4 | "componentFramework": "glass-easel"
5 | }
--------------------------------------------------------------------------------
/examples/card_transition/components/card/card.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | {{item.content}}
9 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/examples/card_transition/components/card/card.wxss:
--------------------------------------------------------------------------------
1 | .card {
2 | border-radius: 5px;
3 | overflow: hidden;
4 | flex-shrink: 0;
5 | width: 100%;
6 | background-color: white;
7 | }
8 |
9 | .card_wrap {
10 | position: absolute;
11 | transform-origin: 0 0;
12 | width: 100%;
13 | display: flex;
14 | flex-direction: column;
15 | }
16 |
17 | .card_img {
18 | width: 100%;
19 | border-top-right-radius: 5px;
20 | border-top-left-radius: 5px;
21 | }
22 |
23 | .card_content {
24 | padding: 8px;
25 | font-size: 14px;
26 | font-weight: 500;
27 | /* height: 54px; */
28 | overflow: hidden;
29 | box-sizing: border-box;
30 | }
31 |
32 | .card_footer {
33 | padding: 0 8px 8px;
34 | display: flex;
35 | flex-direction: row;
36 | font-size: 12px;
37 | color: #666666;
38 | line-height: 20px;
39 | }
40 |
41 | .card_avatar {
42 | width: 20px;
43 | height: 20px;
44 | border-radius: 50%;
45 | }
46 |
47 | .card_nickname {
48 | flex: 1;
49 | padding-left: 4px;
50 | }
51 |
--------------------------------------------------------------------------------
/examples/card_transition/components/navigation-bar/index.js:
--------------------------------------------------------------------------------
1 | Component({
2 | options: {
3 | multipleSlots: true // 在组件定义时的选项中启用多slot支持
4 | },
5 | /**
6 | * 组件的属性列表
7 | */
8 | properties: {
9 | extClass: {
10 | type: String,
11 | value: ''
12 | },
13 | title: {
14 | type: String,
15 | value: ''
16 | },
17 | background: {
18 | type: String,
19 | value: ''
20 | },
21 | color: {
22 | type: String,
23 | value: ''
24 | },
25 | back: {
26 | type: Boolean,
27 | value: true
28 | },
29 | loading: {
30 | type: Boolean,
31 | value: false
32 | },
33 | animated: {
34 | // 显示隐藏的时候opacity动画效果
35 | type: Boolean,
36 | value: true
37 | },
38 | show: {
39 | // 显示隐藏导航,隐藏的时候navigation-bar的高度占位还在
40 | type: Boolean,
41 | value: true,
42 | observer: '_showChange'
43 | },
44 | // back为true的时候,返回的页面深度
45 | delta: {
46 | type: Number,
47 | value: 1
48 | }
49 | },
50 | /**
51 | * 组件的初始数据
52 | */
53 | data: {
54 | displayStyle: ''
55 | },
56 | attached() {
57 | const rect = wx.getMenuButtonBoundingClientRect()
58 | wx.getSystemInfo({
59 | success: (res) => {
60 | this.setData({
61 | statusBarHeight: res.statusBarHeight,
62 | innerPaddingRight: `padding-right:${res.windowWidth - rect.left}px`,
63 | leftWidth: `width:${res.windowWidth - rect.left}px`,
64 | navBarHeight: rect.bottom + rect.top - res.statusBarHeight,
65 | })
66 | }
67 | })
68 | },
69 | /**
70 | * 组件的方法列表
71 | */
72 | methods: {
73 | _showChange(show) {
74 | const animated = this.data.animated
75 | let displayStyle = ''
76 | if (animated) {
77 | displayStyle = `opacity: ${show ? '1' : '0'};transition: opacity 0.5s;`
78 | } else {
79 | displayStyle = `display: ${show ? '' : 'none'}`
80 | }
81 | this.setData({
82 | displayStyle
83 | })
84 | },
85 | back() {
86 | const data = this.data
87 | if (data.delta) {
88 | wx.navigateBack({
89 | delta: data.delta
90 | })
91 | }
92 | this.triggerEvent('back', { delta: data.delta }, {})
93 | }
94 | }
95 | })
96 |
--------------------------------------------------------------------------------
/examples/card_transition/components/navigation-bar/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {},
4 | "addGlobalClass": true,
5 | "componentFramework": "glass-easel"
6 | }
--------------------------------------------------------------------------------
/examples/card_transition/components/navigation-bar/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | {{title}}
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/examples/card_transition/components/navigation-bar/index.wxss:
--------------------------------------------------------------------------------
1 | .weui-navigation-bar {
2 | overflow: hidden;
3 | color: rgba(0, 0, 0, .9);
4 | width: 100vw;
5 | }
6 |
7 | .weui-navigation-bar__placeholder {
8 | background: #f7f7f7;
9 | position: relative;
10 | }
11 |
12 | .weui-navigation-bar__inner, .weui-navigation-bar__inner .weui-navigation-bar__left {
13 | display: flex;
14 | align-items: center;
15 | flex-direction: row;
16 | }
17 |
18 | .weui-navigation-bar__inner {
19 | position: relative;
20 | padding-right: 95px;
21 | width: 100vw;
22 | box-sizing: border-box;
23 | }
24 |
25 | .weui-navigation-bar__inner .weui-navigation-bar__left {
26 | position: relative;
27 | width: 95px;
28 | padding-left: 16px;
29 | box-sizing: border-box;
30 | }
31 |
32 | .weui-navigation-bar__btn_goback_wrapper {
33 | padding: 11px 18px 11px 16px;
34 | margin: -11px -18px -11px -16px;
35 | }
36 |
37 | .weui-navigation-bar__inner .weui-navigation-bar__left .weui-navigation-bar__btn_goback {
38 | font-size: 12px;
39 | width: 12px;
40 | height: 24px;
41 | background: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='24' viewBox='0 0 12 24'%3E %3Cpath fill-opacity='.9' fill-rule='evenodd' d='M10 19.438L8.955 20.5l-7.666-7.79a1.02 1.02 0 0 1 0-1.42L8.955 3.5 10 4.563 2.682 12 10 19.438z'/%3E%3C/svg%3E") no-repeat 50% 50%;
42 | background-size: cover;
43 | }
44 |
45 | .weui-navigation-bar__inner .weui-navigation-bar__center {
46 | font-size: 17px;
47 | text-align: center;
48 | position: relative;
49 | flex: 1;
50 | display: flex;
51 | flex-direction: column;
52 | align-items: center;
53 | justify-content: center;
54 | font-weight: bold;
55 | }
56 |
57 | @media(prefers-color-scheme: dark) {
58 | .weui-navigation-bar {
59 | color: hsla(0, 0%, 100%, .8);
60 | }
61 | .weui-navigation-bar__inner {
62 | background-color: #1f1f1f;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/examples/card_transition/pages/detail/detail.json:
--------------------------------------------------------------------------------
1 | {
2 | "usingComponents": {},
3 | "backgroundColorContent": "#00000000",
4 | "disableScroll": true,
5 | "navigationStyle": "custom"
6 | }
--------------------------------------------------------------------------------
/examples/card_transition/pages/detail/detail.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | {{nickname}}
8 | 关注
9 |
10 |
11 |
18 |
19 |
20 |
21 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | {{content}}
41 |
42 | 🔥 Skyline 以性能为首要目标,提供更为接近原生的用户体验,Skyline 具有以下特点:
43 |
44 | 🌟 界面更不容易被逻辑阻塞,进一步减少卡顿
45 | 🌟 无需为每个页面新建一个 JS 引擎实例(WebView),减少了内存、时间开销
46 | 🌟 框架可以在页面之间共享更多的资源,进一步减少运行时内存、时间开销
47 | 🌟 框架的代码之间无需再通过 JSBridge 进行数据交换,减少了大量通信时间开销
48 |
49 | 👇👇👇 支持了一些 Web 所缺失的但很重要的能力,以满足开发者实现更好的交互体验:
50 |
51 | 🔸 Worklet 动画:能够在渲染线程同步运行动画相关逻辑。
52 | 🔸 手势系统:在渲染线程同步监听手势、执行手势相关逻辑;支持手势协商处理;
53 | 🔸 自定义路由:实现自定义路由动画和交互。
54 | 🔸 共享元素动画:将上一个页面的元素“共享”到下一个页面,并伴随着过渡动画。
55 |
56 |
57 |
70 |
71 |
72 |
73 |
74 |
--------------------------------------------------------------------------------
/examples/card_transition/pages/detail/detail.wxss:
--------------------------------------------------------------------------------
1 | page {
2 | display: flex;
3 | flex-direction: column;
4 | height: 100vh;
5 | background-color: transparent;
6 | }
7 |
8 | view, scroll-view, page, image {
9 | box-sizing: border-box;
10 | }
11 |
12 | #fake-host {
13 | background-color: #FFF;
14 | border-radius: 10px;
15 | overflow: hidden;
16 | }
17 |
18 | #page {
19 | display: flex;
20 | flex-direction: column;
21 | height: 100vh;
22 | }
23 |
24 | .navigation-bar {
25 | padding-top: 44px;
26 | padding-top: env(safe-area-inset-top);
27 | background-color: white;
28 | }
29 |
30 | .navigation-bar-content {
31 | height: 44px;
32 | display: flex;
33 | flex-direction: row;
34 | padding: 0 20px;
35 | justify-content: center;
36 | align-items: center;
37 | font-size: 14px;
38 | }
39 |
40 | .navigation-bar-avatar {
41 | width: 24px;
42 | height: 24px;
43 | border-radius: 100%;
44 | }
45 |
46 | .navigation-bar-title {
47 | flex: 1;
48 | padding-left: 8px;
49 | }
50 |
51 | .navigation-bar-follow {
52 | color: red;
53 | border: .5px solid red;
54 | border-radius: 15px;
55 | padding: 3px 15px;
56 | margin-right: 80px;
57 | }
58 |
59 | .detail-image {
60 | width: 100%;
61 | height: 100%;
62 | }
63 |
64 | .detail-content {
65 | padding: 15px;
66 | }
67 |
68 | .detail-title {
69 | font-weight: bold;
70 | font-size: 18px;
71 | padding-bottom: 3px;
72 | }
73 |
74 | .detail-p {
75 | padding-bottom: 2px;
76 | }
77 |
78 | .footer {
79 | padding-bottom: env(safe-area-inset-bottom);
80 | font-size: 14px;
81 | }
82 |
83 | .footer-content {
84 | display: flex;
85 | align-items: center;
86 | flex-direction: row;
87 | height: 50px;
88 | }
89 |
90 | .footer .footer-input {
91 | flex: 1;
92 | background-color: #EEE;
93 | margin-left: 15px;
94 | margin-right: 15px;
95 | padding-left: 15px;
96 | height: 40px;
97 | border-radius: 20px;
98 | }
99 |
100 | .footer span {
101 | padding-right: 15px;
102 | }
103 |
104 | .footer-icon {
105 | font-size: 26px;
106 | }
107 |
--------------------------------------------------------------------------------
/examples/card_transition/pages/list/list.js:
--------------------------------------------------------------------------------
1 | import { installRouteBuilder } from './route'
2 | import { generateGridList, compareVersion } from './utils'
3 |
4 | const { screenWidth } = wx.getSystemInfoSync()
5 |
6 | Component({
7 | data: {
8 | padding: 4,
9 | gridList: generateGridList(100, 2),
10 | cardWidth: (screenWidth - 4 * 2 - 4) / 2, // 减去间距
11 | },
12 |
13 | lifetimes: {
14 | created() {
15 | const {SDKVersion} = wx.getSystemInfoSync()
16 | if (compareVersion(SDKVersion, '2.30.1') < 0) {
17 | wx.showModal({
18 | content: '基础库版本低于 v2.30.1 可能会有显示问题,建议升级微信体验。',
19 | showCancel: false
20 | })
21 | }
22 | installRouteBuilder()
23 | },
24 | },
25 | })
26 |
--------------------------------------------------------------------------------
/examples/card_transition/pages/list/list.json:
--------------------------------------------------------------------------------
1 | {
2 | "usingComponents": {
3 | "navigation-bar": "../../components/navigation-bar/index",
4 | "card": "../../components/card/card"
5 | },
6 | "disableScroll": true,
7 | "navigationStyle": "custom"
8 | }
--------------------------------------------------------------------------------
/examples/card_transition/pages/list/list.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
15 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/examples/card_transition/pages/list/list.wxss:
--------------------------------------------------------------------------------
1 | page {
2 | display: flex;
3 | flex-direction: column;
4 | height: 100vh;
5 | }
6 |
7 | scroll-view {
8 | background-color: #f4f4f4;
9 | }
10 |
11 | view, scroll-view, page, image {
12 | box-sizing: border-box;
13 | }
14 |
--------------------------------------------------------------------------------
/examples/card_transition/pages/list/route.js:
--------------------------------------------------------------------------------
1 | const AnimationStatus = {
2 | dismissed: 0, // The animation is stopped at the beginning.
3 | forward: 1, // The animation is running from beginning to end.
4 | reverse: 2, // The animation is running backwards, from end to beginning.
5 | completed: 3, // The animation is stopped at the end.
6 | }
7 |
8 | const { Easing, shared } = wx.worklet
9 |
10 | export const Curves = {
11 | linearToEaseOut: Easing.cubicBezier(0.35, 0.91, 0.33, 0.97),
12 | easeInToLinear: Easing.cubicBezier(0.67, 0.03, 0.65, 0.09),
13 | fastOutSlowIn: Easing.cubicBezier(0.4, 0.0, 0.2, 1.0),
14 | slowOutFastIn: Easing.cubicBezier(0.0, 0.8, 1.0, 0.6),
15 | easeOutCubic: Easing.cubicBezier(0.215, 0.61, 0.355, 1.0),
16 | }
17 |
18 | export function CurveAnimation({
19 | animation, animationStatus, curve, reverseCurve
20 | }) {
21 | const { derived } = wx.worklet
22 |
23 | return derived(() => {
24 | 'worklet'
25 |
26 | const useForwardCurve = !reverseCurve || animationStatus.value !== AnimationStatus.reverse
27 | const activeCurve = useForwardCurve ? curve : reverseCurve
28 |
29 | const t = animation.value
30 | if (!activeCurve) return t
31 | if (t === 0 || t === 1) return t
32 | return activeCurve(t)
33 | })
34 | }
35 |
36 | export const lerp = (begin, end, t) => {
37 | 'worklet'
38 | return begin + (end - begin) * t
39 | }
40 |
41 | const ScaleTransitionRouteBuilder = (routeContext) => {
42 | const {
43 | primaryAnimation,
44 | primaryAnimationStatus,
45 | userGestureInProgress,
46 | } = routeContext
47 |
48 | const shareEleTop = shared(0)
49 | routeContext.shareEleTop = shareEleTop
50 |
51 | const _curvePrimaryAnimation = CurveAnimation({
52 | animation: primaryAnimation,
53 | animationStatus: primaryAnimationStatus,
54 | curve: Easing.in(Curves.fastOutSlowIn),
55 | reverseCurve: Easing.out(Curves.fastOutSlowIn)
56 | })
57 |
58 | // 每次路由动画结束(进入或返回)都会重置一下
59 | const reset = () => {
60 | 'worklet'
61 | if (globalThis['RouteCardSrcRect']) {
62 | globalThis['RouteCardSrcRect'].value = undefined
63 | }
64 | if (globalThis['RouteCardDestRect']) {
65 | globalThis['RouteCardDestRect'].value = undefined
66 | }
67 | }
68 |
69 | const handlePrimaryAnimation = () => {
70 | 'worklet'
71 | const status = primaryAnimationStatus.value
72 | // 手势返回时,动画在详情页处理,此处顶层节点只做整体透明度淡出
73 | if (userGestureInProgress.value) {
74 | return {
75 | opacity: Easing.out(Easing.cubicBezier(0.5, 0, 0.7, 0.5)(primaryAnimation.value)),
76 | }
77 | }
78 |
79 | if (status == AnimationStatus.dismissed) {
80 | reset()
81 | return {
82 | transform: `translate(0, 0) scale(0)`,
83 | }
84 | }
85 |
86 | if (status == AnimationStatus.completed ) {
87 | reset()
88 | return {
89 | transform: `translate(0, 0) scale(1)`,
90 | }
91 | }
92 |
93 | let transX = 0
94 | let transY = 0
95 | let scale = status === AnimationStatus.reverse ? 1 : 0
96 |
97 | // 进入或者接口返回
98 | if (globalThis['RouteCardSrcRect'] && globalThis['RouteCardSrcRect'].value != undefined) {
99 | const begin = globalThis['RouteCardSrcRect'].value
100 | const end = globalThis['RouteCardDestRect'].value
101 |
102 | if (status === AnimationStatus.forward) {
103 | shareEleTop.value = end.top
104 | }
105 |
106 | let t = _curvePrimaryAnimation.value
107 | if (status === AnimationStatus.reverse || status === AnimationStatus.dismissed) {
108 | t = 1 - t
109 | }
110 |
111 | const shareEleX = lerp(begin.left, end.left, t)
112 | const shareEleY = lerp(begin.top, end.top, t)
113 | const shareEleW = lerp(begin.width, end.width, t)
114 |
115 | transX = shareEleX
116 | if (status === AnimationStatus.reverse) {
117 | scale = shareEleW / begin.width
118 | transY = shareEleY - begin.top * scale
119 | } else {
120 | scale = shareEleW / end.width
121 | transY = shareEleY - end.top * scale
122 | }
123 | }
124 |
125 | return {
126 | transform: `translate(${transX}px, ${transY}px) scale(${scale})`,
127 | transformOrigin: '0 0',
128 | opacity: _curvePrimaryAnimation.value,
129 | }
130 | }
131 |
132 | return {
133 | opaque: false,
134 | handlePrimaryAnimation,
135 | transitionDuration: 250,
136 | reverseTransitionDuration: 250,
137 | canTransitionTo: false,
138 | canTransitionFrom: false,
139 | barrierColor: "rgba(0, 0, 0, 0.3)",
140 | }
141 | }
142 |
143 | let hasInstalled = false
144 | export function installRouteBuilder() {
145 | if (hasInstalled) {
146 | return
147 | }
148 | wx.router.addRouteBuilder('CardScaleTransition', ScaleTransitionRouteBuilder)
149 | hasInstalled = true
150 | }
151 |
--------------------------------------------------------------------------------
/examples/card_transition/project.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "appid": "wxe5f52902cf4de896",
3 | "compileType": "miniprogram",
4 | "libVersion": "latest",
5 | "packOptions": {
6 | "ignore": [],
7 | "include": []
8 | },
9 | "setting": {
10 | "coverView": true,
11 | "es6": true,
12 | "postcss": true,
13 | "minified": true,
14 | "enhance": true,
15 | "showShadowRootInWxmlPanel": true,
16 | "packNpmRelationList": [],
17 | "babelSetting": {
18 | "ignore": [],
19 | "disablePlugins": [],
20 | "outputPath": ""
21 | },
22 | "condition": false,
23 | "skylineRenderEnable": false,
24 | "compileWorklet": true
25 | },
26 | "condition": {},
27 | "editorSetting": {
28 | "tabIndent": "insertSpaces",
29 | "tabSize": 2
30 | }
31 | }
--------------------------------------------------------------------------------
/examples/card_transition/project.private.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html",
3 | "projectname": "card_transition",
4 | "setting": {
5 | "compileHotReLoad": false,
6 | "skylineRenderEnable": false
7 | },
8 | "condition": {
9 | "miniprogram": {
10 | "list": [
11 | {
12 | "name": "",
13 | "pathName": "detail/detail",
14 | "query": "index=1&url=https%3A%2F%2Fpicsum.photos%2F300%2F400%3Frandom%3D1&content=Hayya Hayya!我来小红书啦&ratio=0.75",
15 | "launchMode": "default",
16 | "scene": null
17 | },
18 | {
19 | "name": "",
20 | "pathName": "list/list",
21 | "query": "",
22 | "launchMode": "default",
23 | "scene": null
24 | }
25 | ]
26 | }
27 | },
28 | "libVersion": "latest"
29 | }
--------------------------------------------------------------------------------
/examples/card_transition/sitemap.json:
--------------------------------------------------------------------------------
1 | {
2 | "desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html",
3 | "rules": [{
4 | "action": "allow",
5 | "page": "*"
6 | }]
7 | }
--------------------------------------------------------------------------------
/examples/expanded-scroll-view/.eslintrc.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Eslint config file
3 | * Documentation: https://eslint.org/docs/user-guide/configuring/
4 | * Install the Eslint extension before using this feature.
5 | */
6 | module.exports = {
7 | env: {
8 | es6: true,
9 | browser: true,
10 | node: true,
11 | },
12 | ecmaFeatures: {
13 | modules: true,
14 | },
15 | parserOptions: {
16 | ecmaVersion: 2018,
17 | sourceType: 'module',
18 | },
19 | globals: {
20 | wx: true,
21 | App: true,
22 | Page: true,
23 | getCurrentPages: true,
24 | getApp: true,
25 | Component: true,
26 | requirePlugin: true,
27 | requireMiniProgram: true,
28 | },
29 | // extends: 'eslint:recommended',
30 | rules: {},
31 | }
32 |
--------------------------------------------------------------------------------
/examples/expanded-scroll-view/app.js:
--------------------------------------------------------------------------------
1 | // app.js
2 | App({})
3 |
--------------------------------------------------------------------------------
/examples/expanded-scroll-view/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "pages": [
3 | "pages/index/index"
4 | ],
5 | "window": {
6 | "backgroundTextStyle": "light",
7 | "navigationBarBackgroundColor": "#fff",
8 | "navigationBarTitleText": "Weixin",
9 | "navigationBarTextStyle": "black"
10 | },
11 | "style": "v2",
12 | "renderer": "skyline",
13 | "rendererOptions": {
14 | "skyline": {
15 | "defaultDisplayBlock": true,
16 | "disableABTest": true
17 | }
18 | },
19 | "lazyCodeLoading": "requiredComponents",
20 | "sitemapLocation": "sitemap.json"
21 | }
--------------------------------------------------------------------------------
/examples/expanded-scroll-view/app.wxss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wechat-miniprogram/awesome-skyline/25e2d93c2daf3f78d0908ff53ea305147d0c8978/examples/expanded-scroll-view/app.wxss
--------------------------------------------------------------------------------
/examples/expanded-scroll-view/pages/index/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "usingComponents": {},
3 | "disableScroll": true,
4 | "navigationStyle": "custom",
5 | "renderer": "skyline",
6 | "componentFramework": "glass-easel"
7 | }
--------------------------------------------------------------------------------
/examples/expanded-scroll-view/project.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "compileType": "miniprogram",
3 | "setting": {
4 | "coverView": true,
5 | "es6": true,
6 | "postcss": true,
7 | "minified": true,
8 | "enhance": true,
9 | "showShadowRootInWxmlPanel": true,
10 | "packNpmRelationList": [],
11 | "babelSetting": {
12 | "ignore": [],
13 | "disablePlugins": [],
14 | "outputPath": ""
15 | },
16 | "condition": false,
17 | "ignoreUploadUnusedFiles": true,
18 | "compileWorklet": true
19 | },
20 | "condition": {},
21 | "editorSetting": {
22 | "tabIndent": "insertSpaces",
23 | "tabSize": 2
24 | },
25 | "packOptions": {
26 | "ignore": [],
27 | "include": []
28 | },
29 | "appid": "wxe5f52902cf4de896"
30 | }
--------------------------------------------------------------------------------
/examples/expanded-scroll-view/project.private.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html",
3 | "projectname": "expanded-scroll-view",
4 | "setting": {
5 | "compileHotReLoad": false,
6 | "skylineRenderEnable": true
7 | },
8 | "libVersion": "latest"
9 | }
--------------------------------------------------------------------------------
/examples/expanded-scroll-view/sitemap.json:
--------------------------------------------------------------------------------
1 | {
2 | "desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html",
3 | "rules": [{
4 | "action": "allow",
5 | "page": "*"
6 | }]
7 | }
--------------------------------------------------------------------------------
/examples/expanded-scroll-view/util.js:
--------------------------------------------------------------------------------
1 | export function getCategory() {
2 | let categorys = [
3 | '中小商户',
4 | '商超零售',
5 | '品牌服饰',
6 | '餐饮',
7 | '医疗',
8 | '酒旅',
9 | '政务',
10 | '开发技术',
11 | '产品能力',
12 | '运营规范',
13 | ]
14 | return categorys
15 | }
16 |
17 | export function getProducts() {
18 | let products = [
19 | '小程序性能优化课程',
20 | '小程序直播企业实践案例',
21 | '微信客服轻松配置,入门必修',
22 | '小程序如何帮助传统医院数字化?',
23 | '帮你快速掌握小商店经营秘诀',
24 | '了解小程序开发动态,听官方为你解读新能力',
25 | '快速了解微信小程序在医疗行业的应用',
26 | '解析常见小程序违规类型',
27 | '想做互联网的生意,可以通过微信怎么经营呢?',
28 | '政务行业小程序实践'
29 | ]
30 | let images = [
31 | 'https://res.wx.qq.com/op_res/RBwYn_b7VGuWuLJ2qBChU_LhYxhaP5JTy7TWgezsDY7RW_l_e04fR7oG7sCKmS8hc8mVeZaY6eUWT3nk-ww_ZQ',
32 | 'https://res.wx.qq.com/op_res/RBwYn_b7VGuWuLJ2qBChU-O3axOjUJGFgutF9Xc1JL1uxXFWYdW85mWG0Zvm5nv7rvP18CJ0q6-RRFM0xWLLog',
33 | 'https://res.wx.qq.com/op_res/RBwYn_b7VGuWuLJ2qBChU3ywQmrV-rSREDwo0Hp9m7iIZZ7Njvjq_TlOg_0ss0cgQL0pfKOuB2NRpAcwfALxvw',
34 | 'https://res.wx.qq.com/op_res/RBwYn_b7VGuWuLJ2qBChU1GROxmiPIBOCoA5Es44GxjN0KuCQQsoxEH33l05TCgk04n0dssHAIPxIV2ycSlSJA',
35 | 'https://res.wx.qq.com/op_res/RBwYn_b7VGuWuLJ2qBChU68wmBQzYcfQfuIAh1IKWq7OyG0EWxdWGhotYHFh-k-JpmkJ1Otq-mYUT8Dp3iucvg',
36 | 'https://res.wx.qq.com/op_res/UxKgRAAdvQE0sTh7eCEwT1ASo_fbE3TppPoza_9I7U7OreGNv8F8ltq80gqQSzxa-86bt-gWalLtgPDAhflj-w',
37 | 'https://res.wx.qq.com/op_res/UxKgRAAdvQE0sTh7eCEwT-SSHr1ULMcspj1yPw2dBQkxDV-Y_fOHodKNyHbS2JwBEVLnVKF2X_TPOhwZG9m0hQ',
38 | 'https://res.wx.qq.com/op_res/Zmvv0fisUjaMjuqWLhWWkuzGktaXJEQt46EaKsCKeT06Z4tROseXN0joI7h2qwzqyx2FUy57cveZL-8iArI8_Q',
39 | 'https://res.wx.qq.com/op_res/mGK9l-4vYzVgHuIz_uFeJitcJIfp9P4VSWxi3126XeiyZ2BnnH0xg-oIXAUgHBgaHjBMwxzSjSkEkTMRqzlKZw',
40 | 'https://res.wx.qq.com/op_res/mGK9l-4vYzVgHuIz_uFeJnw5zq4f_XW3swKAowexqAbziuojU5W9v4CJixA-NDJShkfS0ne3KWY_6SB56yqb3g',
41 | ]
42 | products = products.map((name, id) => ({
43 | name,
44 | image: images[(id % products.length)],
45 | comment: '一如既往的好',
46 | sales: 6500,
47 | discount: 0.01,
48 | price: 0.01
49 | }))
50 | return products
51 | }
--------------------------------------------------------------------------------
/examples/half-screen/.eslintrc.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Eslint config file
3 | * Documentation: https://eslint.org/docs/user-guide/configuring/
4 | * Install the Eslint extension before using this feature.
5 | */
6 | module.exports = {
7 | env: {
8 | es6: true,
9 | browser: true,
10 | node: true,
11 | },
12 | ecmaFeatures: {
13 | modules: true,
14 | },
15 | parserOptions: {
16 | ecmaVersion: 2018,
17 | sourceType: 'module',
18 | },
19 | globals: {
20 | wx: true,
21 | App: true,
22 | Page: true,
23 | getCurrentPages: true,
24 | getApp: true,
25 | Component: true,
26 | requirePlugin: true,
27 | requireMiniProgram: true,
28 | },
29 | // extends: 'eslint:recommended',
30 | rules: {},
31 | }
32 |
--------------------------------------------------------------------------------
/examples/half-screen/app.js:
--------------------------------------------------------------------------------
1 | // app.js
2 | App({})
3 |
--------------------------------------------------------------------------------
/examples/half-screen/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "pages": [
3 | "pages/index/index"
4 | ],
5 | "window": {
6 | "backgroundTextStyle": "light",
7 | "navigationBarBackgroundColor": "#fff",
8 | "navigationBarTitleText": "Weixin",
9 | "navigationBarTextStyle": "black"
10 | },
11 | "style": "v2",
12 | "renderer": "skyline",
13 | "rendererOptions": {
14 | "skyline": {
15 | "defaultDisplayBlock": true,
16 | "disableABTest": true,
17 | "sdkVersionBegin": "3.0.0",
18 | "sdkVersionEnd": "15.255.255"
19 | }
20 | },
21 | "lazyCodeLoading": "requiredComponents",
22 | "componentFramework": "glass-easel",
23 | "sitemapLocation": "sitemap.json"
24 | }
--------------------------------------------------------------------------------
/examples/half-screen/app.wxss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wechat-miniprogram/awesome-skyline/25e2d93c2daf3f78d0908ff53ea305147d0c8978/examples/half-screen/app.wxss
--------------------------------------------------------------------------------
/examples/half-screen/pages/index/index.js:
--------------------------------------------------------------------------------
1 | import { getCommentList } from "./comment-data"
2 |
3 | const { shared, timing } = wx.worklet
4 |
5 | const GestureState = {
6 | POSSIBLE: 0, // 0 此时手势未识别,如 panDown等
7 | BEGIN: 1, // 1 手势已识别
8 | ACTIVE: 2, // 2 连续手势活跃状态
9 | END: 3, // 3 手势终止
10 | CANCELLED: 4, // 4 手势取消,
11 | }
12 |
13 | Component({
14 | data: {
15 | list: getCommentList(),
16 | },
17 | lifetimes: {
18 | created() {
19 | this.transY = shared(1000)
20 | this.scrollTop = shared(0)
21 | this.startPan = shared(true)
22 | this.commentHeight = shared(1000)
23 | },
24 | ready() {
25 | const query = this.createSelectorQuery()
26 | // ready 生命周期里才能获取到首屏的布局信息
27 | query.select('.comment-container').boundingClientRect()
28 | query.exec((res) => {
29 | this.transY.value = this.commentHeight.value = res[0].height
30 | })
31 | // 通过 transY 一个 SharedValue 控制半屏的位置
32 | this.applyAnimatedStyle('.comment-container', () => {
33 | 'worklet'
34 | return { transform: `translateY(${this.transY.value}px)` }
35 | })
36 | },
37 | },
38 | methods: {
39 | onTapOpenComment() {
40 | this.openComment(300)
41 | },
42 | openComment(duration) {
43 | 'worklet'
44 | this.transY.value = timing(0, { duration })
45 | },
46 | onTapCloseComment() {
47 | this.closeComment()
48 | },
49 | closeComment() {
50 | 'worklet'
51 | this.transY.value = timing(this.commentHeight.value, { duration: 200 })
52 | },
53 | // shouldPanResponse 和 shouldScrollViewResponse 用于 pan 手势和 scroll-view 滚动手势的协商
54 | shouldPanResponse() {
55 | 'worklet'
56 | return this.startPan.value
57 | },
58 | shouldScrollViewResponse(pointerEvent) {
59 | 'worklet'
60 | // transY > 0 说明 pan 手势在移动半屏,此时滚动不应生效
61 | if (this.transY.value > 0) return false
62 | const scrollTop = this.scrollTop.value
63 | const { deltaY } = pointerEvent
64 | // deltaY > 0 是往上滚动,scrollTop <= 0 是滚动到顶部边界,此时 pan 开始生效,滚动不生效
65 | const result = scrollTop <= 0 && deltaY > 0
66 | this.startPan.value = result
67 | return !result
68 | },
69 | handlePan(gestureEvent) {
70 | 'worklet'
71 | if (gestureEvent.state === GestureState.ACTIVE) {
72 | const curPosition = this.transY.value
73 | const destination = Math.max(0, curPosition + gestureEvent.deltaY)
74 | if (curPosition === destination) return
75 | this.transY.value = destination
76 | }
77 |
78 | if (gestureEvent.state === GestureState.END || gestureEvent.state === GestureState.CANCELLED) {
79 | if (gestureEvent.velocityY > 500 && this.transY.value > 50) {
80 | this.closeComment()
81 | } else if (this.transY.value > this.commentHeight.value / 2) {
82 | this.closeComment()
83 | } else {
84 | this.openComment(100)
85 | }
86 | }
87 | },
88 | adjustDecelerationVelocity(velocity) {
89 | 'worklet'
90 | const scrollTop = this.scrollTop.value
91 | return scrollTop <= 0 ? 0 : velocity
92 | },
93 | handleScroll(evt) {
94 | 'worklet'
95 | this.scrollTop.value = evt.detail.scrollTop
96 | },
97 | },
98 | })
99 |
--------------------------------------------------------------------------------
/examples/half-screen/pages/index/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "usingComponents": {},
3 | "disableScroll": true,
4 | "navigationStyle": "custom"
5 | }
--------------------------------------------------------------------------------
/examples/half-screen/pages/index/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 |
42 |
--------------------------------------------------------------------------------
/examples/half-screen/pages/index/index.wxss:
--------------------------------------------------------------------------------
1 | page {
2 | display: flex;
3 | flex-direction: column;
4 | padding-top: env(safe-area-inset-top);
5 | width: 100vw;
6 | height: 100vh;
7 | color: #1A191E;
8 | }
9 | page, view {
10 | box-sizing: border-box;
11 | }
12 | pan-gesture-handler, vertical-drag-gesture-handler {
13 | display: flex;
14 | flex-direction: column;
15 | overflow: hidden;
16 | }
17 | .container {
18 | flex: 1;
19 | width: 100vw;
20 | min-height: auto;
21 | overflow: hidden;
22 | }
23 | .container image {
24 | width: 100vw;
25 | }
26 |
27 | .open-comment {
28 | display: flex;
29 | flex-direction: column;
30 | flex-shrink: 0;
31 | width: 100%;
32 | background-color: white;
33 | }
34 | .open-comment-wording {
35 | height: 66px;
36 | display: flex;
37 | justify-content: center;
38 | align-items: center;
39 | }
40 | .safe-area-inset-bottom {
41 | height: env(safe-area-inset-bottom);
42 | }
43 |
44 | .comment-container {
45 | width: 100vw;
46 | height: 70vh;
47 | display: flex;
48 | flex-direction: column;
49 | position: absolute;
50 | bottom: 0;
51 | z-index: 999;
52 | background-color: white;
53 | border-top-left-radius: 20px;
54 | border-top-right-radius: 20px;
55 | box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.2);
56 | transform: translateY(100%);
57 | }
58 | .comment-header {
59 | width: 100%;
60 | font-size: 16px;
61 | text-align: center;
62 | padding: 15px 0;
63 | }
64 | .close-comment {
65 | position: absolute;
66 | left: 20px;
67 | font-size: 10px;
68 | font-weight: bold;
69 | background-color: #F8F8F8;
70 | border-radius: 100%;
71 | width: 20px;
72 | height: 20px;
73 | line-height: 20px;
74 | z-index: 1;
75 | }
76 | .comment-list {
77 | flex: 1;
78 | overflow: hidden;
79 | }
80 | .comment-item {
81 | padding: 0 20px 20px;
82 | font-size: 13px;
83 | line-height: 1.4;
84 | }
85 | .main-comment, .sub-comment {
86 | display: flex;
87 | flex-direction: row;
88 | }
89 | .sub-comment {
90 | padding: 10px 22px 0;
91 | }
92 |
93 | .user-head-img {
94 | width: 33px;
95 | height: 33px;
96 | border-radius: 50%;
97 | margin-top: 5px;
98 | }
99 | .others {
100 | flex: 1;
101 | margin-left: 10px;
102 | }
103 | .user-name {
104 | white-space: nowrap;
105 | overflow: hidden;
106 | text-overflow: ellipsis;
107 | }
108 | .content {
109 | margin-top: 2px;
110 | }
111 |
--------------------------------------------------------------------------------
/examples/half-screen/project.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "appid": "wxe5f52902cf4de896",
3 | "compileType": "miniprogram",
4 | "libVersion": "latest",
5 | "packOptions": {
6 | "ignore": [],
7 | "include": []
8 | },
9 | "setting": {
10 | "coverView": true,
11 | "es6": true,
12 | "postcss": true,
13 | "minified": true,
14 | "enhance": true,
15 | "showShadowRootInWxmlPanel": true,
16 | "packNpmRelationList": [],
17 | "babelSetting": {
18 | "ignore": [],
19 | "disablePlugins": [],
20 | "outputPath": ""
21 | },
22 | "condition": false,
23 | "skylineRenderEnable": true,
24 | "compileWorklet": true
25 | },
26 | "condition": {},
27 | "editorSetting": {
28 | "tabIndent": "insertSpaces",
29 | "tabSize": 2
30 | }
31 | }
--------------------------------------------------------------------------------
/examples/half-screen/project.private.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html",
3 | "projectname": "half-screen",
4 | "setting": {
5 | "compileHotReLoad": false,
6 | "skylineRenderEnable": true
7 | },
8 | "libVersion": "latest"
9 | }
--------------------------------------------------------------------------------
/examples/half-screen/sitemap.json:
--------------------------------------------------------------------------------
1 | {
2 | "desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html",
3 | "rules": [{
4 | "action": "allow",
5 | "page": "*"
6 | }]
7 | }
--------------------------------------------------------------------------------
/examples/product-list/.eslintrc.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Eslint config file
3 | * Documentation: https://eslint.org/docs/user-guide/configuring/
4 | * Install the Eslint extension before using this feature.
5 | */
6 | module.exports = {
7 | env: {
8 | es6: true,
9 | browser: true,
10 | node: true,
11 | },
12 | ecmaFeatures: {
13 | modules: true,
14 | },
15 | parserOptions: {
16 | ecmaVersion: 2018,
17 | sourceType: 'module',
18 | },
19 | globals: {
20 | wx: true,
21 | App: true,
22 | Page: true,
23 | getCurrentPages: true,
24 | getApp: true,
25 | Component: true,
26 | requirePlugin: true,
27 | requireMiniProgram: true,
28 | },
29 | // extends: 'eslint:recommended',
30 | rules: {},
31 | }
32 |
--------------------------------------------------------------------------------
/examples/product-list/app.js:
--------------------------------------------------------------------------------
1 | // app.js
2 | App({})
3 |
--------------------------------------------------------------------------------
/examples/product-list/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "pages": [
3 | "pages/index/index"
4 | ],
5 | "window": {
6 | "backgroundTextStyle": "light",
7 | "navigationBarBackgroundColor": "#fff",
8 | "navigationBarTitleText": "Weixin",
9 | "navigationBarTextStyle": "black"
10 | },
11 | "style": "v2",
12 | "renderer": "skyline",
13 | "rendererOptions": {
14 | "skyline": {
15 | "defaultDisplayBlock": true,
16 | "disableABTest": true,
17 | "sdkVersionBegin": "3.0.0",
18 | "sdkVersionEnd": "15.255.255"
19 | }
20 | },
21 | "lazyCodeLoading": "requiredComponents",
22 | "componentFramework": "glass-easel",
23 | "sitemapLocation": "sitemap.json"
24 | }
--------------------------------------------------------------------------------
/examples/product-list/app.wxss:
--------------------------------------------------------------------------------
1 | /**app.wxss**/
2 | view {
3 | box-sizing: border-box;
4 | }
--------------------------------------------------------------------------------
/examples/product-list/components/navigation-bar/index.js:
--------------------------------------------------------------------------------
1 | Component({
2 | options: {
3 | multipleSlots: true // 在组件定义时的选项中启用多slot支持
4 | },
5 | /**
6 | * 组件的属性列表
7 | */
8 | properties: {
9 | extClass: {
10 | type: String,
11 | value: ''
12 | },
13 | title: {
14 | type: String,
15 | value: ''
16 | },
17 | background: {
18 | type: String,
19 | value: ''
20 | },
21 | color: {
22 | type: String,
23 | value: ''
24 | },
25 | back: {
26 | type: Boolean,
27 | value: true
28 | },
29 | loading: {
30 | type: Boolean,
31 | value: false
32 | },
33 | animated: {
34 | // 显示隐藏的时候opacity动画效果
35 | type: Boolean,
36 | value: true
37 | },
38 | show: {
39 | // 显示隐藏导航,隐藏的时候navigation-bar的高度占位还在
40 | type: Boolean,
41 | value: true,
42 | observer: '_showChange'
43 | },
44 | // back为true的时候,返回的页面深度
45 | delta: {
46 | type: Number,
47 | value: 1
48 | }
49 | },
50 | /**
51 | * 组件的初始数据
52 | */
53 | data: {
54 | displayStyle: ''
55 | },
56 | attached() {
57 | const rect = wx.getMenuButtonBoundingClientRect()
58 | wx.getSystemInfo({
59 | success: (res) => {
60 | this.setData({
61 | statusBarHeight: res.statusBarHeight,
62 | innerPaddingRight: `padding-right:${res.windowWidth - rect.left}px`,
63 | leftWidth: `width:${res.windowWidth - rect.left}px`,
64 | navBarHeight: rect.bottom + rect.top - res.statusBarHeight,
65 | })
66 | }
67 | })
68 | },
69 | /**
70 | * 组件的方法列表
71 | */
72 | methods: {
73 | _showChange(show) {
74 | const animated = this.data.animated
75 | let displayStyle = ''
76 | if (animated) {
77 | displayStyle = `opacity: ${show ? '1' : '0'};transition: opacity 0.5s;`
78 | } else {
79 | displayStyle = `display: ${show ? '' : 'none'}`
80 | }
81 | this.setData({
82 | displayStyle
83 | })
84 | },
85 | back() {
86 | const data = this.data
87 | if (data.delta) {
88 | wx.navigateBack({
89 | delta: data.delta
90 | })
91 | }
92 | this.triggerEvent('back', { delta: data.delta }, {})
93 | }
94 | }
95 | })
96 |
--------------------------------------------------------------------------------
/examples/product-list/components/navigation-bar/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {},
4 | "componentFramework": "glass-easel",
5 | "addGlobalClass": true
6 | }
--------------------------------------------------------------------------------
/examples/product-list/components/navigation-bar/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | {{title}}
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/examples/product-list/components/navigation-bar/index.wxss:
--------------------------------------------------------------------------------
1 | .weui-navigation-bar {
2 | overflow: hidden;
3 | color: rgba(0, 0, 0, .9);
4 | width: 100vw;
5 | }
6 |
7 | .weui-navigation-bar__placeholder {
8 | background: #f7f7f7;
9 | position: relative;
10 | }
11 |
12 | .weui-navigation-bar__inner, .weui-navigation-bar__inner .weui-navigation-bar__left {
13 | display: flex;
14 | align-items: center;
15 | flex-direction: row;
16 | }
17 |
18 | .weui-navigation-bar__inner {
19 | position: relative;
20 | padding-right: 95px;
21 | width: 100vw;
22 | box-sizing: border-box;
23 | }
24 |
25 | .weui-navigation-bar__inner .weui-navigation-bar__left {
26 | position: relative;
27 | /* width: 95px; */
28 | padding-left: 16px;
29 | box-sizing: border-box;
30 | }
31 |
32 | .weui-navigation-bar__btn_goback_wrapper {
33 | padding: 11px 18px 11px 16px;
34 | margin: -11px -18px -11px -16px;
35 | }
36 |
37 | .weui-navigation-bar__inner .weui-navigation-bar__left .weui-navigation-bar__btn_goback {
38 | font-size: 12px;
39 | width: 12px;
40 | height: 24px;
41 | background: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='24' viewBox='0 0 12 24'%3E %3Cpath fill-opacity='.9' fill-rule='evenodd' d='M10 19.438L8.955 20.5l-7.666-7.79a1.02 1.02 0 0 1 0-1.42L8.955 3.5 10 4.563 2.682 12 10 19.438z'/%3E%3C/svg%3E") no-repeat 50% 50%;
42 | background-size: cover;
43 | }
44 |
45 | .weui-navigation-bar__inner .weui-navigation-bar__center {
46 | font-size: 17px;
47 | text-align: center;
48 | position: relative;
49 | flex: 1;
50 | display: flex;
51 | flex-direction: column;
52 | align-items: center;
53 | justify-content: center;
54 | font-weight: bold;
55 | }
56 |
57 | @media(prefers-color-scheme: dark) {
58 | .weui-navigation-bar {
59 | color: hsla(0, 0%, 100%, .8);
60 | }
61 | .weui-navigation-bar__inner {
62 | background-color: #1f1f1f;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/examples/product-list/images/search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wechat-miniprogram/awesome-skyline/25e2d93c2daf3f78d0908ff53ea305147d0c8978/examples/product-list/images/search.png
--------------------------------------------------------------------------------
/examples/product-list/pages/index/index.js:
--------------------------------------------------------------------------------
1 | import { getCategory, getGoods, getVIPCategory } from '../../util'
2 |
3 | const systemInfo = wx.getSystemInfoSync()
4 |
5 | const { shared, Easing } = wx.worklet
6 |
7 | const lerp = function (begin, end, t) {
8 | 'worklet'
9 | return begin + (end - begin) * t
10 | }
11 |
12 | const clamp = function (cur, lowerBound, upperBound) {
13 | 'worklet'
14 | if (cur > upperBound) return upperBound
15 | if (cur < lowerBound) return lowerBound
16 | return cur
17 | }
18 |
19 | Component({
20 | data: {
21 | goods: getGoods(30),
22 | categorySet: [{
23 | page: 0,
24 | categorys: getCategory()
25 | }, {
26 | page: 1,
27 | categorys: getCategory().reverse()
28 | }],
29 | paddingTop: 44,
30 | renderer: 'skyline',
31 | vipCategorys: getVIPCategory(),
32 | categoryItemWidth: 0,
33 | intoView: '',
34 | selected: 0
35 | },
36 |
37 | lifetimes: {
38 | created() {
39 | this.searchBarWidth = shared(100)
40 | this.navBarOpactiy = shared(1)
41 | },
42 | attached() {
43 | const padding = 10 * 2
44 | const categoryItemWidth = (systemInfo.windowWidth - padding) / 5
45 | this.setData({ categoryItemWidth, paddingTop: systemInfo.statusBarHeight, renderer: this.renderer })
46 |
47 | this.applyAnimatedStyle('.nav-bar', () => {
48 | 'worklet'
49 | return {
50 | opacity: this.navBarOpactiy.value
51 | }
52 | })
53 |
54 | this.applyAnimatedStyle('.search', () => {
55 | 'worklet'
56 | return {
57 | width: `${this.searchBarWidth.value}%`,
58 | }
59 | })
60 |
61 | this.applyAnimatedStyle('.search-container', () => {
62 | 'worklet'
63 | return {
64 | backgroundColor: (this.navBarOpactiy.value > 0 && this.renderer == 'skyline') ? 'transparent' : '#fff'
65 | }
66 | })
67 | },
68 | },
69 |
70 | methods: {
71 | chooseVipCategory(evt) {
72 | const id = evt.currentTarget.dataset.id
73 | this.setData({
74 | intoView: `vip-category-${id}`,
75 | selected: parseInt(id, 10)
76 | })
77 | },
78 |
79 | handleScrollUpdate(evt) {
80 | 'worklet'
81 | const maxDistance = 60
82 | const scrollTop = clamp(evt.detail.scrollTop, 0, maxDistance)
83 | const progress = scrollTop / maxDistance
84 | const EasingFn = Easing.cubicBezier(0.4, 0.0, 0.2, 1.0)
85 | this.searchBarWidth.value = lerp(100, 70, EasingFn(progress))
86 | this.navBarOpactiy.value = lerp(1, 0, progress)
87 | },
88 | },
89 | })
90 |
--------------------------------------------------------------------------------
/examples/product-list/pages/index/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "usingComponents": {
3 | "navigation-bar": "../../components/navigation-bar"
4 | },
5 | "disableScroll": true,
6 | "navigationStyle": "custom"
7 | }
8 |
--------------------------------------------------------------------------------
/examples/product-list/pages/index/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 微信学堂
6 |
7 |
8 |
9 |
10 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | 这是skyline实现的~
26 | 搜索
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | {{category.name}}
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
60 |
61 |
62 | {{item.name}}
63 |
64 |
65 |
66 |
67 |
74 |
75 |
76 |
77 |
78 | {{item.title}}
79 |
80 |
83 |
84 |
85 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/examples/product-list/pages/index/index.wxss:
--------------------------------------------------------------------------------
1 | .fake-nav-bar {
2 | height: 60px;
3 | }
4 |
5 | .search-container {
6 | padding: 0 16px 10px 16px;
7 | /* margin-top: 44px; */
8 | /* background-color: transparent; */
9 | background-color: #FFF;
10 | }
11 | .search {
12 | display: flex;
13 | flex-direction: row;
14 | box-sizing: border-box;
15 | width: 100%;
16 | height: 40px;
17 | border-radius: 20px;
18 | border: 2px solid #07c160;
19 | position: relative;
20 | align-items: center;
21 | background-color: #fff;
22 | }
23 |
24 | .search-text {
25 | color: #8f8888;
26 | font-size: 14px;
27 | }
28 |
29 | .search-icon-wrp {
30 | display: flex;
31 | width: 30px;
32 | height: 100%;
33 | flex-direction: row;
34 | align-items: center;
35 | justify-content: center;
36 | }
37 |
38 | .search-icon {
39 | width: 16px;
40 | height: 16px;
41 | }
42 |
43 | .search-btn {
44 | position: absolute;
45 | right: 0;
46 | width: 60px;
47 | height: 100%;
48 | border-radius: 20px;
49 | background-color: #07c160;
50 | display: flex;
51 | align-items: center;
52 | justify-content: center;
53 | color: #FFF;
54 | font-size: 16px;
55 | /* font-weight: bold; */
56 | }
57 |
58 | .nav-bar {
59 | background-color: #fff;
60 | position: absolute;
61 | }
62 |
63 | .nav-left {
64 | display: flex;
65 | flex-direction: row;
66 | align-items: center;
67 | }
68 |
69 | .nav-logo {
70 | width: 40px;
71 | height: 40px;
72 | border-radius: 50%;
73 | }
74 |
75 | .nav-title {
76 | margin-left: 2px;
77 | font-size: 20px;
78 | color: #3f3e3e;
79 | /* font-weight: bold; */
80 | }
81 |
82 | .scroll-area {
83 | height: 100vh;
84 | }
85 |
86 | .category-wrp {
87 | height: 220px;
88 | padding: 10px 0;
89 | background-color: #FFF;
90 | }
91 |
92 | .category-list {
93 | display: flex;
94 | flex-direction: row;
95 | justify-content: space-between;
96 | flex-wrap: wrap;
97 | padding: 0 10px;
98 | }
99 |
100 | .category-item {
101 | display: flex;
102 | flex-direction: column;
103 | align-items: center;
104 | margin: 10px 0;
105 | font-size: 14px;
106 | }
107 |
108 | .category-icon {
109 | width: 50px;
110 | height: 50px;
111 | margin-bottom: 10px;
112 | border-radius: 50%;
113 | }
114 |
115 | .category-name {
116 | height: 30px;
117 | display: flex;
118 | justify-content: center;
119 | align-items: center;
120 | }
121 |
122 | .good {
123 | background-color: #FFF;
124 | border-radius: 6px;
125 | overflow: hidden;
126 | }
127 |
128 | .good-icon {
129 | width: 100%;
130 | }
131 |
132 | .good-title {
133 | width: 100%;
134 | line-height: 1.4;
135 | margin: 8px 0;
136 | padding: 0 5px;
137 | font-size: 14px;
138 | }
139 |
140 | .good-comment {
141 | font-size: 12px;
142 | color: #ccc;
143 | padding-left: 5px;
144 | margin-bottom: 10px;
145 | }
146 |
147 | .vip-categorys-list {
148 | background-color: #fff;
149 | width: 100%;
150 | height: 60px;
151 | display: flex;
152 | flex-direction: row;
153 | }
154 |
155 | .vip-category-item {
156 | display: flex;
157 | flex-shrink: 0;
158 | height: 100%;
159 | justify-content: center;
160 | align-items: center;
161 | padding-right: 20px;
162 | padding-left: 40px;
163 | }
164 | .vip-category-item:first-child {
165 | padding-left: 20px;
166 | }
167 |
168 | .vip-category-name {
169 | color: #8f8888;
170 | font-size: 16px;
171 | transition: transform .3s;
172 | }
173 |
174 | .selected {
175 | transform: scale(1.2);
176 | color: #2c2c2c;
177 | font-weight: bold;
178 | }
179 |
--------------------------------------------------------------------------------
/examples/product-list/project.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "appid": "wxe5f52902cf4de896",
3 | "compileType": "miniprogram",
4 | "libVersion": "latest",
5 | "packOptions": {
6 | "ignore": [],
7 | "include": []
8 | },
9 | "setting": {
10 | "coverView": true,
11 | "es6": true,
12 | "postcss": true,
13 | "minified": true,
14 | "enhance": true,
15 | "showShadowRootInWxmlPanel": true,
16 | "packNpmRelationList": [],
17 | "babelSetting": {
18 | "ignore": [],
19 | "disablePlugins": [],
20 | "outputPath": ""
21 | },
22 | "condition": false,
23 | "skylineRenderEnable": true,
24 | "compileWorklet": true
25 | },
26 | "condition": {},
27 | "editorSetting": {
28 | "tabIndent": "insertSpaces",
29 | "tabSize": 2
30 | }
31 | }
--------------------------------------------------------------------------------
/examples/product-list/project.private.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html",
3 | "projectname": "product-list",
4 | "setting": {
5 | "compileHotReLoad": false
6 | },
7 | "libVersion": "latest"
8 | }
--------------------------------------------------------------------------------
/examples/product-list/sitemap.json:
--------------------------------------------------------------------------------
1 | {
2 | "desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html",
3 | "rules": [{
4 | "action": "allow",
5 | "page": "*"
6 | }]
7 | }
--------------------------------------------------------------------------------
/examples/product-list/util.js:
--------------------------------------------------------------------------------
1 | export function getCategory() {
2 | let categorys = [
3 | '中小商户',
4 | '商超零售',
5 | '品牌服饰',
6 | '餐饮',
7 | '医疗',
8 | '酒旅',
9 | '政务',
10 | '开发技术',
11 | '产品能力',
12 | '运营规范',
13 | ]
14 | let images = [
15 | 'https://res.wx.qq.com/op_res/mGK9l-4vYzVgHuIz_uFeJgc9If4xjgvN3O4UQclWMiJxMoExkarf71FN-3SSf3Sh-GoatfvTbKcPE-grH-1L9g',
16 | 'https://res.wx.qq.com/op_res/mGK9l-4vYzVgHuIz_uFeJrmxgZKLSYHHwqx6YfJyqPnSNeIHovelr_r6GLFpsiCuCuBgYKBc68vBi0dJYSMeZA',
17 | 'https://res.wx.qq.com/op_res/mGK9l-4vYzVgHuIz_uFeJk4e_uP2-FWEQKo5Ijp5itIrlf-qIXozTGY6D595Ri2YIoLCUS7YseOda2JLTAEz7Q',
18 | 'https://res.wx.qq.com/op_res/mGK9l-4vYzVgHuIz_uFeJj6M4Aqf4ov3F7tRlrb62now5owS_Q6vkhsWjnU_uWVbBR84dTHxG4tzAcjwAqOGZQ',
19 | 'https://res.wx.qq.com/op_res/mGK9l-4vYzVgHuIz_uFeJrBCMpypwJ_xFgSnas6etb7Y6JuMRRMBJ6cSMmbmSkCkOjCSPDdC_eLEK1_FT-d-PQ',
20 | 'https://res.wx.qq.com/op_res/mGK9l-4vYzVgHuIz_uFeJitcJIfp9P4VSWxi3126XeiyZ2BnnH0xg-oIXAUgHBgaHjBMwxzSjSkEkTMRqzlKZw',
21 | 'https://res.wx.qq.com/op_res/mGK9l-4vYzVgHuIz_uFeJnw5zq4f_XW3swKAowexqAbziuojU5W9v4CJixA-NDJShkfS0ne3KWY_6SB56yqb3g',
22 | 'https://res.wx.qq.com/op_res/mGK9l-4vYzVgHuIz_uFeJu8Q1L10fFiMMnZVYnLoP1GuT0q26CJLtjSRfJAjTvj6DBNuWrzzMD9UYZEb-pznKA',
23 | 'https://res.wx.qq.com/op_res/RBwYn_b7VGuWuLJ2qBChUzvBckq_FnOrUIIgSP2hJ9cYByUIwgzBEaDCcF5YiPNMmcMg0ewQBn_nMCt-q71vsg',
24 | 'https://res.wx.qq.com/op_res/Zmvv0fisUjaMjuqWLhWWkuzGktaXJEQt46EaKsCKeT06Z4tROseXN0joI7h2qwzqyx2FUy57cveZL-8iArI8_Q',
25 | ]
26 | categorys = categorys.map((name, id) => ({
27 | id,
28 | name,
29 | icon: images[(id % categorys.length)] //`/images/boy/b${id}.png`
30 | }))
31 | return categorys
32 | }
33 |
34 | export function getGoods(num) {
35 | const titles = [
36 | '小程序性能优化课程基于实际开发场景,提升小程序性能表现,满足用户体验',
37 | '解析常见小程序违规类型,帮助大家更好理解平台规则',
38 | '快速了解微信小程序在医疗行业的应用',
39 | '小程序直播的企业实践案例。',
40 | '微信客服轻松配置,入门必修',
41 | '想做互联网的生意,可以通过微信怎么经营呢?',
42 | '了解小程序开发动态,听官方为你解读新能力',
43 | '医保支付、互联网医院、线上问诊...小程序如何帮助传统医院数字化?',
44 | '内含开店指引、店铺运营和平台规则,帮你快速掌握小商店经营秘诀',
45 | '浅谈连锁零售的私域流量运营'
46 | ]
47 |
48 | const images = [
49 | 'https://res.wx.qq.com/op_res/RBwYn_b7VGuWuLJ2qBChU_LhYxhaP5JTy7TWgezsDY7RW_l_e04fR7oG7sCKmS8hc8mVeZaY6eUWT3nk-ww_ZQ',
50 | 'https://res.wx.qq.com/op_res/Zmvv0fisUjaMjuqWLhWWkuzGktaXJEQt46EaKsCKeT06Z4tROseXN0joI7h2qwzqyx2FUy57cveZL-8iArI8_Q',
51 | 'https://res.wx.qq.com/op_res/mGK9l-4vYzVgHuIz_uFeJrBCMpypwJ_xFgSnas6etb7Y6JuMRRMBJ6cSMmbmSkCkOjCSPDdC_eLEK1_FT-d-PQ',
52 | 'https://res.wx.qq.com/op_res/RBwYn_b7VGuWuLJ2qBChU-O3axOjUJGFgutF9Xc1JL1uxXFWYdW85mWG0Zvm5nv7rvP18CJ0q6-RRFM0xWLLog',
53 | 'https://res.wx.qq.com/op_res/RBwYn_b7VGuWuLJ2qBChU3ywQmrV-rSREDwo0Hp9m7iIZZ7Njvjq_TlOg_0ss0cgQL0pfKOuB2NRpAcwfALxvw',
54 | 'https://res.wx.qq.com/op_res/mGK9l-4vYzVgHuIz_uFeJgc9If4xjgvN3O4UQclWMiJxMoExkarf71FN-3SSf3Sh-GoatfvTbKcPE-grH-1L9g',
55 | 'https://res.wx.qq.com/op_res/mGK9l-4vYzVgHuIz_uFeJu8Q1L10fFiMMnZVYnLoP1GuT0q26CJLtjSRfJAjTvj6DBNuWrzzMD9UYZEb-pznKA',
56 | 'https://res.wx.qq.com/op_res/RBwYn_b7VGuWuLJ2qBChU1GROxmiPIBOCoA5Es44GxjN0KuCQQsoxEH33l05TCgk04n0dssHAIPxIV2ycSlSJA',
57 | 'https://res.wx.qq.com/op_res/RBwYn_b7VGuWuLJ2qBChU68wmBQzYcfQfuIAh1IKWq7OyG0EWxdWGhotYHFh-k-JpmkJ1Otq-mYUT8Dp3iucvg',
58 | 'https://res.wx.qq.com/op_res/mGK9l-4vYzVgHuIz_uFeJrmxgZKLSYHHwqx6YfJyqPnSNeIHovelr_r6GLFpsiCuCuBgYKBc68vBi0dJYSMeZA'
59 | ]
60 |
61 | const goods = []
62 | for (let id = 0; id < num; id++) {
63 | goods.push({
64 | id,
65 | title: titles[(id % titles.length)],
66 | icon: images[(id % titles.length)] // `/images/goods/g${(id % num)}.jpg`
67 | })
68 | }
69 | return goods
70 | }
71 |
72 | export function getVIPCategory() {
73 | let vipCategorys = [
74 | '本月最热',
75 | '官方经营',
76 | '行业实践',
77 | '微信服务商'
78 | ]
79 | vipCategorys = vipCategorys.map((name, id) => ({
80 | id,
81 | name
82 | }))
83 | return vipCategorys
84 | }
--------------------------------------------------------------------------------
/examples/refresher-two-level/app.js:
--------------------------------------------------------------------------------
1 | // app.js
2 | App({})
3 |
--------------------------------------------------------------------------------
/examples/refresher-two-level/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "pages": [
3 | "index/index"
4 | ],
5 | "window": {
6 | "backgroundTextStyle": "light",
7 | "navigationBarBackgroundColor": "#fff",
8 | "navigationBarTitleText": "Weixin",
9 | "navigationBarTextStyle": "black"
10 | },
11 | "style": "v2",
12 | "renderer": "skyline",
13 | "rendererOptions": {
14 | "skyline": {
15 | "defaultDisplayBlock": true,
16 | "disableABTest": true,
17 | "sdkVersionBegin": "3.0.0",
18 | "sdkVersionEnd": "15.255.255"
19 | }
20 | },
21 | "lazyCodeLoading": "requiredComponents",
22 | "componentFramework": "glass-easel",
23 | "sitemapLocation": "sitemap.json"
24 | }
--------------------------------------------------------------------------------
/examples/refresher-two-level/app.wxss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wechat-miniprogram/awesome-skyline/25e2d93c2daf3f78d0908ff53ea305147d0c8978/examples/refresher-two-level/app.wxss
--------------------------------------------------------------------------------
/examples/refresher-two-level/components/navigation-bar/index.js:
--------------------------------------------------------------------------------
1 | Component({
2 | options: {
3 | multipleSlots: true // 在组件定义时的选项中启用多slot支持
4 | },
5 | /**
6 | * 组件的属性列表
7 | */
8 | properties: {
9 | extClass: {
10 | type: String,
11 | value: ''
12 | },
13 | title: {
14 | type: String,
15 | value: ''
16 | },
17 | background: {
18 | type: String,
19 | value: ''
20 | },
21 | color: {
22 | type: String,
23 | value: ''
24 | },
25 | back: {
26 | type: Boolean,
27 | value: true
28 | },
29 | loading: {
30 | type: Boolean,
31 | value: false
32 | },
33 | animated: {
34 | // 显示隐藏的时候opacity动画效果
35 | type: Boolean,
36 | value: true
37 | },
38 | show: {
39 | // 显示隐藏导航,隐藏的时候navigation-bar的高度占位还在
40 | type: Boolean,
41 | value: true,
42 | observer: '_showChange'
43 | },
44 | // back为true的时候,返回的页面深度
45 | delta: {
46 | type: Number,
47 | value: 1
48 | }
49 | },
50 | /**
51 | * 组件的初始数据
52 | */
53 | data: {
54 | displayStyle: ''
55 | },
56 | attached() {
57 | const rect = wx.getMenuButtonBoundingClientRect()
58 | wx.getSystemInfo({
59 | success: (res) => {
60 | this.setData({
61 | statusBarHeight: res.statusBarHeight,
62 | innerPaddingRight: `padding-right:${res.windowWidth - rect.left}px`,
63 | leftWidth: `width:${res.windowWidth - rect.left}px`,
64 | navBarHeight: rect.bottom + rect.top - res.statusBarHeight,
65 | })
66 | }
67 | })
68 | },
69 | /**
70 | * 组件的方法列表
71 | */
72 | methods: {
73 | _showChange(show) {
74 | const animated = this.data.animated
75 | let displayStyle = ''
76 | if (animated) {
77 | displayStyle = `opacity: ${show ? '1' : '0'};transition: opacity 0.5s;`
78 | } else {
79 | displayStyle = `display: ${show ? '' : 'none'}`
80 | }
81 | this.setData({
82 | displayStyle
83 | })
84 | },
85 | back() {
86 | const data = this.data
87 | if (data.delta) {
88 | wx.navigateBack({
89 | delta: data.delta
90 | })
91 | }
92 | this.triggerEvent('back', { delta: data.delta }, {})
93 | }
94 | }
95 | })
96 |
--------------------------------------------------------------------------------
/examples/refresher-two-level/components/navigation-bar/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {},
4 | "componentFramework": "glass-easel",
5 | "addGlobalClass": true
6 | }
--------------------------------------------------------------------------------
/examples/refresher-two-level/components/navigation-bar/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | {{title}}
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/examples/refresher-two-level/components/navigation-bar/index.wxss:
--------------------------------------------------------------------------------
1 | .weui-navigation-bar {
2 | overflow: hidden;
3 | color: rgba(0, 0, 0, .9);
4 | width: 100vw;
5 | }
6 |
7 | .weui-navigation-bar__placeholder {
8 | background: #f7f7f7;
9 | position: relative;
10 | }
11 |
12 | .weui-navigation-bar__inner, .weui-navigation-bar__inner .weui-navigation-bar__left {
13 | display: flex;
14 | align-items: center;
15 | flex-direction: row;
16 | }
17 |
18 | .weui-navigation-bar__inner {
19 | position: relative;
20 | padding-right: 95px;
21 | width: 100vw;
22 | box-sizing: border-box;
23 | }
24 |
25 | .weui-navigation-bar__inner .weui-navigation-bar__left {
26 | position: relative;
27 | /* width: 95px; */
28 | padding-left: 16px;
29 | box-sizing: border-box;
30 | }
31 |
32 | .weui-navigation-bar__btn_goback_wrapper {
33 | padding: 11px 18px 11px 16px;
34 | margin: -11px -18px -11px -16px;
35 | }
36 |
37 | .weui-navigation-bar__inner .weui-navigation-bar__left .weui-navigation-bar__btn_goback {
38 | font-size: 12px;
39 | width: 12px;
40 | height: 24px;
41 | background: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='24' viewBox='0 0 12 24'%3E %3Cpath fill-opacity='.9' fill-rule='evenodd' d='M10 19.438L8.955 20.5l-7.666-7.79a1.02 1.02 0 0 1 0-1.42L8.955 3.5 10 4.563 2.682 12 10 19.438z'/%3E%3C/svg%3E") no-repeat 50% 50%;
42 | background-size: cover;
43 | }
44 |
45 | .weui-navigation-bar__inner .weui-navigation-bar__center {
46 | font-size: 17px;
47 | text-align: center;
48 | position: relative;
49 | flex: 1;
50 | display: flex;
51 | flex-direction: column;
52 | align-items: center;
53 | justify-content: center;
54 | font-weight: bold;
55 | }
56 |
57 | @media(prefers-color-scheme: dark) {
58 | .weui-navigation-bar {
59 | color: hsla(0, 0%, 100%, .8);
60 | }
61 | .weui-navigation-bar__inner {
62 | background-color: #1f1f1f;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/examples/refresher-two-level/goods.less:
--------------------------------------------------------------------------------
1 | .exp-room {
2 | .nav-bar {
3 | background-color: #fff;
4 | position: absolute;
5 | }
6 |
7 | .nav-left {
8 | display: flex;
9 | flex-direction: row;
10 | align-items: center;
11 | }
12 |
13 | .nav-logo {
14 | width: 40px;
15 | height: 40px;
16 | border-radius: 50%;
17 | }
18 |
19 | .nav-title {
20 | margin-left: 2px;
21 | font-size: 20px;
22 | color: #3f3e3e;
23 | }
24 |
25 | width: 100vw;
26 | height: 100vh;
27 | background-color: rgb(3, 3, 41);
28 |
29 | .nav-bar {
30 | position: relative;
31 | background-color: rgb(3, 3, 41);
32 | }
33 |
34 | .nav-logo {
35 | width: 32px;
36 | height: 32px;
37 | }
38 |
39 | .nav-title {
40 | color: #fff;
41 | font-size: 18px;
42 | }
43 |
44 | .exp-category-list {
45 | display: flex;
46 | flex-direction: row;
47 | margin: 10px 16px;
48 | }
49 |
50 | .exp-category-item {
51 | margin-right: 20px;
52 | }
53 |
54 | .exp-category-name {
55 | color: #8f8888;
56 | font-size: 16px;
57 | }
58 |
59 | .selected {
60 | transform: scale(1.2);
61 | color: #fff;
62 | font-weight: bold;
63 | }
64 |
65 | .scroll-area {
66 | flex: 1;
67 | }
68 |
69 | .video-container {
70 | height: 240px;
71 | }
72 |
73 | .video {
74 | overflow: hidden;
75 | border-radius: 16px;
76 | margin: 10px 0;
77 | position: relative;
78 | width: 100%;
79 | height: 100%;
80 | }
81 |
82 | .video-title {
83 | position: absolute;
84 | top: 16px;
85 | left: 16px;
86 | color: #fff;
87 | font-size: 14px;
88 | }
89 |
90 | .expand {
91 | width: 100%;
92 | height: 100%;
93 | }
94 |
95 | .refresher-tips {
96 | position: absolute;
97 | bottom: 20px;
98 | width: 100%;
99 | text-align: center;
100 | color: #fff;
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/examples/refresher-two-level/goods.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | 官方讲师课程
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | {{item.name}}
17 |
18 |
19 |
20 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/examples/refresher-two-level/goods/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "usingComponents": {
3 | "navigation-bar": "../components/navigation-bar"
4 | },
5 | "renderer": "skyline",
6 | "componentFramework": "glass-easel"
7 | }
--------------------------------------------------------------------------------
/examples/refresher-two-level/goods/index.less:
--------------------------------------------------------------------------------
1 | @import '../goods.less';
--------------------------------------------------------------------------------
/examples/refresher-two-level/goods/index.ts:
--------------------------------------------------------------------------------
1 | import { getCategory, getGoods, getVIPCategory, getExpCategory, getVideoList } from '../util'
2 |
3 | // pages/goods/index.ts
4 | Page({
5 |
6 | /**
7 | * 页面的初始数据
8 | */
9 | data: {
10 | goodsData: {
11 | expSelected: 0,
12 | expCategorys: getExpCategory(),
13 | videoList: getVideoList(20),
14 | hasRouteDone: false,
15 | }
16 | },
17 |
18 | back() {
19 | wx.navigateBack({})
20 | },
21 |
22 | /**
23 | * 生命周期函数--监听页面加载
24 | */
25 |
26 | onRouteDone() {
27 | console.info('@@@ goods page routeDone ')
28 | this.setData({
29 | 'goodsData.hasRouteDone': true,
30 | })
31 | if (this.eventChannel) {
32 | this.eventChannel.emit('nextPageRouteDone', { });
33 | }
34 | },
35 |
36 | onLoad() {
37 | this.eventChannel = this.getOpenerEventChannel()
38 | },
39 |
40 | /**
41 | * 生命周期函数--监听页面初次渲染完成
42 | */
43 | onReady() {
44 |
45 | },
46 |
47 | /**
48 | * 生命周期函数--监听页面显示
49 | */
50 | onShow() {
51 |
52 | },
53 |
54 | /**
55 | * 生命周期函数--监听页面隐藏
56 | */
57 | onHide() {
58 |
59 | },
60 |
61 | /**
62 | * 生命周期函数--监听页面卸载
63 | */
64 | onUnload() {
65 |
66 | },
67 |
68 | /**
69 | * 页面相关事件处理函数--监听用户下拉动作
70 | */
71 | onPullDownRefresh() {
72 |
73 | },
74 |
75 | /**
76 | * 页面上拉触底事件的处理函数
77 | */
78 | onReachBottom() {
79 |
80 | },
81 |
82 | /**
83 | * 用户点击右上角分享
84 | */
85 | onShareAppMessage() {
86 |
87 | }
88 | })
--------------------------------------------------------------------------------
/examples/refresher-two-level/goods/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/examples/refresher-two-level/images/back_delete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wechat-miniprogram/awesome-skyline/25e2d93c2daf3f78d0908ff53ea305147d0c8978/examples/refresher-two-level/images/back_delete.png
--------------------------------------------------------------------------------
/examples/refresher-two-level/images/search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wechat-miniprogram/awesome-skyline/25e2d93c2daf3f78d0908ff53ea305147d0c8978/examples/refresher-two-level/images/search.png
--------------------------------------------------------------------------------
/examples/refresher-two-level/index/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "usingComponents": {
3 | "navigation-bar": "../components/navigation-bar"
4 | },
5 | "disableScroll": true,
6 | "renderer": "skyline",
7 | "navigationStyle": "custom",
8 | "componentFramework": "glass-easel"
9 | }
10 |
--------------------------------------------------------------------------------
/examples/refresher-two-level/index/index.less:
--------------------------------------------------------------------------------
1 | @import '../goods.less';
2 |
3 | .fake-nav-bar {
4 | height: 60px;
5 | }
6 |
7 | .search-container {
8 | padding: 0 16px 10px 16px;
9 | /* margin-top: 44px; */
10 | /* background-color: transparent; */
11 | background-color: #FFF;
12 | }
13 |
14 | .search {
15 | display: flex;
16 | flex-direction: row;
17 | box-sizing: border-box;
18 | width: 100%;
19 | height: 40px;
20 | border-radius: 20px;
21 | border: 2px solid #07c160;
22 | position: relative;
23 | align-items: center;
24 | background-color: #fff;
25 | }
26 |
27 | .search-text {
28 | color: #8f8888;
29 | font-size: 14px;
30 | }
31 |
32 | .search-icon-wrp {
33 | display: flex;
34 | width: 30px;
35 | height: 100%;
36 | flex-direction: row;
37 | align-items: center;
38 | justify-content: center;
39 | }
40 |
41 | .search-icon {
42 | width: 16px;
43 | height: 16px;
44 | }
45 |
46 | .search-btn {
47 | position: absolute;
48 | right: 0;
49 | width: 60px;
50 | height: 100%;
51 | border-radius: 20px;
52 | background-color: #07c160;
53 | display: flex;
54 | align-items: center;
55 | justify-content: center;
56 | color: #FFF;
57 | font-size: 16px;
58 | /* font-weight: bold; */
59 | }
60 |
61 | .nav-bar {
62 | background-color: #fff;
63 | position: absolute;
64 | }
65 |
66 | .nav-left {
67 | display: flex;
68 | flex-direction: row;
69 | align-items: center;
70 | }
71 |
72 | .nav-logo {
73 | width: 40px;
74 | height: 40px;
75 | border-radius: 50%;
76 | }
77 |
78 | .nav-title {
79 | margin-left: 2px;
80 | font-size: 20px;
81 | color: #3f3e3e;
82 | /* font-weight: bold; */
83 | }
84 |
85 | .scroll-area {
86 | height: 100vh;
87 | }
88 |
89 | .category-wrp {
90 | height: 220px;
91 | padding: 10px 0;
92 | background-color: #FFF;
93 | }
94 |
95 | .category-list {
96 | display: flex;
97 | flex-direction: row;
98 | justify-content: space-between;
99 | flex-wrap: wrap;
100 | padding: 0 10px;
101 | }
102 |
103 | .category-item {
104 | display: flex;
105 | flex-direction: column;
106 | align-items: center;
107 | margin: 10px 0;
108 | font-size: 14px;
109 | }
110 |
111 | .category-icon {
112 | width: 50px;
113 | height: 50px;
114 | margin-bottom: 10px;
115 | border-radius: 50%;
116 | }
117 |
118 | .category-name {
119 | height: 30px;
120 | display: flex;
121 | justify-content: center;
122 | align-items: center;
123 | }
124 |
125 | .good {
126 | background-color: #FFF;
127 | }
128 |
129 | .good-icon {
130 | width: 100%;
131 | border-radius: 6px;
132 | }
133 |
134 | .good-title {
135 | width: 100%;
136 | line-height: 1.4;
137 | margin: 8px 0;
138 | padding: 0 5px;
139 | font-size: 14px;
140 | }
141 |
142 | .good-comment {
143 | font-size: 12px;
144 | color: #ccc;
145 | padding-left: 5px;
146 | margin-bottom: 10px;
147 | }
148 |
149 | .vip-categorys-list {
150 | background-color: #fff;
151 | width: 100%;
152 | height: 60px;
153 | }
154 |
155 | .vip-category-item {
156 | display: flex;
157 | height: 100%;
158 | justify-content: center;
159 | padding-right: 20px;
160 | }
161 |
162 | .vip-category-name {
163 | color: #8f8888;
164 | font-size: 16px;
165 | transition: transform .3s;
166 | }
167 |
168 | .selected {
169 | transform: scale(1.2);
170 | color: #2c2c2c;
171 | font-weight: bold;
172 | }
--------------------------------------------------------------------------------
/examples/refresher-two-level/index/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | 微信学堂
7 |
8 |
9 |
10 |
11 |
34 |
35 |
36 |
37 | {{refreshStatus}}
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 | 这是skyline实现的~{{twoLevelStyle}}
49 | 搜索
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 | {{category.name}}
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
81 |
82 |
83 |
84 | {{item.name}}
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
99 |
100 | {{item.title}}
101 |
102 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
--------------------------------------------------------------------------------
/examples/refresher-two-level/project.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "appid": "wxe5f52902cf4de896",
3 | "compileType": "miniprogram",
4 | "libVersion": "3.1.5",
5 | "packOptions": {
6 | "ignore": [],
7 | "include": []
8 | },
9 | "setting": {
10 | "coverView": true,
11 | "es6": true,
12 | "postcss": true,
13 | "minified": true,
14 | "enhance": true,
15 | "showShadowRootInWxmlPanel": true,
16 | "packNpmRelationList": [],
17 | "babelSetting": {
18 | "ignore": [],
19 | "disablePlugins": [],
20 | "outputPath": ""
21 | },
22 | "useCompilerPlugins": [
23 | "typescript",
24 | "less"
25 | ]
26 | },
27 | "condition": {},
28 | "editorSetting": {
29 | "tabIndent": "auto",
30 | "tabSize": 4
31 | },
32 | "projectname": "refresher-two-level"
33 | }
--------------------------------------------------------------------------------
/examples/segmented-half-screen/.eslintrc.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Eslint config file
3 | * Documentation: https://eslint.org/docs/user-guide/configuring/
4 | * Install the Eslint extension before using this feature.
5 | */
6 | module.exports = {
7 | env: {
8 | es6: true,
9 | browser: true,
10 | node: true,
11 | },
12 | ecmaFeatures: {
13 | modules: true,
14 | },
15 | parserOptions: {
16 | ecmaVersion: 2018,
17 | sourceType: 'module',
18 | },
19 | globals: {
20 | wx: true,
21 | App: true,
22 | Page: true,
23 | getCurrentPages: true,
24 | getApp: true,
25 | Component: true,
26 | requirePlugin: true,
27 | requireMiniProgram: true,
28 | },
29 | // extends: 'eslint:recommended',
30 | rules: {},
31 | }
32 |
--------------------------------------------------------------------------------
/examples/segmented-half-screen/app.js:
--------------------------------------------------------------------------------
1 | // app.js
2 | App({})
3 |
--------------------------------------------------------------------------------
/examples/segmented-half-screen/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "pages": [
3 | "pages/index/index"
4 | ],
5 | "window": {
6 | "backgroundTextStyle": "light",
7 | "navigationBarBackgroundColor": "#fff",
8 | "navigationBarTitleText": "Weixin",
9 | "navigationBarTextStyle": "black"
10 | },
11 | "style": "v2",
12 | "renderer": "skyline",
13 | "rendererOptions": {
14 | "skyline": {
15 | "defaultDisplayBlock": true,
16 | "disableABTest": true,
17 | "sdkVersionBegin": "3.0.0",
18 | "sdkVersionEnd": "15.255.255"
19 | }
20 | },
21 | "lazyCodeLoading": "requiredComponents",
22 | "componentFramework": "glass-easel",
23 | "sitemapLocation": "sitemap.json"
24 | }
--------------------------------------------------------------------------------
/examples/segmented-half-screen/app.wxss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wechat-miniprogram/awesome-skyline/25e2d93c2daf3f78d0908ff53ea305147d0c8978/examples/segmented-half-screen/app.wxss
--------------------------------------------------------------------------------
/examples/segmented-half-screen/pages/index/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "usingComponents": {},
3 | "disableScroll": true,
4 | "navigationStyle": "custom"
5 | }
--------------------------------------------------------------------------------
/examples/segmented-half-screen/pages/index/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
36 |
--------------------------------------------------------------------------------
/examples/segmented-half-screen/pages/index/index.wxss:
--------------------------------------------------------------------------------
1 | page {
2 | display: flex;
3 | flex-direction: column;
4 | width: 100vw;
5 | height: 100vh;
6 | color: #1A191E;
7 | }
8 | page, view {
9 | box-sizing: border-box;
10 | }
11 | pan-gesture-handler, vertical-drag-gesture-handler {
12 | display: flex;
13 | flex-direction: column;
14 | overflow: hidden;
15 | }
16 | .container {
17 | flex: 1;
18 | width: 100vw;
19 | overflow: hidden;
20 | }
21 | .container image {
22 | width: 100vw;
23 | }
24 |
25 | #myMap {
26 | width: 100vw;
27 | height: 100vh;
28 | }
29 |
30 | .open-comment {
31 | display: flex;
32 | flex-direction: column;
33 | flex-shrink: 0;
34 | width: 100%;
35 | background-color: white;
36 | }
37 | .open-comment-wording {
38 | height: 66px;
39 | display: flex;
40 | justify-content: center;
41 | align-items: center;
42 | }
43 | .safe-area-inset-bottom {
44 | height: env(safe-area-inset-bottom);
45 | }
46 |
47 | .comment-container {
48 | width: 100vw;
49 | height: 100vh;
50 | display: flex;
51 | flex-direction: column;
52 | position: absolute;
53 | top: 0;
54 | z-index: 999;
55 | background-color: white;
56 | border-top-left-radius: 20px;
57 | border-top-right-radius: 20px;
58 | box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.2);
59 | }
60 | .comment-header {
61 | width: 100%;
62 | font-size: 16px;
63 | text-align: center;
64 | padding: 15px 0;
65 | }
66 | .comment-handler {
67 | width: 50px;
68 | height: 3px;
69 | border-radius: 3px;
70 | background-color: #EEE;
71 | margin: 0 auto 10px;
72 | }
73 | .comment-list {
74 | flex: 1;
75 | overflow: hidden;
76 | }
77 | .comment-item {
78 | padding: 0 20px 20px;
79 | font-size: 13px;
80 | line-height: 1.4;
81 | }
82 | .main-comment, .sub-comment {
83 | display: flex;
84 | flex-direction: row;
85 | }
86 | .sub-comment {
87 | padding: 10px 22px 0;
88 | }
89 |
90 | .user-head-img {
91 | width: 33px;
92 | height: 33px;
93 | border-radius: 50%;
94 | margin-top: 5px;
95 | }
96 | .others {
97 | flex: 1;
98 | margin-left: 10px;
99 | }
100 | .user-name {
101 | white-space: nowrap;
102 | overflow: hidden;
103 | text-overflow: ellipsis;
104 | }
105 | .content {
106 | margin-top: 2px;
107 | }
108 |
--------------------------------------------------------------------------------
/examples/segmented-half-screen/project.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "appid": "wxe5f52902cf4de896",
3 | "compileType": "miniprogram",
4 | "libVersion": "latest",
5 | "packOptions": {
6 | "ignore": [],
7 | "include": []
8 | },
9 | "setting": {
10 | "coverView": true,
11 | "es6": true,
12 | "postcss": true,
13 | "minified": true,
14 | "enhance": true,
15 | "showShadowRootInWxmlPanel": true,
16 | "packNpmRelationList": [],
17 | "babelSetting": {
18 | "ignore": [],
19 | "disablePlugins": [],
20 | "outputPath": ""
21 | },
22 | "condition": false,
23 | "skylineRenderEnable": false,
24 | "compileWorklet": true
25 | },
26 | "condition": {},
27 | "editorSetting": {
28 | "tabIndent": "insertSpaces",
29 | "tabSize": 2
30 | }
31 | }
--------------------------------------------------------------------------------
/examples/segmented-half-screen/project.private.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html",
3 | "projectname": "segmented",
4 | "setting": {
5 | "compileHotReLoad": false,
6 | "skylineRenderEnable": true
7 | },
8 | "libVersion": "latest"
9 | }
--------------------------------------------------------------------------------
/examples/segmented-half-screen/sitemap.json:
--------------------------------------------------------------------------------
1 | {
2 | "desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html",
3 | "rules": [{
4 | "action": "allow",
5 | "page": "*"
6 | }]
7 | }
--------------------------------------------------------------------------------
/examples/tab-indicator/.eslintrc.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Eslint config file
3 | * Documentation: https://eslint.org/docs/user-guide/configuring/
4 | * Install the Eslint extension before using this feature.
5 | */
6 | module.exports = {
7 | env: {
8 | es6: true,
9 | browser: true,
10 | node: true,
11 | },
12 | ecmaFeatures: {
13 | modules: true,
14 | },
15 | parserOptions: {
16 | ecmaVersion: 2018,
17 | sourceType: 'module',
18 | },
19 | globals: {
20 | wx: true,
21 | App: true,
22 | Page: true,
23 | getCurrentPages: true,
24 | getApp: true,
25 | Component: true,
26 | requirePlugin: true,
27 | requireMiniProgram: true,
28 | },
29 | // extends: 'eslint:recommended',
30 | rules: {},
31 | }
32 |
--------------------------------------------------------------------------------
/examples/tab-indicator/app.js:
--------------------------------------------------------------------------------
1 | // app.js
2 | App({})
3 |
--------------------------------------------------------------------------------
/examples/tab-indicator/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "pages": [
3 | "pages/index/index"
4 | ],
5 | "window": {
6 | "backgroundTextStyle": "light",
7 | "navigationBarBackgroundColor": "#fff",
8 | "navigationBarTitleText": "Weixin",
9 | "navigationBarTextStyle": "black"
10 | },
11 | "style": "v2",
12 | "renderer": "skyline",
13 | "rendererOptions": {
14 | "skyline": {
15 | "defaultDisplayBlock": true,
16 | "disableABTest": true,
17 | "sdkVersionBegin": "3.0.0",
18 | "sdkVersionEnd": "15.255.255"
19 | }
20 | },
21 | "lazyCodeLoading": "requiredComponents",
22 | "componentFramework": "glass-easel",
23 | "sitemapLocation": "sitemap.json"
24 | }
--------------------------------------------------------------------------------
/examples/tab-indicator/app.wxss:
--------------------------------------------------------------------------------
1 | /**app.wxss**/
2 | .container {
3 | height: 100%;
4 | display: flex;
5 | flex-direction: column;
6 | align-items: center;
7 | justify-content: space-between;
8 | padding: 200rpx 0;
9 | box-sizing: border-box;
10 | }
11 |
--------------------------------------------------------------------------------
/examples/tab-indicator/components/navigation-bar/index.js:
--------------------------------------------------------------------------------
1 | Component({
2 | options: {
3 | multipleSlots: true // 在组件定义时的选项中启用多slot支持
4 | },
5 | /**
6 | * 组件的属性列表
7 | */
8 | properties: {
9 | extClass: {
10 | type: String,
11 | value: ''
12 | },
13 | title: {
14 | type: String,
15 | value: ''
16 | },
17 | background: {
18 | type: String,
19 | value: ''
20 | },
21 | color: {
22 | type: String,
23 | value: ''
24 | },
25 | back: {
26 | type: Boolean,
27 | value: true
28 | },
29 | loading: {
30 | type: Boolean,
31 | value: false
32 | },
33 | animated: {
34 | // 显示隐藏的时候opacity动画效果
35 | type: Boolean,
36 | value: true
37 | },
38 | show: {
39 | // 显示隐藏导航,隐藏的时候navigation-bar的高度占位还在
40 | type: Boolean,
41 | value: true,
42 | observer: '_showChange'
43 | },
44 | // back为true的时候,返回的页面深度
45 | delta: {
46 | type: Number,
47 | value: 1
48 | }
49 | },
50 | /**
51 | * 组件的初始数据
52 | */
53 | data: {
54 | displayStyle: ''
55 | },
56 | attached() {
57 | const rect = wx.getMenuButtonBoundingClientRect()
58 | wx.getSystemInfo({
59 | success: (res) => {
60 | this.setData({
61 | statusBarHeight: res.statusBarHeight,
62 | innerPaddingRight: `padding-right:${res.windowWidth - rect.left}px`,
63 | leftWidth: `width:${res.windowWidth - rect.left}px`,
64 | navBarHeight: rect.bottom + rect.top - res.statusBarHeight,
65 | })
66 | }
67 | })
68 | },
69 | /**
70 | * 组件的方法列表
71 | */
72 | methods: {
73 | _showChange(show) {
74 | const animated = this.data.animated
75 | let displayStyle = ''
76 | if (animated) {
77 | displayStyle = `opacity: ${show ? '1' : '0'};transition: opacity 0.5s;`
78 | } else {
79 | displayStyle = `display: ${show ? '' : 'none'}`
80 | }
81 | this.setData({
82 | displayStyle
83 | })
84 | },
85 | back() {
86 | const data = this.data
87 | if (data.delta) {
88 | wx.navigateBack({
89 | delta: data.delta
90 | })
91 | }
92 | this.triggerEvent('back', { delta: data.delta }, {})
93 | }
94 | }
95 | })
96 |
--------------------------------------------------------------------------------
/examples/tab-indicator/components/navigation-bar/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {},
4 | "componentFramework": "glass-easel",
5 | "addGlobalClass": true
6 | }
--------------------------------------------------------------------------------
/examples/tab-indicator/components/navigation-bar/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | {{title}}
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/examples/tab-indicator/components/navigation-bar/index.wxss:
--------------------------------------------------------------------------------
1 | .weui-navigation-bar {
2 | overflow: hidden;
3 | color: rgba(0, 0, 0, .9);
4 | width: 100vw;
5 | }
6 |
7 | .weui-navigation-bar__placeholder {
8 | background: #f7f7f7;
9 | position: relative;
10 | }
11 |
12 | .weui-navigation-bar__inner, .weui-navigation-bar__inner .weui-navigation-bar__left {
13 | display: flex;
14 | align-items: center;
15 | flex-direction: row;
16 | }
17 |
18 | .weui-navigation-bar__inner {
19 | position: relative;
20 | padding-right: 95px;
21 | width: 100vw;
22 | box-sizing: border-box;
23 | }
24 |
25 | .weui-navigation-bar__inner .weui-navigation-bar__left {
26 | position: relative;
27 | width: 95px;
28 | padding-left: 16px;
29 | box-sizing: border-box;
30 | }
31 |
32 | .weui-navigation-bar__btn_goback_wrapper {
33 | padding: 11px 18px 11px 16px;
34 | margin: -11px -18px -11px -16px;
35 | }
36 |
37 | .weui-navigation-bar__inner .weui-navigation-bar__left .weui-navigation-bar__btn_goback {
38 | font-size: 12px;
39 | width: 12px;
40 | height: 24px;
41 | background: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='24' viewBox='0 0 12 24'%3E %3Cpath fill-opacity='.9' fill-rule='evenodd' d='M10 19.438L8.955 20.5l-7.666-7.79a1.02 1.02 0 0 1 0-1.42L8.955 3.5 10 4.563 2.682 12 10 19.438z'/%3E%3C/svg%3E") no-repeat 50% 50%;
42 | background-size: cover;
43 | }
44 |
45 | .weui-navigation-bar__inner .weui-navigation-bar__center {
46 | font-size: 17px;
47 | text-align: center;
48 | position: relative;
49 | flex: 1;
50 | display: flex;
51 | flex-direction: column;
52 | align-items: center;
53 | justify-content: center;
54 | font-weight: bold;
55 | }
56 |
57 | @media(prefers-color-scheme: dark) {
58 | .weui-navigation-bar {
59 | color: hsla(0, 0%, 100%, .8);
60 | }
61 | .weui-navigation-bar__inner {
62 | background-color: #1f1f1f;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/examples/tab-indicator/pages/index/index.js:
--------------------------------------------------------------------------------
1 | const ScrollState = {
2 | scrollStart: 0,
3 | scrollUpdate: 1,
4 | scrollEnd: 2,
5 | }
6 |
7 | const tabs = [
8 | {
9 | title: '性能优化',
10 | title2: '小程序性能优化实践',
11 | img: 'http://mmbiz.qpic.cn/mmbiz_jpg/PxLPibq1ibyh0U4e0qLqNrULAUzW5UbWbicUN5GyJqd24GR0Ricg5q14VGGBWlicNca8x4xelvDrM1r0ibwAjAsR0bOA/0?wx_fmt=jpeg',
12 | desc: '小程序性能优化课程基于实际开发场景,由资深开发者分享小程序性能优化的各项能力及应用实践,提升小程序性能表现,满足用户体验。',
13 | },
14 | {
15 | title: '新能力解读',
16 | title2: '小程序开发新能力解读',
17 | img: 'http://mmbiz.qpic.cn/sz_mmbiz_png/GEWVeJPFkSH05EZMIBafqzpoZVSXtCE47V7icf0gru4KPUzMjIcIibJPUlXqbZib4VNmTecxef987XEWib2vhwuqbQ/0?wx_fmt=png',
18 | desc: '这个月小程序释放了什么新能力?又有哪些新规则?收藏课程,及时了解小程序开发动态,听官方为你解读新能力。',
19 | },
20 | {
21 | title: '基础开发',
22 | title2: '小程序基础开发之架构、框架、组件',
23 | img: 'http://mmbiz.qpic.cn/sz_mmbiz_jpg/GEWVeJPFkSEz7tgvlaTtv2MYO01RZr0yNgtbEZJzcbRl0deOWmSbX0UfRHPt78UCOxPIVYnhAiaJVib40SviaV1Vw/0?wx_fmt=jpeg',
24 | desc: '小程序基础开发之架构、框架、组件,更多课程正在制作中...',
25 | },
26 | ]
27 |
28 | Component({
29 | data: {
30 | selectedTab: 0,
31 | tabs,
32 | translateX: 0,
33 | },
34 |
35 | lifetimes: {
36 | created() {
37 | const shared = wx.worklet.shared
38 | const { windowWidth } = wx.getSystemInfoSync()
39 | const innerWindowWidth = windowWidth - 48 // 左右 padding 各 24
40 | this._tabWidth = shared(innerWindowWidth / 3) // 通过 boundingClientRect 算也行
41 | this._translateX = shared(0)
42 | this._lastTranslateX = shared(0)
43 | this._scaleX = shared(0.7)
44 | this._windowWidth = shared(windowWidth)
45 |
46 | },
47 | attached() {
48 | this.applyAnimatedStyle('.tab-border', () => {
49 | 'worklet'
50 | return {
51 | transform: `translateX(${this._translateX.value}px) scaleX(${this._scaleX.value})`,
52 | }
53 | })
54 | },
55 | },
56 |
57 | methods: {
58 | onTapTab(evt) {
59 | const { tab } = evt.currentTarget.dataset || {}
60 | this.setData({
61 | selectedTab: tab,
62 | })
63 | },
64 |
65 | onTabChanged(evt) {
66 | const index = evt.detail.current
67 | this.setData({
68 | selectedTab: index,
69 | })
70 | if (this.renderer !== 'skyline') {
71 | this.setData({
72 | translateX: this._tabWidth.value * index
73 | })
74 | }
75 | },
76 |
77 | // swiper 切换过程中每帧回调,声明为 worklet 函数使其跑在 UI 线程
78 | onTabTransition(evt) {
79 | 'worklet'
80 | // 这里 swiper item 是占满了整个屏幕宽度,算出拖动比例,换算成相对 tab width 的偏移
81 | const translateRatio = evt.detail.dx / this._windowWidth.value
82 | this._translateX.value = this._lastTranslateX.value + translateRatio * this._tabWidth.value
83 |
84 | // 控制 scale 值,拖到中间时 scale 处于最大值 1,两端递减
85 | const scaleRatio = (this._translateX.value / this._tabWidth.value) % 1
86 | const changedScale = scaleRatio <= 0.5 ? scaleRatio : (1 - scaleRatio) // 最大值 0.5
87 | this._scaleX.value = Math.abs(changedScale) * 0.6 + 0.7
88 |
89 | if (evt.detail.state === ScrollState.scrollEnd) {
90 | this._lastTranslateX.value = this._translateX.value
91 | }
92 | },
93 |
94 | onTabTransitionEnd(evt) {
95 | 'worklet'
96 | this.onTabTransition(evt)
97 |
98 | // end
99 | this._lastTranslateX.value = this._translateX.value
100 | }
101 | },
102 | })
103 |
--------------------------------------------------------------------------------
/examples/tab-indicator/pages/index/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "usingComponents": {
3 | "navigation-bar": "../../components/navigation-bar"
4 | },
5 | "disableScroll": true,
6 | "navigationStyle": "custom"
7 | }
8 |
--------------------------------------------------------------------------------
/examples/tab-indicator/pages/index/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {{ item.title }}
6 |
7 |
8 |
9 |
10 |
11 |
12 | {{item.title2}}
13 | {{item.desc}}
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/examples/tab-indicator/pages/index/index.wxss:
--------------------------------------------------------------------------------
1 | view, swiper-item {
2 | box-sizing: border-box;
3 | }
4 |
5 | .tab-container {
6 | display: flex;
7 | flex-direction: column;
8 | width: 100vw;
9 | height: 100vh;
10 | }
11 |
12 | .tab-list {
13 | display: flex;
14 | flex-direction: row;
15 | margin: 5px 24px 0;
16 | position: relative;
17 | }
18 |
19 | .tab-item {
20 | display: flex;
21 | flex-direction: row;
22 | align-items: center;
23 | justify-content: center;
24 | position: relative;
25 | flex: 1;
26 | height: 50px;
27 | border-bottom: 0.5px solid white;
28 | }
29 |
30 | .tab-item.active {
31 | color: #07c160;
32 | }
33 |
34 | .tab-border {
35 | position: absolute;
36 | left: 0;
37 | bottom: 0;
38 | height: 3px;
39 | background-color: #07c160;
40 | width: 33.33%;
41 | transform: translateX(0) scaleX(0.7);
42 | z-index: 1;
43 | }
44 |
45 | .scroll-list {
46 | flex: 1;
47 | width: 100%;
48 | overflow: hidden;
49 | }
50 |
51 | swiper-item {
52 | padding: 30px;
53 | }
54 |
55 | .item-image {
56 | display: flex;
57 | flex-direction: row;
58 | justify-content: center;
59 | align-items: center;
60 | width: 100%;
61 | }
62 |
63 | .item-title {
64 | padding: 20px 0 8px 0;
65 | font-size: 18px;
66 | }
67 |
--------------------------------------------------------------------------------
/examples/tab-indicator/project.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "appid": "wxe5f52902cf4de896",
3 | "compileType": "miniprogram",
4 | "libVersion": "latest",
5 | "packOptions": {
6 | "ignore": [],
7 | "include": []
8 | },
9 | "setting": {
10 | "coverView": true,
11 | "es6": true,
12 | "postcss": true,
13 | "minified": true,
14 | "enhance": true,
15 | "showShadowRootInWxmlPanel": true,
16 | "packNpmRelationList": [],
17 | "babelSetting": {
18 | "ignore": [],
19 | "disablePlugins": [],
20 | "outputPath": ""
21 | },
22 | "condition": false,
23 | "skylineRenderEnable": true,
24 | "compileWorklet": true
25 | },
26 | "condition": {},
27 | "editorSetting": {
28 | "tabIndent": "insertSpaces",
29 | "tabSize": 2
30 | }
31 | }
--------------------------------------------------------------------------------
/examples/tab-indicator/project.private.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html",
3 | "projectname": "tab-indicator",
4 | "setting": {
5 | "compileHotReLoad": false
6 | },
7 | "libVersion": "latest"
8 | }
--------------------------------------------------------------------------------
/examples/tab-indicator/sitemap.json:
--------------------------------------------------------------------------------
1 | {
2 | "desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html",
3 | "rules": [{
4 | "action": "allow",
5 | "page": "*"
6 | }]
7 | }
--------------------------------------------------------------------------------