main 4789c045ccb9 cached
218 files
335.4 KB
124.7k tokens
252 symbols
1 requests
Download .txt
Showing preview only (408K chars total). Download the full file or copy to clipboard to get everything.
Repository: wechat-miniprogram/awesome-skyline
Branch: main
Commit: 4789c045ccb9
Files: 218
Total size: 335.4 KB

Directory structure:
gitextract_s27a10mg/

├── .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
    │   ├── 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
    │   ├── 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
    │   ├── 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/
    │   │   ├── index.json
    │   │   ├── index.less
    │   │   ├── index.ts
    │   │   └── index.wxml
    │   ├── goods.less
    │   ├── goods.wxml
    │   ├── 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

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
.DS_Store


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2023 wechat-miniprogram

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
# awesome-skyline

Skyline 是微信小程序推出的新渲染引擎,用于替代 WebView 渲染,其能够带来更好的渲染性能,并且添加了诸多增强特性,让小程序拥有更接近原生的交互体验。更多细节可查看[文档](https://developers.weixin.qq.com/miniprogram/dev/framework/runtime/skyline/introduction.html)。

## 示例集

- [通讯录](./examples/address-book)
- [相册](./examples/album)
- [卡片转场](./examples/card_transition)
- [半屏弹窗](./examples/half-screen)
- [分段式半屏](./examples/segmented-half-screen)
- [Tab 指示条](./examples/tab-indicator)
- [搜索栏吸附](./examples/product-list)
- [沉浸式商品浏览](./examples/expanded-scroll-view)
- [分类列表联动](./examples/associated-scroll-view)


================================================
FILE: examples/address-book/.eslintrc.js
================================================
/*
 * Eslint config file
 * Documentation: https://eslint.org/docs/user-guide/configuring/
 * Install the Eslint extension before using this feature.
 */
module.exports = {
  env: {
    es6: true,
    browser: true,
    node: true,
  },
  ecmaFeatures: {
    modules: true,
  },
  parserOptions: {
    ecmaVersion: 2018,
    sourceType: 'module',
  },
  globals: {
    wx: true,
    App: true,
    Page: true,
    getCurrentPages: true,
    getApp: true,
    Component: true,
    requirePlugin: true,
    requireMiniProgram: true,
  },
  // extends: 'eslint:recommended',
  rules: {},
}


================================================
FILE: examples/address-book/app.js
================================================
// app.js
App({})


================================================
FILE: examples/address-book/app.json
================================================
{
  "pages": [
    "pages/index/index"
  ],
  "window": {
    "backgroundTextStyle": "light",
    "navigationBarBackgroundColor": "#fff",
    "navigationBarTitleText": "Weixin",
    "navigationBarTextStyle": "black"
  },
  "style": "v2",
  "renderer": "skyline",
  "rendererOptions": {
    "skyline": {
      "defaultDisplayBlock": true,
      "disableABTest": true,
      "sdkVersionBegin": "3.0.0",
      "sdkVersionEnd": "15.255.255"
    }
  },
  "lazyCodeLoading": "requiredComponents",
  "componentFramework": "glass-easel",
  "sitemapLocation": "sitemap.json"
}

================================================
FILE: examples/address-book/app.wxss
================================================


================================================
FILE: examples/address-book/components/address-book/index.js
================================================
const throttle = function throttle(func, wait, options) {
  let context
  let args
  let result = void 0
  let timeout
  let previous = 0
  if (!options) options = {}
  const later = function later() {
    previous = options.leading === false ? 0 : Date.now()
    timeout = null
    result = func.apply(context, args)
    if (!timeout) context = args = null
  }
  return function () {
    const now = Date.now()
    if (!previous && options.leading === false) previous = now
    const remaining = wait - (now - previous)
    context = this
    args = arguments
    if (remaining <= 0 || remaining > wait) {
      clearTimeout(timeout)
      timeout = null
      previous = now
      result = func.apply(context, args)
      if (!timeout) context = args = null
    } else if (!timeout && options.trailing !== false) {
      timeout = setTimeout(later, remaining)
    }
    return result
  }
}

Component({
  behaviors: [],
  options: {
    addGlobalClass: false,
    virtualHost: true,
    pureDataPattern: /^_/,
  },
  properties: {
    list: {
      type: Array,
      value: [],
      observer(newVal) {
        if (newVal.length === 0) return
        const alphabet = this.data.list.map((item, index) => {
          this.data._tops[index] = 2e10
          return item.alpha
        })
        this._sharedTops.value = this.data._tops
        this.setData({
          alphabet,
          current: alphabet[0]
        }, () => {
          this.computedSize()
        })
      },
    },
  },

  data: {
    current: 'A',
    intoView: '',
    touching: false,
    alphabet: [],
    _vibrated: true,
    _tops: [],
    _anchorItemH: 0,
    _anchorItemW: 0,
    _anchorTop: 0,
  },

  observers: {
    'current': function (current) {
      this._sharedCurrentIdx.value = this.data.alphabet.indexOf(current)
    },
  },

  lifetimes: {
    created() {
      this._handlePan = throttle(this._handlePan, 100, {})
      this._sharedTops = wx.worklet.shared([])
      this._sharedScrollTop = wx.worklet.shared(0)
      this._sharedHeight = wx.worklet.shared(0)
      this._sharedCurrentIdx = wx.worklet.shared(0)
    },
    attached() {
      // scroll-view 高度
      this.createSelectorQuery().select('.scroll-view').boundingClientRect(res => {
        this._sharedHeight.value = res.height
      }).exec()

      // 右侧目录计算
      const query = this.createSelectorQuery()
      query.select('.anchor-list').boundingClientRect(rect => {
        this.data._anchorItemH = rect.height / this.data.alphabet.length
        this.data._anchorItemW = rect.width
        this.data._anchorTop = rect.top
      }).exec()
    },
  },
  methods: {
    handlePan(e) {
      this._handlePan(e)
    },
    _handlePan(e) {
      const data = this.data
      const clientY = e.changedTouches[0].clientY
      const index = Math.floor((clientY - data._anchorTop) / data._anchorItemH)
      const current = data.alphabet[index]
      if (current !== this.data.current) {
        wx.vibrateShort({
          type: 'light'
        })
        this.setData({
          current,
          intoView: current,
          touching: true
        })
      }
    },
    cancelPan() {
      setTimeout(() => {
        this.setData({ touching: false })
      }, 150)
    },
    computedSize() {
      this.data.alphabet.forEach((element, index) => {
        // NOTE: 在 Skyline 下如果用了 list-view / grid-view 会有按需渲染特性,取其子节点的 clientRect
        // 时若不在屏会取不到,而这里是取 sticky-header 的,会立即渲染也就能立即返回,但 top 值是预估的。
        // 因为 list-view 的高度是预估的(第一个子节点的高度 * 数量),由于其子节点是等高,故预估是基本准确的
        this.createSelectorQuery().select(`#${element}`).boundingClientRect(res => {
          this.data._tops[index] = res.top
          this._sharedTops.value = this.data._tops
        }).exec()
      })
    },
    handleScroll(e) {
      'worklet'
      const scrollTop = e.detail.scrollTop
      // 用于计算每个 header 的 offsetTop
      this._sharedScrollTop.value = scrollTop

      // 下面判断当前选中态,按需更新
      const tops = this._sharedTops.value
      for (let i = tops.length - 1; i >= 0; i--) {
        // header 超过屏幕一半就改为选中态
        if (scrollTop + this._sharedHeight.value / 2 > tops[i]) {
          if (i !== this._sharedCurrentIdx.value) {
            // worklet 函数运行在 UI 线程,setData 调用要抛回 JS 线程执行
            wx.worklet.runOnJS(this.updateCurrent.bind(this))(i)
          }
          break
        }
      }
    },
    updateCurrent(idx) {
      if (this.data.touching) return
      this.setData({ current: this.data.alphabet[idx] })
    },
  }
})


================================================
FILE: examples/address-book/components/address-book/index.json
================================================
{
  "component": true,
  "usingComponents": {},
  "addGlobalClass": false,
  "componentFramework": "glass-easel"
}

================================================
FILE: examples/address-book/components/address-book/index.wxml
================================================
<!-- 主列表 -->
<scroll-view
  type="custom"
  scroll-y
  show-scrollbar="{{false}}"
  scroll-into-view="{{intoView}}"
  class="scroll-view"
  bind:scroll="handleScroll"
>
  <view><slot></slot></view>
  <sticky-section wx:for="{{list}}" wx:key="alpha">
    <sticky-header>
      <view class="city-group__title tips-color" id="{{item.alpha}}">{{item.alpha}}</view>
    </sticky-header>
    <list-view>
      <block wx:for="{{item.subItems}}" wx:for-item="subItem" wx:key="name">
        <view class="city-group__item thin-border-bottom" hover-class="bg-highlight">{{subItem.name}}</view>
      </block>
    </list-view>
  </sticky-section>
</scroll-view>
<!-- 右侧目录 -->
<root-portal>
  <!-- 这里也可以用 pan-gesture-handler -->
  <view class="wx-flex right-directory" catch:touchstart='handlePan' catch:touchmove='handlePan' catch:touchend='cancelPan'>
    <view class="anchor-bar">
      <view class="anchor-list">
        <block wx:for="{{alphabet}}" wx:key="*this" wx:for-item="alpha">
          <view data-alpha="{{alpha}}">
            <view class="anchor-item {{current == alpha ? ( touching ? 'selected tapped' : 'selected' ): ''}}">
              <view class="anchor-item__inner">{{alpha}}</view>
              <view class="anchor-item__pop">
                {{alpha}}
                <view class="anchor-item__pop_after"></view>
              </view>
            </view>
          </view>
        </block>
      </view>
    </view>
  </view>
</root-portal>


================================================
FILE: examples/address-book/components/address-book/index.wxss
================================================
.wx-flex {
  display: flex;
  align-items: center
}

.scroll-view {
  height: 100%;
}

.thin-border-bottom {
  position: relative
}

.thin-border-top {
  position: relative
}

.square-tag {
  color: #9a9a9a;
  text-align: center;
  height: 30px;
  line-height: 30px;
  box-sizing: border-box;
  border-radius: 2px;
  background-color: #f7f7f7;
  font-size: 12px;
  position: relative
}

.square-tag.selected {
  background: rgba(26, 173, 25, 0.1);
  color: #1AAD19
}

.select-city__hd {
  padding: 0 15px;
  position: fixed;
  height: 50px;
  background-color: #fff;
  left: 0;
  right: 0;
  z-index: 990
}

.current-city__name {
  display: inline-block;
  margin-right: 10px;
  margin-left: 11px
}

.city-group_part .city-group__title {
  padding-bottom: 12px
}

.city-group__title {
  padding: 12px 12px 11px
}

.square-tag {
  width: 100px;
  display: inline-block;
  margin-right: 12px;
  margin-bottom: 12px;
  height: 40px;
  line-height: 40px;
  font-size: 15px;
  color: #000;
  background-color: rgba(0, 0, 0, 0.02);
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis
}

.city-group__item {
  padding: 15px 12px;
  font-size: 15px
}

.city-group_all {
  padding-bottom: 50px
}

.fixed__top {
  position: fixed;
  top: 0
}

.anchor-bar__wrp {
  position: fixed;
  top: 0;
  bottom: 0;
  right: 0;
  width: 30px;
  z-index: 999
}

.anchor-item {
  font-size: 0;
  text-align: center;
  position: relative
}

.anchor-item__inner {
  line-height: 10px;
  height: 14px;
  width: 14px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 10px;
  margin: 1px 0;
  font-weight: 500
}

.tapped .anchor-item__pop {
  display: flex;
}

.anchor-item__pop {
  position: absolute;
  font-size: 50px;
  width: 55px;
  height: 55px;
  line-height: 45px;
  color: #fff;
  background-color: #C9C9C9;
  border-radius: 50%;
  border: 5px solid transparent;
  right: 40px;
  top: 50%;
  transform: translateY(-50%);
  display: none;
  box-sizing: border-box;
  align-items: center;
  justify-content: center;
}

.anchor-item__pop_after {
  position: absolute;
  width: 0;
  height: 0;
  left: 42px;
  border: 20px solid;
  border-color: transparent transparent transparent #C9C9C9;
  top: 50%;
  transform: translateY(-50%)
}

.anchor-item.selected .anchor-item__inner {
  color: #fff;
  background-color: #1aad19
}

.right-directory {
  position: absolute;
  top: 0;
  right: 0;
  z-index: 1;
  width: 30px;
  height: 100vh;
  justify-content: center;
  flex-direction: column;
}
.anchor-bar {
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 30px;
}

.tips-color {
  color: #5d5d5d;
  background-color: #EAEAEA;
  font-weight: bold;
}

sticky-header {
  position: sticky;
  top: 0;
  z-index: 1;
  display: block;
}


================================================
FILE: examples/address-book/components/navigation-bar/index.js
================================================
Component({
  options: {
    multipleSlots: true // 在组件定义时的选项中启用多slot支持
  },
  /**
   * 组件的属性列表
   */
  properties: {
    extClass: {
      type: String,
      value: ''
    },
    title: {
      type: String,
      value: ''
    },
    background: {
      type: String,
      value: ''
    },
    color: {
      type: String,
      value: ''
    },
    back: {
      type: Boolean,
      value: true
    },
    loading: {
      type: Boolean,
      value: false
    },
    animated: {
      // 显示隐藏的时候opacity动画效果
      type: Boolean,
      value: true
    },
    show: {
      // 显示隐藏导航,隐藏的时候navigation-bar的高度占位还在
      type: Boolean,
      value: true,
      observer: '_showChange'
    },
    // back为true的时候,返回的页面深度
    delta: {
      type: Number,
      value: 1
    }
  },
  /**
   * 组件的初始数据
   */
  data: {
    displayStyle: ''
  },
  attached() {
    const rect = wx.getMenuButtonBoundingClientRect()
    wx.getSystemInfo({
      success: (res) => {
        this.setData({
          statusBarHeight: res.statusBarHeight,
          innerPaddingRight: `padding-right:${res.windowWidth - rect.left}px`,
          leftWidth: `width:${res.windowWidth - rect.left}px`,
          navBarHeight: rect.bottom + rect.top - res.statusBarHeight,
        })
      }
    })
  },
  /**
   * 组件的方法列表
   */
  methods: {
    _showChange(show) {
      const animated = this.data.animated
      let displayStyle = ''
      if (animated) {
        displayStyle = `opacity: ${show ? '1' : '0'};transition: opacity 0.5s;`
      } else {
        displayStyle = `display: ${show ? '' : 'none'}`
      }
      this.setData({
        displayStyle
      })
    },
    back() {
      const data = this.data
      if (data.delta) {
        wx.navigateBack({
          delta: data.delta
        })
      }
      this.triggerEvent('back', { delta: data.delta }, {})
    }
  }
})


================================================
FILE: examples/address-book/components/navigation-bar/index.json
================================================
{
  "component": true,
  "usingComponents": {},
  "addGlobalClass": true,
  "componentFramework": "glass-easel"
}

================================================
FILE: examples/address-book/components/navigation-bar/index.wxml
================================================
<view class="weui-navigation-bar {{extClass}}">
  <view class="weui-navigation-bar__inner" style="padding-top: {{statusBarHeight}}px; height: {{navBarHeight}}px; color: {{color}}; background: {{background}}; {{displayStyle}}; {{innerPaddingRight}};">
    <view class='weui-navigation-bar__left' style="{{leftWidth}}">
      <block wx:if="{{back}}">
        <view class="navigation-bar__buttons" bindtap="back">
          <view class="navigation-bar__button navigation-bar__btn_goback" hover-class="active"></view>
        </view>
      </block>
      <block wx:else>
        <slot name="left"></slot>
      </block>
    </view>

    <view class='weui-navigation-bar__center'>
      <view wx:if="{{loading}}" class="weui-navigation-bar__loading" aria-role="alert">
        <view class="weui-loading" style="width:{{size.width}}rpx;height:{{size.height}}rpx;" aria-role="img" aria-label="加载中"></view>
      </view>
      <block wx:if="{{title}}">
        <text>{{title}}</text>
      </block>
      <block wx:else>
        <slot name="center"></slot>
      </block>
    </view>

    <view class='weui-navigation-bar__right'>
      <slot name="right"></slot>
    </view>
  </view>
</view>


================================================
FILE: examples/address-book/components/navigation-bar/index.wxss
================================================
.weui-navigation-bar {
  overflow: hidden;
  color: rgba(0, 0, 0, .9);
  width: 100vw;
}

.weui-navigation-bar__placeholder {
  background: #f7f7f7;
  position: relative;
}

.weui-navigation-bar__inner, .weui-navigation-bar__inner .weui-navigation-bar__left {
  display: flex;
  align-items: center;
  flex-direction: row;
}

.weui-navigation-bar__inner {
  position: relative;
  padding-right: 95px;
  width: 100vw;
  box-sizing: border-box;
}

.weui-navigation-bar__inner .weui-navigation-bar__left {
  position: relative;
  width: 95px;
  padding-left: 16px;
  box-sizing: border-box;
}

.weui-navigation-bar__btn_goback_wrapper {
  padding: 11px 18px 11px 16px;
  margin: -11px -18px -11px -16px;
}

.weui-navigation-bar__inner .weui-navigation-bar__left .navigation-bar__btn_goback {
  font-size: 12px;
  width: 12px;
  height: 24px;
  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%;
  background-size: cover;
}

.weui-navigation-bar__inner .weui-navigation-bar__center {
  font-size: 17px;
  text-align: center;
  position: relative;
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  font-weight: bold;
}

@media(prefers-color-scheme: dark) {
  .weui-navigation-bar {
    color: hsla(0, 0%, 100%, .8);
  }
  .weui-navigation-bar__inner {
    background-color: #1f1f1f;
  }
}


================================================
FILE: examples/address-book/pages/index/data.js
================================================
export const cityData = [{ "fullname": "东城区", "id": "110101", "location": { "lat": 39.92855, "lng": 116.41637 }, "name": "东城", "pinyin": ["dong", "cheng"] }, { "fullname": "西城区", "id": "110102", "location": { "lat": 39.91231, "lng": 116.36611 }, "name": "西城", "pinyin": ["xi", "cheng"] }, { "fullname": "朝阳区", "id": "110105", "location": { "lat": 39.9219, "lng": 116.44355 }, "name": "朝阳", "pinyin": ["chao", "yang"] }, { "fullname": "丰台区", "id": "110106", "location": { "lat": 39.85856, "lng": 116.28616 }, "name": "丰台", "pinyin": ["feng", "tai"] }, { "fullname": "石景山区", "id": "110107", "location": { "lat": 39.90569, "lng": 116.22299 }, "name": "石景山", "pinyin": ["shi", "jing", "shan"] }, { "fullname": "海淀区", "id": "110108", "location": { "lat": 39.95933, "lng": 116.29845 }, "name": "海淀", "pinyin": ["hai", "dian"] }, { "fullname": "门头沟区", "id": "110109", "location": { "lat": 39.94048, "lng": 116.10146 }, "name": "门头沟", "pinyin": ["men", "tou", "gou"] }, { "fullname": "房山区", "id": "110111", "location": { "lat": 39.74788, "lng": 116.14294 }, "name": "房山", "pinyin": ["fang", "shan"] }, { "fullname": "通州区", "id": "110112", "location": { "lat": 39.90998, "lng": 116.65714 }, "name": "通州", "pinyin": ["tong", "zhou"] }, { "fullname": "顺义区", "id": "110113", "location": { "lat": 40.13012, "lng": 116.65477 }, "name": "顺义", "pinyin": ["shun", "yi"] }, { "fullname": "昌平区", "id": "110114", "location": { "lat": 40.22077, "lng": 116.23128 }, "name": "昌平", "pinyin": ["chang", "ping"] }, { "fullname": "大兴区", "id": "110115", "location": { "lat": 39.72684, "lng": 116.34159 }, "name": "大兴", "pinyin": ["da", "xing"] }, { "fullname": "怀柔区", "id": "110116", "location": { "lat": 40.316, "lng": 116.63177 }, "name": "怀柔", "pinyin": ["huai", "rou"] }, { "fullname": "平谷区", "id": "110117", "location": { "lat": 40.14062, "lng": 117.12141 }, "name": "平谷", "pinyin": ["ping", "gu"] }, { "fullname": "密云区", "id": "110118", "location": { "lat": 40.37625, "lng": 116.84317 }, "name": "密云", "pinyin": ["mi", "yun"] }, { "fullname": "延庆区", "id": "110119", "location": { "lat": 40.45678, "lng": 115.97503 }, "name": "延庆", "pinyin": ["yan", "qing"] }, { "fullname": "和平区", "id": "120101", "location": { "lat": 39.11712, "lng": 117.2147 }, "name": "和平", "pinyin": ["he", "ping"] }, { "fullname": "河东区", "id": "120102", "location": { "lat": 39.12827, "lng": 117.25228 }, "name": "河东", "pinyin": ["he", "dong"] }, { "fullname": "河西区", "id": "120103", "location": { "lat": 39.10954, "lng": 117.22336 }, "name": "河西", "pinyin": ["he", "xi"] }, { "fullname": "南开区", "id": "120104", "location": { "lat": 39.13815, "lng": 117.15011 }, "name": "南开", "pinyin": ["nan", "kai"] }, { "fullname": "河北区", "id": "120105", "location": { "lat": 39.14784, "lng": 117.19674 }, "name": "河北", "pinyin": ["he", "bei"] }, { "fullname": "红桥区", "id": "120106", "location": { "lat": 39.16734, "lng": 117.15161 }, "name": "红桥", "pinyin": ["hong", "qiao"] }, { "fullname": "东丽区", "id": "120110", "location": { "lat": 39.08652, "lng": 117.31428 }, "name": "东丽", "pinyin": ["dong", "li"] }, { "fullname": "西青区", "id": "120111", "location": { "lat": 39.14111, "lng": 117.00739 }, "name": "西青", "pinyin": ["xi", "qing"] }, { "fullname": "津南区", "id": "120112", "location": { "lat": 38.9375, "lng": 117.3571 }, "name": "津南", "pinyin": ["jin", "nan"] }, { "fullname": "北辰区", "id": "120113", "location": { "lat": 39.22393, "lng": 117.13544 }, "name": "北辰", "pinyin": ["bei", "chen"] }, { "fullname": "武清区", "id": "120114", "location": { "lat": 39.38408, "lng": 117.0443 }, "name": "武清", "pinyin": ["wu", "qing"] }, { "fullname": "宝坻区", "id": "120115", "location": { "lat": 39.71755, "lng": 117.30983 }, "name": "宝坻", "pinyin": ["bao", "di"] }, { "fullname": "滨海新区", "id": "120116", "location": { "lat": 39.0032, "lng": 117.71071 }, "name": "滨海", "pinyin": ["bin", "hai"] }, { "fullname": "宁河区", "id": "120117", "location": { "lat": 39.33091, "lng": 117.82478 }, "name": "宁河", "pinyin": ["ning", "he"] }, { "fullname": "静海区", "id": "120118", "location": { "lat": 38.94737, "lng": 116.97428 }, "name": "静海", "pinyin": ["jing", "hai"] }, { "fullname": "蓟州区", "id": "120119", "location": { "lat": 40.04577, "lng": 117.40829 }, "name": "蓟州", "pinyin": ["ji", "zhou"] }, { "cidx": [0, 21], "fullname": "石家庄市", "id": "130100", "location": { "lat": 38.04276, "lng": 114.5143 }, "name": "石家庄", "pinyin": ["shi", "jia", "zhuang"] }, { "cidx": [22, 36], "fullname": "唐山市", "id": "130200", "location": { "lat": 39.63048, "lng": 118.18058 }, "name": "唐山", "pinyin": ["tang", "shan"] }, { "cidx": [37, 43], "fullname": "秦皇岛市", "id": "130300", "location": { "lat": 39.93545, "lng": 119.59964 }, "name": "秦皇岛", "pinyin": ["qin", "huang", "dao"] }, { "cidx": [44, 61], "fullname": "邯郸市", "id": "130400", "location": { "lat": 36.62556, "lng": 114.53918 }, "name": "邯郸", "pinyin": ["han", "dan"] }, { "cidx": [62, 80], "fullname": "邢台市", "id": "130500", "location": { "lat": 37.07055, "lng": 114.50443 }, "name": "邢台", "pinyin": ["xing", "tai"] }, { "cidx": [81, 104], "fullname": "保定市", "id": "130600", "location": { "lat": 38.87396, "lng": 115.46459 }, "name": "保定", "pinyin": ["bao", "ding"] }, { "cidx": [105, 120], "fullname": "张家口市", "id": "130700", "location": { "lat": 40.82444, "lng": 114.88755 }, "name": "张家口", "pinyin": ["zhang", "jia", "kou"] }, { "cidx": [121, 131], "fullname": "承德市", "id": "130800", "location": { "lat": 40.9515, "lng": 117.9634 }, "name": "承德", "pinyin": ["cheng", "de"] }, { "cidx": [132, 147], "fullname": "沧州市", "id": "130900", "location": { "lat": 38.30441, "lng": 116.83869 }, "name": "沧州", "pinyin": ["cang", "zhou"] }, { "cidx": [148, 157], "fullname": "廊坊市", "id": "131000", "location": { "lat": 39.53775, "lng": 116.68376 }, "name": "廊坊", "pinyin": ["lang", "fang"] }, { "cidx": [158, 168], "fullname": "衡水市", "id": "131100", "location": { "lat": 37.73886, "lng": 115.67054 }, "name": "衡水", "pinyin": ["heng", "shui"] }, { "cidx": [169, 178], "fullname": "太原市", "id": "140100", "location": { "lat": 37.87059, "lng": 112.55067 }, "name": "太原", "pinyin": ["tai", "yuan"] }, { "cidx": [179, 188], "fullname": "大同市", "id": "140200", "location": { "lat": 40.07637, "lng": 113.30001 }, "name": "大同", "pinyin": ["da", "tong"] }, { "cidx": [189, 193], "fullname": "阳泉市", "id": "140300", "location": { "lat": 37.85668, "lng": 113.58047 }, "name": "阳泉", "pinyin": ["yang", "quan"] }, { "cidx": [194, 205], "fullname": "长治市", "id": "140400", "location": { "lat": 36.19581, "lng": 113.11649 }, "name": "长治", "pinyin": ["chang", "zhi"] }, { "cidx": [206, 211], "fullname": "晋城市", "id": "140500", "location": { "lat": 35.49039, "lng": 112.85113 }, "name": "晋城", "pinyin": ["jin", "cheng"] }, { "cidx": [212, 217], "fullname": "朔州市", "id": "140600", "location": { "lat": 39.33155, "lng": 112.43286 }, "name": "朔州", "pinyin": ["shuo", "zhou"] }, { "cidx": [218, 228], "fullname": "晋中市", "id": "140700", "location": { "lat": 37.68702, "lng": 112.75278 }, "name": "晋中", "pinyin": ["jin", "zhong"] }, { "cidx": [229, 241], "fullname": "运城市", "id": "140800", "location": { "lat": 35.02628, "lng": 111.00699 }, "name": "运城", "pinyin": ["yun", "cheng"] }, { "cidx": [242, 255], "fullname": "忻州市", "id": "140900", "location": { "lat": 38.4167, "lng": 112.73418 }, "name": "忻州", "pinyin": ["xin", "zhou"] }, { "cidx": [256, 272], "fullname": "临汾市", "id": "141000", "location": { "lat": 36.08822, "lng": 111.51962 }, "name": "临汾", "pinyin": ["lin", "fen"] }, { "cidx": [273, 285], "fullname": "吕梁市", "id": "141100", "location": { "lat": 37.51934, "lng": 111.14165 }, "name": "吕梁", "pinyin": ["lv", "liang"] }, { "cidx": [286, 294], "fullname": "呼和浩特市", "id": "150100", "location": { "lat": 40.84149, "lng": 111.75199 }, "name": "呼和浩特", "pinyin": ["hu", "he", "hao", "te"] }, { "cidx": [295, 303], "fullname": "包头市", "id": "150200", "location": { "lat": 40.65781, "lng": 109.84021 }, "name": "包头", "pinyin": ["bao", "tou"] }, { "cidx": [304, 306], "fullname": "乌海市", "id": "150300", "location": { "lat": 39.65384, "lng": 106.79546 }, "name": "乌海", "pinyin": ["wu", "hai"] }, { "cidx": [307, 318], "fullname": "赤峰市", "id": "150400", "location": { "lat": 42.2586, "lng": 118.88894 }, "name": "赤峰", "pinyin": ["chi", "feng"] }, { "cidx": [319, 326], "fullname": "通辽市", "id": "150500", "location": { "lat": 43.65247, "lng": 122.24469 }, "name": "通辽", "pinyin": ["tong", "liao"] }, { "cidx": [327, 335], "fullname": "鄂尔多斯市", "id": "150600", "location": { "lat": 39.60845, "lng": 109.78087 }, "name": "鄂尔多斯", "pinyin": ["e", "er", "duo", "si"] }, { "cidx": [336, 349], "fullname": "呼伦贝尔市", "id": "150700", "location": { "lat": 49.21163, "lng": 119.76584 }, "name": "呼伦贝尔", "pinyin": ["hu", "lun", "bei", "er"] }, { "cidx": [350, 356], "fullname": "巴彦淖尔市", "id": "150800", "location": { "lat": 40.74317, "lng": 107.38773 }, "name": "巴彦淖尔", "pinyin": ["ba", "yan", "nao", "er"] }, { "cidx": [357, 367], "fullname": "乌兰察布市", "id": "150900", "location": { "lat": 40.99391, "lng": 113.13376 }, "name": "乌兰察布", "pinyin": ["wu", "lan", "cha", "bu"] }, { "cidx": [368, 373], "fullname": "兴安盟", "id": "152200", "location": { "lat": 46.08208, "lng": 122.03818 }, "name": "兴安", "pinyin": ["xing", "an"] }, { "cidx": [374, 385], "fullname": "锡林郭勒盟", "id": "152500", "location": { "lat": 43.9332, "lng": 116.04775 }, "name": "锡林郭勒", "pinyin": ["xi", "lin", "guo", "le"] }, { "cidx": [386, 388], "fullname": "阿拉善盟", "id": "152900", "location": { "lat": 38.85153, "lng": 105.72898 }, "name": "阿拉善", "pinyin": ["a", "la", "shan"] }, { "cidx": [389, 401], "fullname": "沈阳市", "id": "210100", "location": { "lat": 41.67718, "lng": 123.4631 }, "name": "沈阳", "pinyin": ["shen", "yang"] }, { "cidx": [402, 411], "fullname": "大连市", "id": "210200", "location": { "lat": 38.91369, "lng": 121.61476 }, "name": "大连", "pinyin": ["da", "lian"] }, { "cidx": [412, 418], "fullname": "鞍山市", "id": "210300", "location": { "lat": 41.10777, "lng": 122.9946 }, "name": "鞍山", "pinyin": ["an", "shan"] }, { "cidx": [419, 425], "fullname": "抚顺市", "id": "210400", "location": { "lat": 41.87971, "lng": 123.95722 }, "name": "抚顺", "pinyin": ["fu", "shun"] }, { "cidx": [426, 431], "fullname": "本溪市", "id": "210500", "location": { "lat": 41.29413, "lng": 123.76686 }, "name": "本溪", "pinyin": ["ben", "xi"] }, { "cidx": [432, 437], "fullname": "丹东市", "id": "210600", "location": { "lat": 39.9998, "lng": 124.35601 }, "name": "丹东", "pinyin": ["dan", "dong"] }, { "cidx": [438, 444], "fullname": "锦州市", "id": "210700", "location": { "lat": 41.09515, "lng": 121.12703 }, "name": "锦州", "pinyin": ["jin", "zhou"] }, { "cidx": [445, 450], "fullname": "营口市", "id": "210800", "location": { "lat": 40.66683, "lng": 122.2349 }, "name": "营口", "pinyin": ["ying", "kou"] }, { "cidx": [451, 457], "fullname": "阜新市", "id": "210900", "location": { "lat": 42.02166, "lng": 121.67011 }, "name": "阜新", "pinyin": ["fu", "xin"] }, { "cidx": [458, 464], "fullname": "辽阳市", "id": "211000", "location": { "lat": 41.26809, "lng": 123.23736 }, "name": "辽阳", "pinyin": ["liao", "yang"] }, { "cidx": [465, 468], "fullname": "盘锦市", "id": "211100", "location": { "lat": 41.11996, "lng": 122.07078 }, "name": "盘锦", "pinyin": ["pan", "jin"] }, { "cidx": [469, 475], "fullname": "铁岭市", "id": "211200", "location": { "lat": 42.2862, "lng": 123.84241 }, "name": "铁岭", "pinyin": ["tie", "ling"] }, { "cidx": [476, 482], "fullname": "朝阳市", "id": "211300", "location": { "lat": 41.57347, "lng": 120.4508 }, "name": "朝阳", "pinyin": ["chao", "yang"] }, { "cidx": [483, 488], "fullname": "葫芦岛市", "id": "211400", "location": { "lat": 40.711, "lng": 120.83699 }, "name": "葫芦岛", "pinyin": ["hu", "lu", "dao"] }, { "cidx": [489, 498], "fullname": "长春市", "id": "220100", "location": { "lat": 43.81602, "lng": 125.32357 }, "name": "长春", "pinyin": ["chang", "chun"] }, { "cidx": [499, 507], "fullname": "吉林市", "id": "220200", "location": { "lat": 43.83784, "lng": 126.54944 }, "name": "吉林", "pinyin": ["ji", "lin"] }, { "cidx": [508, 513], "fullname": "四平市", "id": "220300", "location": { "lat": 43.16646, "lng": 124.35036 }, "name": "四平", "pinyin": ["si", "ping"] }, { "cidx": [514, 517], "fullname": "辽源市", "id": "220400", "location": { "lat": 42.88805, "lng": 125.14368 }, "name": "辽源", "pinyin": ["liao", "yuan"] }, { "cidx": [518, 524], "fullname": "通化市", "id": "220500", "location": { "lat": 41.72829, "lng": 125.9399 }, "name": "通化", "pinyin": ["tong", "hua"] }, { "cidx": [525, 530], "fullname": "白山市", "id": "220600", "location": { "lat": 41.9408, "lng": 126.42443 }, "name": "白山", "pinyin": ["bai", "shan"] }, { "cidx": [531, 535], "fullname": "松原市", "id": "220700", "location": { "lat": 45.1411, "lng": 124.82515 }, "name": "松原", "pinyin": ["song", "yuan"] }, { "cidx": [536, 540], "fullname": "白城市", "id": "220800", "location": { "lat": 45.6196, "lng": 122.83871 }, "name": "白城", "pinyin": ["bai", "cheng"] }, { "cidx": [541, 548], "fullname": "延边朝鲜族自治州", "id": "222400", "location": { "lat": 42.89119, "lng": 129.5091 }, "name": "延边", "pinyin": ["yan", "bian"] }, { "cidx": [549, 566], "fullname": "哈尔滨市", "id": "230100", "location": { "lat": 45.80216, "lng": 126.5358 }, "name": "哈尔滨", "pinyin": ["ha", "er", "bin"] }, { "cidx": [567, 582], "fullname": "齐齐哈尔市", "id": "230200", "location": { "lat": 47.35431, "lng": 123.91796 }, "name": "齐齐哈尔", "pinyin": ["qi", "qi", "ha", "er"] }, { "cidx": [583, 591], "fullname": "鸡西市", "id": "230300", "location": { "lat": 45.29524, "lng": 130.96954 }, "name": "鸡西", "pinyin": ["ji", "xi"] }, { "cidx": [592, 599], "fullname": "鹤岗市", "id": "230400", "location": { "lat": 47.34989, "lng": 130.29785 }, "name": "鹤岗", "pinyin": ["he", "gang"] }, { "cidx": [600, 607], "fullname": "双鸭山市", "id": "230500", "location": { "lat": 46.64658, "lng": 131.1591 }, "name": "双鸭山", "pinyin": ["shuang", "ya", "shan"] }, { "cidx": [608, 616], "fullname": "大庆市", "id": "230600", "location": { "lat": 46.58758, "lng": 125.10307 }, "name": "大庆", "pinyin": ["da", "qing"] }, { "cidx": [617, 633], "fullname": "伊春市", "id": "230700", "location": { "lat": 47.72752, "lng": 128.84049 }, "name": "伊春", "pinyin": ["yi", "chun"] }, { "cidx": [634, 643], "fullname": "佳木斯市", "id": "230800", "location": { "lat": 46.79977, "lng": 130.31882 }, "name": "佳木斯", "pinyin": ["jia", "mu", "si"] }, { "cidx": [644, 647], "fullname": "七台河市", "id": "230900", "location": { "lat": 45.77065, "lng": 131.00306 }, "name": "七台河", "pinyin": ["qi", "tai", "he"] }, { "cidx": [648, 657], "fullname": "牡丹江市", "id": "231000", "location": { "lat": 44.55269, "lng": 129.63244 }, "name": "牡丹江", "pinyin": ["mu", "dan", "jiang"] }, { "cidx": [658, 663], "fullname": "黑河市", "id": "231100", "location": { "lat": 50.24523, "lng": 127.52852 }, "name": "黑河", "pinyin": ["hei", "he"] }, { "cidx": [664, 673], "fullname": "绥化市", "id": "231200", "location": { "lat": 46.65246, "lng": 126.96932 }, "name": "绥化", "pinyin": ["sui", "hua"] }, { "cidx": [674, 677], "fullname": "大兴安岭地区", "id": "232700", "location": { "lat": 51.92398, "lng": 124.59216 }, "name": "大兴安岭", "pinyin": ["da", "xing", "an", "ling"] }, { "fullname": "黄浦区", "id": "310101", "location": { "lat": 31.23162, "lng": 121.48461 }, "name": "黄浦", "pinyin": ["huang", "pu"] }, { "fullname": "徐汇区", "id": "310104", "location": { "lat": 31.18826, "lng": 121.43687 }, "name": "徐汇", "pinyin": ["xu", "hui"] }, { "fullname": "长宁区", "id": "310105", "location": { "lat": 31.22024, "lng": 121.42394 }, "name": "长宁", "pinyin": ["chang", "ning"] }, { "fullname": "静安区", "id": "310106", "location": { "lat": 31.22352, "lng": 121.45591 }, "name": "静安", "pinyin": ["jing", "an"] }, { "fullname": "普陀区", "id": "310107", "location": { "lat": 31.2494, "lng": 121.397 }, "name": "普陀", "pinyin": ["pu", "tuo"] }, { "fullname": "虹口区", "id": "310109", "location": { "lat": 31.26451, "lng": 121.50515 }, "name": "虹口", "pinyin": ["hong", "kou"] }, { "fullname": "杨浦区", "id": "310110", "location": { "lat": 31.25956, "lng": 121.52609 }, "name": "杨浦", "pinyin": ["yang", "pu"] }, { "fullname": "闵行区", "id": "310112", "location": { "lat": 31.11325, "lng": 121.38206 }, "name": "闵行", "pinyin": ["min", "hang"] }, { "fullname": "宝山区", "id": "310113", "location": { "lat": 31.40527, "lng": 121.48941 }, "name": "宝山", "pinyin": ["bao", "shan"] }, { "fullname": "嘉定区", "id": "310114", "location": { "lat": 31.37482, "lng": 121.26621 }, "name": "嘉定", "pinyin": ["jia", "ding"] }, { "fullname": "浦东新区", "id": "310115", "location": { "lat": 31.22114, "lng": 121.54409 }, "name": "浦东", "pinyin": ["pu", "dong"] }, { "fullname": "金山区", "id": "310116", "location": { "lat": 30.74185, "lng": 121.34242 }, "name": "金山", "pinyin": ["jin", "shan"] }, { "fullname": "松江区", "id": "310117", "location": { "lat": 31.03241, "lng": 121.22654 }, "name": "松江", "pinyin": ["song", "jiang"] }, { "fullname": "青浦区", "id": "310118", "location": { "lat": 31.14979, "lng": 121.12426 }, "name": "青浦", "pinyin": ["qing", "pu"] }, { "fullname": "奉贤区", "id": "310120", "location": { "lat": 30.91803, "lng": 121.4741 }, "name": "奉贤", "pinyin": ["feng", "xian"] }, { "fullname": "崇明区", "id": "310151", "location": { "lat": 31.6229, "lng": 121.3973 }, "name": "崇明", "pinyin": ["chong", "ming"] }, { "cidx": [678, 688], "fullname": "南京市", "id": "320100", "location": { "lat": 32.05838, "lng": 118.79647 }, "name": "南京", "pinyin": ["nan", "jing"] }, { "cidx": [689, 695], "fullname": "无锡市", "id": "320200", "location": { "lat": 31.49099, "lng": 120.31237 }, "name": "无锡", "pinyin": ["wu", "xi"] }, { "cidx": [696, 705], "fullname": "徐州市", "id": "320300", "location": { "lat": 34.2044, "lng": 117.28577 }, "name": "徐州", "pinyin": ["xu", "zhou"] }, { "cidx": [706, 711], "fullname": "常州市", "id": "320400", "location": { "lat": 31.81072, "lng": 119.97365 }, "name": "常州", "pinyin": ["chang", "zhou"] }, { "cidx": [712, 720], "fullname": "苏州市", "id": "320500", "location": { "lat": 31.29834, "lng": 120.58319 }, "name": "苏州", "pinyin": ["su", "zhou"] }, { "cidx": [721, 728], "fullname": "南通市", "id": "320600", "location": { "lat": 31.97958, "lng": 120.89371 }, "name": "南通", "pinyin": ["nan", "tong"] }, { "cidx": [729, 734], "fullname": "连云港市", "id": "320700", "location": { "lat": 34.59669, "lng": 119.22295 }, "name": "连云港", "pinyin": ["lian", "yun", "gang"] }, { "cidx": [735, 741], "fullname": "淮安市", "id": "320800", "location": { "lat": 33.61016, "lng": 119.01595 }, "name": "淮安", "pinyin": ["huai", "an"] }, { "cidx": [742, 750], "fullname": "盐城市", "id": "320900", "location": { "lat": 33.34951, "lng": 120.16164 }, "name": "盐城", "pinyin": ["yan", "cheng"] }, { "cidx": [751, 756], "fullname": "扬州市", "id": "321000", "location": { "lat": 32.39358, "lng": 119.41269 }, "name": "扬州", "pinyin": ["yang", "zhou"] }, { "cidx": [757, 762], "fullname": "镇江市", "id": "321100", "location": { "lat": 32.18959, "lng": 119.425 }, "name": "镇江", "pinyin": ["zhen", "jiang"] }, { "cidx": [763, 768], "fullname": "泰州市", "id": "321200", "location": { "lat": 32.45546, "lng": 119.92554 }, "name": "泰州", "pinyin": ["tai", "zhou"] }, { "cidx": [769, 773], "fullname": "宿迁市", "id": "321300", "location": { "lat": 33.96193, "lng": 118.27549 }, "name": "宿迁", "pinyin": ["su", "qian"] }, { "cidx": [774, 786], "fullname": "杭州市", "id": "330100", "location": { "lat": 30.27415, "lng": 120.15515 }, "name": "杭州", "pinyin": ["hang", "zhou"] }, { "cidx": [787, 796], "fullname": "宁波市", "id": "330200", "location": { "lat": 29.87386, "lng": 121.55027 }, "name": "宁波", "pinyin": ["ning", "bo"] }, { "cidx": [797, 808], "fullname": "温州市", "id": "330300", "location": { "lat": 27.99492, "lng": 120.69939 }, "name": "温州", "pinyin": ["wen", "zhou"] }, { "cidx": [809, 815], "fullname": "嘉兴市", "id": "330400", "location": { "lat": 30.74501, "lng": 120.7555 }, "name": "嘉兴", "pinyin": ["jia", "xing"] }, { "cidx": [816, 820], "fullname": "湖州市", "id": "330500", "location": { "lat": 30.89305, "lng": 120.08805 }, "name": "湖州", "pinyin": ["hu", "zhou"] }, { "cidx": [821, 826], "fullname": "绍兴市", "id": "330600", "location": { "lat": 30.03033, "lng": 120.5802 }, "name": "绍兴", "pinyin": ["shao", "xing"] }, { "cidx": [827, 835], "fullname": "金华市", "id": "330700", "location": { "lat": 29.07812, "lng": 119.64759 }, "name": "金华", "pinyin": ["jin", "hua"] }, { "cidx": [836, 841], "fullname": "衢州市", "id": "330800", "location": { "lat": 28.93592, "lng": 118.87419 }, "name": "衢州", "pinyin": ["qu", "zhou"] }, { "cidx": [842, 845], "fullname": "舟山市", "id": "330900", "location": { "lat": 29.98539, "lng": 122.20778 }, "name": "舟山", "pinyin": ["zhou", "shan"] }, { "cidx": [846, 854], "fullname": "台州市", "id": "331000", "location": { "lat": 28.65611, "lng": 121.42056 }, "name": "台州", "pinyin": ["tai", "zhou"] }, { "cidx": [855, 863], "fullname": "丽水市", "id": "331100", "location": { "lat": 28.4672, "lng": 119.92293 }, "name": "丽水", "pinyin": ["li", "shui"] }, { "cidx": [864, 872], "fullname": "合肥市", "id": "340100", "location": { "lat": 31.82057, "lng": 117.22901 }, "name": "合肥", "pinyin": ["he", "fei"] }, { "cidx": [873, 880], "fullname": "芜湖市", "id": "340200", "location": { "lat": 31.35246, "lng": 118.43313 }, "name": "芜湖", "pinyin": ["wu", "hu"] }, { "cidx": [881, 887], "fullname": "蚌埠市", "id": "340300", "location": { "lat": 32.91548, "lng": 117.38932 }, "name": "蚌埠", "pinyin": ["beng", "bu"] }, { "cidx": [888, 894], "fullname": "淮南市", "id": "340400", "location": { "lat": 32.62549, "lng": 116.9998 }, "name": "淮南", "pinyin": ["huai", "nan"] }, { "cidx": [895, 900], "fullname": "马鞍山市", "id": "340500", "location": { "lat": 31.67067, "lng": 118.50611 }, "name": "马鞍山", "pinyin": ["ma", "an", "shan"] }, { "cidx": [901, 904], "fullname": "淮北市", "id": "340600", "location": { "lat": 33.95479, "lng": 116.79834 }, "name": "淮北", "pinyin": ["huai", "bei"] }, { "cidx": [905, 908], "fullname": "铜陵市", "id": "340700", "location": { "lat": 30.94486, "lng": 117.81232 }, "name": "铜陵", "pinyin": ["tong", "ling"] }, { "cidx": [909, 918], "fullname": "安庆市", "id": "340800", "location": { "lat": 30.54294, "lng": 117.06354 }, "name": "安庆", "pinyin": ["an", "qing"] }, { "cidx": [919, 925], "fullname": "黄山市", "id": "341000", "location": { "lat": 29.71517, "lng": 118.33866 }, "name": "黄山", "pinyin": ["huang", "shan"] }, { "cidx": [926, 933], "fullname": "滁州市", "id": "341100", "location": { "lat": 32.30181, "lng": 118.31683 }, "name": "滁州", "pinyin": ["chu", "zhou"] }, { "cidx": [934, 941], "fullname": "阜阳市", "id": "341200", "location": { "lat": 32.88963, "lng": 115.81495 }, "name": "阜阳", "pinyin": ["fu", "yang"] }, { "cidx": [942, 946], "fullname": "宿州市", "id": "341300", "location": { "lat": 33.64614, "lng": 116.96391 }, "name": "宿州", "pinyin": ["su", "zhou"] }, { "cidx": [947, 953], "fullname": "六安市", "id": "341500", "location": { "lat": 31.73488, "lng": 116.52324 }, "name": "六安", "pinyin": ["liu", "an"] }, { "cidx": [954, 957], "fullname": "亳州市", "id": "341600", "location": { "lat": 33.84461, "lng": 115.77931 }, "name": "亳州", "pinyin": ["bo", "zhou"] }, { "cidx": [958, 961], "fullname": "池州市", "id": "341700", "location": { "lat": 30.66469, "lng": 117.49142 }, "name": "池州", "pinyin": ["chi", "zhou"] }, { "cidx": [962, 968], "fullname": "宣城市", "id": "341800", "location": { "lat": 30.94078, "lng": 118.75866 }, "name": "宣城", "pinyin": ["xuan", "cheng"] }, { "cidx": [969, 981], "fullname": "福州市", "id": "350100", "location": { "lat": 26.07421, "lng": 119.29647 }, "name": "福州", "pinyin": ["fu", "zhou"] }, { "cidx": [982, 987], "fullname": "厦门市", "id": "350200", "location": { "lat": 24.47951, "lng": 118.08948 }, "name": "厦门", "pinyin": ["xia", "men"] }, { "cidx": [988, 992], "fullname": "莆田市", "id": "350300", "location": { "lat": 25.454, "lng": 119.00771 }, "name": "莆田", "pinyin": ["pu", "tian"] }, { "cidx": [993, 1004], "fullname": "三明市", "id": "350400", "location": { "lat": 26.26385, "lng": 117.63922 }, "name": "三明", "pinyin": ["san", "ming"] }, { "cidx": [1005, 1016], "fullname": "泉州市", "id": "350500", "location": { "lat": 24.87389, "lng": 118.67587 }, "name": "泉州", "pinyin": ["quan", "zhou"] }, { "cidx": [1017, 1027], "fullname": "漳州市", "id": "350600", "location": { "lat": 24.51347, "lng": 117.64725 }, "name": "漳州", "pinyin": ["zhang", "zhou"] }, { "cidx": [1028, 1037], "fullname": "南平市", "id": "350700", "location": { "lat": 27.33175, "lng": 118.12043 }, "name": "南平", "pinyin": ["nan", "ping"] }, { "cidx": [1038, 1044], "fullname": "龙岩市", "id": "350800", "location": { "lat": 25.07504, "lng": 117.01722 }, "name": "龙岩", "pinyin": ["long", "yan"] }, { "cidx": [1045, 1053], "fullname": "宁德市", "id": "350900", "location": { "lat": 26.66571, "lng": 119.54819 }, "name": "宁德", "pinyin": ["ning", "de"] }, { "cidx": [1054, 1062], "fullname": "南昌市", "id": "360100", "location": { "lat": 28.68202, "lng": 115.85794 }, "name": "南昌", "pinyin": ["nan", "chang"] }, { "cidx": [1063, 1066], "fullname": "景德镇市", "id": "360200", "location": { "lat": 29.26869, "lng": 117.17839 }, "name": "景德镇", "pinyin": ["jing", "de", "zhen"] }, { "cidx": [1067, 1071], "fullname": "萍乡市", "id": "360300", "location": { "lat": 27.62289, "lng": 113.85427 }, "name": "萍乡", "pinyin": ["ping", "xiang"] }, { "cidx": [1072, 1084], "fullname": "九江市", "id": "360400", "location": { "lat": 29.70548, "lng": 116.00146 }, "name": "九江", "pinyin": ["jiu", "jiang"] }, { "cidx": [1085, 1086], "fullname": "新余市", "id": "360500", "location": { "lat": 27.81776, "lng": 114.91713 }, "name": "新余", "pinyin": ["xin", "yu"] }, { "cidx": [1087, 1089], "fullname": "鹰潭市", "id": "360600", "location": { "lat": 28.26019, "lng": 117.06919 }, "name": "鹰潭", "pinyin": ["ying", "tan"] }, { "cidx": [1090, 1107], "fullname": "赣州市", "id": "360700", "location": { "lat": 25.83109, "lng": 114.93476 }, "name": "赣州", "pinyin": ["gan", "zhou"] }, { "cidx": [1108, 1120], "fullname": "吉安市", "id": "360800", "location": { "lat": 27.11382, "lng": 114.99376 }, "name": "吉安", "pinyin": ["ji", "an"] }, { "cidx": [1121, 1130], "fullname": "宜春市", "id": "360900", "location": { "lat": 27.81443, "lng": 114.41612 }, "name": "宜春", "pinyin": ["yi", "chun"] }, { "cidx": [1131, 1141], "fullname": "抚州市", "id": "361000", "location": { "lat": 27.94781, "lng": 116.35809 }, "name": "抚州", "pinyin": ["fu", "zhou"] }, { "cidx": [1142, 1153], "fullname": "上饶市", "id": "361100", "location": { "lat": 28.45463, "lng": 117.94357 }, "name": "上饶", "pinyin": ["shang", "rao"] }, { "cidx": [1154, 1165], "fullname": "济南市", "id": "370100", "location": { "lat": 36.65184, "lng": 117.12009 }, "name": "济南", "pinyin": ["ji", "nan"] }, { "cidx": [1166, 1175], "fullname": "青岛市", "id": "370200", "location": { "lat": 36.06623, "lng": 120.38299 }, "name": "青岛", "pinyin": ["qing", "dao"] }, { "cidx": [1176, 1183], "fullname": "淄博市", "id": "370300", "location": { "lat": 36.8131, "lng": 118.0548 }, "name": "淄博", "pinyin": ["zi", "bo"] }, { "cidx": [1184, 1189], "fullname": "枣庄市", "id": "370400", "location": { "lat": 34.81071, "lng": 117.32196 }, "name": "枣庄", "pinyin": ["zao", "zhuang"] }, { "cidx": [1190, 1194], "fullname": "东营市", "id": "370500", "location": { "lat": 37.43365, "lng": 118.67466 }, "name": "东营", "pinyin": ["dong", "ying"] }, { "cidx": [1195, 1206], "fullname": "烟台市", "id": "370600", "location": { "lat": 37.46353, "lng": 121.44801 }, "name": "烟台", "pinyin": ["yan", "tai"] }, { "cidx": [1207, 1218], "fullname": "潍坊市", "id": "370700", "location": { "lat": 36.70686, "lng": 119.16176 }, "name": "潍坊", "pinyin": ["wei", "fang"] }, { "cidx": [1219, 1229], "fullname": "济宁市", "id": "370800", "location": { "lat": 35.41459, "lng": 116.58724 }, "name": "济宁", "pinyin": ["ji", "ning"] }, { "cidx": [1230, 1235], "fullname": "泰安市", "id": "370900", "location": { "lat": 36.19994, "lng": 117.0884 }, "name": "泰安", "pinyin": ["tai", "an"] }, { "cidx": [1236, 1239], "fullname": "威海市", "id": "371000", "location": { "lat": 37.51348, "lng": 122.12171 }, "name": "威海", "pinyin": ["wei", "hai"] }, { "cidx": [1240, 1243], "fullname": "日照市", "id": "371100", "location": { "lat": 35.41646, "lng": 119.52719 }, "name": "日照", "pinyin": ["ri", "zhao"] }, { "cidx": [1244, 1255], "fullname": "临沂市", "id": "371300", "location": { "lat": 35.10465, "lng": 118.35646 }, "name": "临沂", "pinyin": ["lin", "yi"] }, { "cidx": [1256, 1266], "fullname": "德州市", "id": "371400", "location": { "lat": 37.4355, "lng": 116.35927 }, "name": "德州", "pinyin": ["de", "zhou"] }, { "cidx": [1267, 1274], "fullname": "聊城市", "id": "371500", "location": { "lat": 36.45702, "lng": 115.98549 }, "name": "聊城", "pinyin": ["liao", "cheng"] }, { "cidx": [1275, 1281], "fullname": "滨州市", "id": "371600", "location": { "lat": 37.38211, "lng": 117.97279 }, "name": "滨州", "pinyin": ["bin", "zhou"] }, { "cidx": [1282, 1290], "fullname": "菏泽市", "id": "371700", "location": { "lat": 35.23363, "lng": 115.48115 }, "name": "菏泽", "pinyin": ["he", "ze"] }, { "cidx": [1291, 1302], "fullname": "郑州市", "id": "410100", "location": { "lat": 34.74725, "lng": 113.62493 }, "name": "郑州", "pinyin": ["zheng", "zhou"] }, { "cidx": [1303, 1311], "fullname": "开封市", "id": "410200", "location": { "lat": 34.79726, "lng": 114.30731 }, "name": "开封", "pinyin": ["kai", "feng"] }, { "cidx": [1312, 1326], "fullname": "洛阳市", "id": "410300", "location": { "lat": 34.61812, "lng": 112.45361 }, "name": "洛阳", "pinyin": ["luo", "yang"] }, { "cidx": [1327, 1336], "fullname": "平顶山市", "id": "410400", "location": { "lat": 33.76609, "lng": 113.19241 }, "name": "平顶山", "pinyin": ["ping", "ding", "shan"] }, { "cidx": [1337, 1345], "fullname": "安阳市", "id": "410500", "location": { "lat": 36.09771, "lng": 114.3931 }, "name": "安阳", "pinyin": ["an", "yang"] }, { "cidx": [1346, 1350], "fullname": "鹤壁市", "id": "410600", "location": { "lat": 35.747, "lng": 114.29745 }, "name": "鹤壁", "pinyin": ["he", "bi"] }, { "cidx": [1351, 1362], "fullname": "新乡市", "id": "410700", "location": { "lat": 35.30323, "lng": 113.92675 }, "name": "新乡", "pinyin": ["xin", "xiang"] }, { "cidx": [1363, 1372], "fullname": "焦作市", "id": "410800", "location": { "lat": 35.21563, "lng": 113.24201 }, "name": "焦作", "pinyin": ["jiao", "zuo"] }, { "cidx": [1373, 1378], "fullname": "濮阳市", "id": "410900", "location": { "lat": 35.76189, "lng": 115.02932 }, "name": "濮阳", "pinyin": ["pu", "yang"] }, { "cidx": [1379, 1384], "fullname": "许昌市", "id": "411000", "location": { "lat": 34.0357, "lng": 113.85233 }, "name": "许昌", "pinyin": ["xu", "chang"] }, { "cidx": [1385, 1389], "fullname": "漯河市", "id": "411100", "location": { "lat": 33.58149, "lng": 114.01681 }, "name": "漯河", "pinyin": ["luo", "he"] }, { "cidx": [1390, 1395], "fullname": "三门峡市", "id": "411200", "location": { "lat": 34.77261, "lng": 111.2003 }, "name": "三门峡", "pinyin": ["san", "men", "xia"] }, { "cidx": [1396, 1408], "fullname": "南阳市", "id": "411300", "location": { "lat": 32.99073, "lng": 112.52851 }, "name": "南阳", "pinyin": ["nan", "yang"] }, { "cidx": [1409, 1417], "fullname": "商丘市", "id": "411400", "location": { "lat": 34.41427, "lng": 115.65635 }, "name": "商丘", "pinyin": ["shang", "qiu"] }, { "cidx": [1418, 1427], "fullname": "信阳市", "id": "411500", "location": { "lat": 32.14714, "lng": 114.09279 }, "name": "信阳", "pinyin": ["xin", "yang"] }, { "cidx": [1428, 1437], "fullname": "周口市", "id": "411600", "location": { "lat": 33.62583, "lng": 114.69695 }, "name": "周口", "pinyin": ["zhou", "kou"] }, { "cidx": [1438, 1447], "fullname": "驻马店市", "id": "411700", "location": { "lat": 33.01142, "lng": 114.02299 }, "name": "驻马店", "pinyin": ["zhu", "ma", "dian"] }, { "fullname": "济源市", "id": "419001", "location": { "lat": 35.06707, "lng": 112.60273 }, "name": "济源", "pinyin": ["ji", "yuan"] }, { "cidx": [1448, 1460], "fullname": "武汉市", "id": "420100", "location": { "lat": 30.59276, "lng": 114.30525 }, "name": "武汉", "pinyin": ["wu", "han"] }, { "cidx": [1461, 1466], "fullname": "黄石市", "id": "420200", "location": { "lat": 30.19953, "lng": 115.0389 }, "name": "黄石", "pinyin": ["huang", "shi"] }, { "cidx": [1467, 1474], "fullname": "十堰市", "id": "420300", "location": { "lat": 32.62918, "lng": 110.79801 }, "name": "十堰", "pinyin": ["shi", "yan"] }, { "cidx": [1475, 1487], "fullname": "宜昌市", "id": "420500", "location": { "lat": 30.69186, "lng": 111.28642 }, "name": "宜昌", "pinyin": ["yi", "chang"] }, { "cidx": [1488, 1496], "fullname": "襄阳市", "id": "420600", "location": { "lat": 32.009, "lng": 112.12255 }, "name": "襄阳", "pinyin": ["xiang", "yang"] }, { "cidx": [1497, 1499], "fullname": "鄂州市", "id": "420700", "location": { "lat": 30.39085, "lng": 114.89495 }, "name": "鄂州", "pinyin": ["e", "zhou"] }, { "cidx": [1500, 1504], "fullname": "荆门市", "id": "420800", "location": { "lat": 31.03546, "lng": 112.19945 }, "name": "荆门", "pinyin": ["jing", "men"] }, { "cidx": [1505, 1511], "fullname": "孝感市", "id": "420900", "location": { "lat": 30.92483, "lng": 113.91645 }, "name": "孝感", "pinyin": ["xiao", "gan"] }, { "cidx": [1512, 1519], "fullname": "荆州市", "id": "421000", "location": { "lat": 30.33479, "lng": 112.24069 }, "name": "荆州", "pinyin": ["jing", "zhou"] }, { "cidx": [1520, 1529], "fullname": "黄冈市", "id": "421100", "location": { "lat": 30.45347, "lng": 114.87238 }, "name": "黄冈", "pinyin": ["huang", "gang"] }, { "cidx": [1530, 1535], "fullname": "咸宁市", "id": "421200", "location": { "lat": 29.84126, "lng": 114.32245 }, "name": "咸宁", "pinyin": ["xian", "ning"] }, { "cidx": [1536, 1538], "fullname": "随州市", "id": "421300", "location": { "lat": 31.69013, "lng": 113.38262 }, "name": "随州", "pinyin": ["sui", "zhou"] }, { "cidx": [1539, 1546], "fullname": "恩施土家族苗族自治州", "id": "422800", "location": { "lat": 30.27217, "lng": 109.48817 }, "name": "恩施", "pinyin": ["en", "shi"] }, { "fullname": "仙桃市", "id": "429004", "location": { "lat": 30.36251, "lng": 113.4545 }, "name": "仙桃", "pinyin": ["xian", "tao"] }, { "fullname": "潜江市", "id": "429005", "location": { "lat": 30.40147, "lng": 112.8993 }, "name": "潜江", "pinyin": ["qian", "jiang"] }, { "fullname": "天门市", "id": "429006", "location": { "lat": 30.66339, "lng": 113.16614 }, "name": "天门", "pinyin": ["tian", "men"] }, { "fullname": "神农架林区", "id": "429021", "location": { "lat": 31.74452, "lng": 110.67598 }, "name": "神农架", "pinyin": ["shen", "nong", "jia"] }, { "cidx": [1547, 1555], "fullname": "长沙市", "id": "430100", "location": { "lat": 28.22778, "lng": 112.93886 }, "name": "长沙", "pinyin": ["chang", "sha"] }, { "cidx": [1556, 1564], "fullname": "株洲市", "id": "430200", "location": { "lat": 27.82767, "lng": 113.13396 }, "name": "株洲", "pinyin": ["zhu", "zhou"] }, { "cidx": [1565, 1569], "fullname": "湘潭市", "id": "430300", "location": { "lat": 27.82975, "lng": 112.94411 }, "name": "湘潭", "pinyin": ["xiang", "tan"] }, { "cidx": [1570, 1581], "fullname": "衡阳市", "id": "430400", "location": { "lat": 26.89324, "lng": 112.57195 }, "name": "衡阳", "pinyin": ["heng", "yang"] }, { "cidx": [1582, 1593], "fullname": "邵阳市", "id": "430500", "location": { "lat": 27.2389, "lng": 111.4677 }, "name": "邵阳", "pinyin": ["shao", "yang"] }, { "cidx": [1594, 1602], "fullname": "岳阳市", "id": "430600", "location": { "lat": 29.35728, "lng": 113.12919 }, "name": "岳阳", "pinyin": ["yue", "yang"] }, { "cidx": [1603, 1611], "fullname": "常德市", "id": "430700", "location": { "lat": 29.03158, "lng": 111.69854 }, "name": "常德", "pinyin": ["chang", "de"] }, { "cidx": [1612, 1615], "fullname": "张家界市", "id": "430800", "location": { "lat": 29.11667, "lng": 110.47839 }, "name": "张家界", "pinyin": ["zhang", "jia", "jie"] }, { "cidx": [1616, 1621], "fullname": "益阳市", "id": "430900", "location": { "lat": 28.55391, "lng": 112.35516 }, "name": "益阳", "pinyin": ["yi", "yang"] }, { "cidx": [1622, 1632], "fullname": "郴州市", "id": "431000", "location": { "lat": 25.77063, "lng": 113.01485 }, "name": "郴州", "pinyin": ["chen", "zhou"] }, { "cidx": [1633, 1643], "fullname": "永州市", "id": "431100", "location": { "lat": 26.42034, "lng": 111.61225 }, "name": "永州", "pinyin": ["yong", "zhou"] }, { "cidx": [1644, 1655], "fullname": "怀化市", "id": "431200", "location": { "lat": 27.56974, "lng": 110.0016 }, "name": "怀化", "pinyin": ["huai", "hua"] }, { "cidx": [1656, 1660], "fullname": "娄底市", "id": "431300", "location": { "lat": 27.69728, "lng": 111.99458 }, "name": "娄底", "pinyin": ["lou", "di"] }, { "cidx": [1661, 1668], "fullname": "湘西土家族苗族自治州", "id": "433100", "location": { "lat": 28.31173, "lng": 109.73893 }, "name": "湘西", "pinyin": ["xiang", "xi"] }, { "cidx": [1669, 1679], "fullname": "广州市", "id": "440100", "location": { "lat": 23.12908, "lng": 113.26436 }, "name": "广州", "pinyin": ["guang", "zhou"] }, { "cidx": [1680, 1689], "fullname": "韶关市", "id": "440200", "location": { "lat": 24.81039, "lng": 113.59723 }, "name": "韶关", "pinyin": ["shao", "guan"] }, { "cidx": [1690, 1698], "fullname": "深圳市", "id": "440300", "location": { "lat": 22.54286, "lng": 114.05956 }, "name": "深圳", "pinyin": ["shen", "zhen"] }, { "cidx": [1699, 1702], "fullname": "珠海市", "id": "440400", "location": { "lat": 22.27073, "lng": 113.57668 }, "name": "珠海", "pinyin": ["zhu", "hai"] }, { "cidx": [1703, 1709], "fullname": "汕头市", "id": "440500", "location": { "lat": 23.3535, "lng": 116.68221 }, "name": "汕头", "pinyin": ["shan", "tou"] }, { "cidx": [1710, 1714], "fullname": "佛山市", "id": "440600", "location": { "lat": 23.02185, "lng": 113.12192 }, "name": "佛山", "pinyin": ["fo", "shan"] }, { "cidx": [1715, 1721], "fullname": "江门市", "id": "440700", "location": { "lat": 22.57865, "lng": 113.08161 }, "name": "江门", "pinyin": ["jiang", "men"] }, { "cidx": [1722, 1730], "fullname": "湛江市", "id": "440800", "location": { "lat": 21.27134, "lng": 110.35894 }, "name": "湛江", "pinyin": ["zhan", "jiang"] }, { "cidx": [1731, 1735], "fullname": "茂名市", "id": "440900", "location": { "lat": 21.66329, "lng": 110.92523 }, "name": "茂名", "pinyin": ["mao", "ming"] }, { "cidx": [1736, 1743], "fullname": "肇庆市", "id": "441200", "location": { "lat": 23.0469, "lng": 112.46528 }, "name": "肇庆", "pinyin": ["zhao", "qing"] }, { "cidx": [1744, 1748], "fullname": "惠州市", "id": "441300", "location": { "lat": 23.11075, "lng": 114.41679 }, "name": "惠州", "pinyin": ["hui", "zhou"] }, { "cidx": [1749, 1756], "fullname": "梅州市", "id": "441400", "location": { "lat": 24.28844, "lng": 116.12264 }, "name": "梅州", "pinyin": ["mei", "zhou"] }, { "cidx": [1757, 1760], "fullname": "汕尾市", "id": "441500", "location": { "lat": 22.78566, "lng": 115.37514 }, "name": "汕尾", "pinyin": ["shan", "wei"] }, { "cidx": [1761, 1766], "fullname": "河源市", "id": "441600", "location": { "lat": 23.74365, "lng": 114.70065 }, "name": "河源", "pinyin": ["he", "yuan"] }, { "cidx": [1767, 1770], "fullname": "阳江市", "id": "441700", "location": { "lat": 21.85829, "lng": 111.98256 }, "name": "阳江", "pinyin": ["yang", "jiang"] }, { "cidx": [1771, 1778], "fullname": "清远市", "id": "441800", "location": { "lat": 23.68201, "lng": 113.05615 }, "name": "清远", "pinyin": ["qing", "yuan"] }, { "cidx": [1779, 1779], "fullname": "东莞市", "id": "441900", "location": { "lat": 23.02067, "lng": 113.75179 }, "name": "东莞", "pinyin": ["dong", "guan"] }, { "cidx": [1780, 1780], "fullname": "中山市", "id": "442000", "location": { "lat": 22.51595, "lng": 113.3926 }, "name": "中山", "pinyin": ["zhong", "shan"] }, { "cidx": [1781, 1783], "fullname": "潮州市", "id": "445100", "location": { "lat": 23.6567, "lng": 116.62296 }, "name": "潮州", "pinyin": ["chao", "zhou"] }, { "cidx": [1784, 1788], "fullname": "揭阳市", "id": "445200", "location": { "lat": 23.54972, "lng": 116.37271 }, "name": "揭阳", "pinyin": ["jie", "yang"] }, { "cidx": [1789, 1793], "fullname": "云浮市", "id": "445300", "location": { "lat": 22.91525, "lng": 112.04453 }, "name": "云浮", "pinyin": ["yun", "fu"] }, { "cidx": [1794, 1805], "fullname": "南宁市", "id": "450100", "location": { "lat": 22.81673, "lng": 108.3669 }, "name": "南宁", "pinyin": ["nan", "ning"] }, { "cidx": [1806, 1815], "fullname": "柳州市", "id": "450200", "location": { "lat": 24.32543, "lng": 109.41552 }, "name": "柳州", "pinyin": ["liu", "zhou"] }, { "cidx": [1816, 1832], "fullname": "桂林市", "id": "450300", "location": { "lat": 25.27361, "lng": 110.29002 }, "name": "桂林", "pinyin": ["gui", "lin"] }, { "cidx": [1833, 1839], "fullname": "梧州市", "id": "450400", "location": { "lat": 23.47691, "lng": 111.27917 }, "name": "梧州", "pinyin": ["wu", "zhou"] }, { "cidx": [1840, 1843], "fullname": "北海市", "id": "450500", "location": { "lat": 21.48112, "lng": 109.12008 }, "name": "北海", "pinyin": ["bei", "hai"] }, { "cidx": [1844, 1847], "fullname": "防城港市", "id": "450600", "location": { "lat": 21.68713, "lng": 108.35472 }, "name": "防城港", "pinyin": ["fang", "cheng", "gang"] }, { "cidx": [1848, 1851], "fullname": "钦州市", "id": "450700", "location": { "lat": 21.9797, "lng": 108.65431 }, "name": "钦州", "pinyin": ["qin", "zhou"] }, { "cidx": [1852, 1856], "fullname": "贵港市", "id": "450800", "location": { "lat": 23.11306, "lng": 109.59764 }, "name": "贵港", "pinyin": ["gui", "gang"] }, { "cidx": [1857, 1863], "fullname": "玉林市", "id": "450900", "location": { "lat": 22.65451, "lng": 110.18098 }, "name": "玉林", "pinyin": ["yu", "lin"] }, { "cidx": [1864, 1875], "fullname": "百色市", "id": "451000", "location": { "lat": 23.90216, "lng": 106.61838 }, "name": "百色", "pinyin": ["bai", "se"] }, { "cidx": [1876, 1880], "fullname": "贺州市", "id": "451100", "location": { "lat": 24.40346, "lng": 111.56655 }, "name": "贺州", "pinyin": ["he", "zhou"] }, { "cidx": [1881, 1891], "fullname": "河池市", "id": "451200", "location": { "lat": 24.69291, "lng": 108.0854 }, "name": "河池", "pinyin": ["he", "chi"] }, { "cidx": [1892, 1897], "fullname": "来宾市", "id": "451300", "location": { "lat": 23.7521, "lng": 109.22238 }, "name": "来宾", "pinyin": ["lai", "bin"] }, { "cidx": [1898, 1904], "fullname": "崇左市", "id": "451400", "location": { "lat": 22.37895, "lng": 107.36485 }, "name": "崇左", "pinyin": ["chong", "zuo"] }, { "cidx": [1905, 1908], "fullname": "海口市", "id": "460100", "location": { "lat": 20.04422, "lng": 110.19989 }, "name": "海口", "pinyin": ["hai", "kou"] }, { "cidx": [1909, 1912], "fullname": "三亚市", "id": "460200", "location": { "lat": 18.25248, "lng": 109.51209 }, "name": "三亚", "pinyin": ["san", "ya"] }, { "cidx": [1913, 1915], "fullname": "三沙市", "id": "460300", "location": { "lat": 16.83272, "lng": 112.33356 }, "name": "三沙", "pinyin": ["san", "sha"] }, { "cidx": [1916, 1916], "fullname": "儋州市", "id": "460400", "location": { "lat": 19.52093, "lng": 109.58069 }, "name": "儋州", "pinyin": ["dan", "zhou"] }, { "fullname": "五指山市", "id": "469001", "location": { "lat": 18.77515, "lng": 109.51696 }, "name": "五指山", "pinyin": ["wu", "zhi", "shan"] }, { "fullname": "琼海市", "id": "469002", "location": { "lat": 19.25838, "lng": 110.47464 }, "name": "琼海", "pinyin": ["qiong", "hai"] }, { "fullname": "文昌市", "id": "469005", "location": { "lat": 19.54329, "lng": 110.79774 }, "name": "文昌", "pinyin": ["wen", "chang"] }, { "fullname": "万宁市", "id": "469006", "location": { "lat": 18.79532, "lng": 110.38975 }, "name": "万宁", "pinyin": ["wan", "ning"] }, { "fullname": "东方市", "id": "469007", "location": { "lat": 19.09614, "lng": 108.65367 }, "name": "东方", "pinyin": ["dong", "fang"] }, { "fullname": "定安县", "id": "469021", "location": { "lat": 19.68121, "lng": 110.3593 }, "name": "定安", "pinyin": ["ding", "an"] }, { "fullname": "屯昌县", "id": "469022", "location": { "lat": 19.35182, "lng": 110.10347 }, "name": "屯昌", "pinyin": ["tun", "chang"] }, { "fullname": "澄迈县", "id": "469023", "location": { "lat": 19.73849, "lng": 110.00487 }, "name": "澄迈", "pinyin": ["cheng", "mai"] }, { "fullname": "临高县", "id": "469024", "location": { "lat": 19.91243, "lng": 109.69077 }, "name": "临高", "pinyin": ["lin", "gao"] }, { "fullname": "白沙黎族自治县", "id": "469025", "location": { "lat": 19.22543, "lng": 109.45167 }, "name": "白沙", "pinyin": ["bai", "sha"] }, { "fullname": "昌江黎族自治县", "id": "469026", "location": { "lat": 19.29828, "lng": 109.05559 }, "name": "昌江", "pinyin": ["chang", "jiang"] }, { "fullname": "乐东黎族自治县", "id": "469027", "location": { "lat": 18.74986, "lng": 109.17361 }, "name": "乐东", "pinyin": ["le", "dong"] }, { "fullname": "陵水黎族自治县", "id": "469028", "location": { "lat": 18.50596, "lng": 110.0372 }, "name": "陵水", "pinyin": ["ling", "shui"] }, { "fullname": "保亭黎族苗族自治县", "id": "469029", "location": { "lat": 18.63905, "lng": 109.70259 }, "name": "保亭", "pinyin": ["bao", "ting"] }, { "fullname": "琼中黎族苗族自治县", "id": "469030", "location": { "lat": 19.03334, "lng": 109.83839 }, "name": "琼中", "pinyin": ["qiong", "zhong"] }, { "fullname": "万州区", "id": "500101", "location": { "lat": 30.8079, "lng": 108.40873 }, "name": "万州", "pinyin": ["wan", "zhou"] }, { "fullname": "涪陵区", "id": "500102", "location": { "lat": 29.70239, "lng": 107.38779 }, "name": "涪陵", "pinyin": ["fu", "ling"] }, { "fullname": "渝中区", "id": "500103", "location": { "lat": 29.55314, "lng": 106.5686 }, "name": "渝中", "pinyin": ["yu", "zhong"] }, { "fullname": "大渡口区", "id": "500104", "location": { "lat": 29.48408, "lng": 106.48225 }, "name": "大渡口", "pinyin": ["da", "du", "kou"] }, { "fullname": "江北区", "id": "500105", "location": { "lat": 29.60661, "lng": 106.57439 }, "name": "江北", "pinyin": ["jiang", "bei"] }, { "fullname": "沙坪坝区", "id": "500106", "location": { "lat": 29.54098, "lng": 106.45773 }, "name": "沙坪坝", "pinyin": ["sha", "ping", "ba"] }, { "fullname": "九龙坡区", "id": "500107", "location": { "lat": 29.50207, "lng": 106.5114 }, "name": "九龙坡", "pinyin": ["jiu", "long", "po"] }, { "fullname": "南岸区", "id": "500108", "location": { "lat": 29.52168, "lng": 106.56256 }, "name": "南岸", "pinyin": ["nan", "an"] }, { "fullname": "北碚区", "id": "500109", "location": { "lat": 29.80583, "lng": 106.39628 }, "name": "北碚", "pinyin": ["bei", "bei"] }, { "fullname": "綦江区", "id": "500110", "location": { "lat": 28.96463, "lng": 106.92852 }, "name": "綦江", "pinyin": ["qi", "jiang"] }, { "fullname": "大足区", "id": "500111", "location": { "lat": 29.48604, "lng": 105.78017 }, "name": "大足", "pinyin": ["da", "zu"] }, { "fullname": "渝北区", "id": "500112", "location": { "lat": 29.71798, "lng": 106.63043 }, "name": "渝北", "pinyin": ["yu", "bei"] }, { "fullname": "巴南区", "id": "500113", "location": { "lat": 29.40268, "lng": 106.54041 }, "name": "巴南", "pinyin": ["ba", "nan"] }, { "fullname": "黔江区", "id": "500114", "location": { "lat": 29.53322, "lng": 108.771086 }, "name": "黔江", "pinyin": ["qian", "jiang"] }, { "fullname": "长寿区", "id": "500115", "location": { "lat": 29.85781, "lng": 107.08105 }, "name": "长寿", "pinyin": ["chang", "shou"] }, { "fullname": "江津区", "id": "500116", "location": { "lat": 29.29014, "lng": 106.25936 }, "name": "江津", "pinyin": ["jiang", "jin"] }, { "fullname": "合川区", "id": "500117", "location": { "lat": 29.97288, "lng": 106.27679 }, "name": "合川", "pinyin": ["he", "chuan"] }, { "fullname": "永川区", "id": "500118", "location": { "lat": 29.356, "lng": 105.92709 }, "name": "永川", "pinyin": ["yong", "chuan"] }, { "fullname": "南川区", "id": "500119", "location": { "lat": 29.15788, "lng": 107.09896 }, "name": "南川", "pinyin": ["nan", "chuan"] }, { "fullname": "璧山区", "id": "500120", "location": { "lat": 29.59202, "lng": 106.22742 }, "name": "璧山", "pinyin": ["bi", "shan"] }, { "fullname": "铜梁区", "id": "500151", "location": { "lat": 29.84475, "lng": 106.05638 }, "name": "铜梁", "pinyin": ["tong", "liang"] }, { "fullname": "潼南区", "id": "500152", "location": { "lat": 30.19054, "lng": 105.83952 }, "name": "潼南", "pinyin": ["tong", "nan"] }, { "fullname": "荣昌区", "id": "500153", "location": { "lat": 29.41671, "lng": 105.61188 }, "name": "荣昌", "pinyin": ["rong", "chang"] }, { "fullname": "开州区", "id": "500154", "location": { "lat": 31.16098, "lng": 108.39311 }, "name": "开州", "pinyin": ["kai", "zhou"] }, { "fullname": "梁平区", "id": "500155", "location": { "lat": 30.67373, "lng": 107.80235 }, "name": "梁平", "pinyin": ["liang", "ping"] }, { "fullname": "武隆区", "id": "500156", "location": { "lat": 29.32543, "lng": 107.75993 }, "name": "武隆", "pinyin": ["wu", "long"] }, { "fullname": "城口县", "id": "500229", "location": { "lat": 31.94767, "lng": 108.66433 }, "name": "城口", "pinyin": ["cheng", "kou"] }, { "fullname": "丰都县", "id": "500230", "location": { "lat": 29.86352, "lng": 107.73085 }, "name": "丰都", "pinyin": ["feng", "du"] }, { "fullname": "垫江县", "id": "500231", "location": { "lat": 30.3268, "lng": 107.33515 }, "name": "垫江", "pinyin": ["dian", "jiang"] }, { "fullname": "忠县", "id": "500233", "location": { "lat": 30.30026, "lng": 108.03767 }, "name": "忠县", "pinyin": ["zhong", "xian"] }, { "fullname": "云阳县", "id": "500235", "location": { "lat": 30.93063, "lng": 108.69698 }, "name": "云阳", "pinyin": ["yun", "yang"] }, { "fullname": "奉节县", "id": "500236", "location": { "lat": 31.018551, "lng": 109.40093 }, "name": "奉节", "pinyin": ["feng", "jie"] }, { "fullname": "巫山县", "id": "500237", "location": { "lat": 31.07462, "lng": 109.8788 }, "name": "巫山", "pinyin": ["wu", "shan"] }, { "fullname": "巫溪县", "id": "500238", "location": { "lat": 31.3986, "lng": 109.57016 }, "name": "巫溪", "pinyin": ["wu", "xi"] }, { "fullname": "石柱土家族自治县", "id": "500240", "location": { "lat": 29.99968, "lng": 108.11415 }, "name": "石柱", "pinyin": ["shi", "zhu"] }, { "fullname": "秀山土家族苗族自治县", "id": "500241", "location": { "lat": 28.44832, "lng": 109.00714 }, "name": "秀山", "pinyin": ["xiu", "shan"] }, { "fullname": "酉阳土家族苗族自治县", "id": "500242", "location": { "lat": 28.84126, "lng": 108.76778 }, "name": "酉阳", "pinyin": ["you", "yang"] }, { "fullname": "彭水苗族土家族自治县", "id": "500243", "location": { "lat": 29.29376, "lng": 108.16555 }, "name": "彭水", "pinyin": ["peng", "shui"] }, { "cidx": [1917, 1936], "fullname": "成都市", "id": "510100", "location": { "lat": 30.5702, "lng": 104.06476 }, "name": "成都", "pinyin": ["cheng", "du"] }, { "cidx": [1937, 1942], "fullname": "自贡市", "id": "510300", "location": { "lat": 29.3392, "lng": 104.77844 }, "name": "自贡", "pinyin": ["zi", "gong"] }, { "cidx": [1943, 1947], "fullname": "攀枝花市", "id": "510400", "location": { "lat": 26.58228, "lng": 101.71872 }, "name": "攀枝花", "pinyin": ["pan", "zhi", "hua"] }, { "cidx": [1948, 1954], "fullname": "泸州市", "id": "510500", "location": { "lat": 28.8717, "lng": 105.44257 }, "name": "泸州", "pinyin": ["lu", "zhou"] }, { "cidx": [1955, 1960], "fullname": "德阳市", "id": "510600", "location": { "lat": 31.12679, "lng": 104.3979 }, "name": "德阳", "pinyin": ["de", "yang"] }, { "cidx": [1961, 1969], "fullname": "绵阳市", "id": "510700", "location": { "lat": 31.46751, "lng": 104.6796 }, "name": "绵阳", "pinyin": ["mian", "yang"] }, { "cidx": [1970, 1976], "fullname": "广元市", "id": "510800", "location": { "lat": 32.43549, "lng": 105.84357 }, "name": "广元", "pinyin": ["guang", "yuan"] }, { "cidx": [1977, 1981], "fullname": "遂宁市", "id": "510900", "location": { "lat": 30.53286, "lng": 105.59273 }, "name": "遂宁", "pinyin": ["sui", "ning"] }, { "cidx": [1982, 1986], "fullname": "内江市", "id": "511000", "location": { "lat": 29.58015, "lng": 105.05844 }, "name": "内江", "pinyin": ["nei", "jiang"] }, { "cidx": [1987, 1997], "fullname": "乐山市", "id": "511100", "location": { "lat": 29.55221, "lng": 103.76539 }, "name": "乐山", "pinyin": ["le", "shan"] }, { "cidx": [1998, 2006], "fullname": "南充市", "id": "511300", "location": { "lat": 30.83731, "lng": 106.11073 }, "name": "南充", "pinyin": ["nan", "chong"] }, { "cidx": [2007, 2012], "fullname": "眉山市", "id": "511400", "location": { "lat": 30.07563, "lng": 103.84851 }, "name": "眉山", "pinyin": ["mei", "shan"] }, { "cidx": [2013, 2022], "fullname": "宜宾市", "id": "511500", "location": { "lat": 28.7513, "lng": 104.6417 }, "name": "宜宾", "pinyin": ["yi", "bin"] }, { "cidx": [2023, 2028], "fullname": "广安市", "id": "511600", "location": { "lat": 30.45596, "lng": 106.63322 }, "name": "广安", "pinyin": ["guang", "an"] }, { "cidx": [2029, 2035], "fullname": "达州市", "id": "511700", "location": { "lat": 31.20864, "lng": 107.46791 }, "name": "达州", "pinyin": ["da", "zhou"] }, { "cidx": [2036, 2043], "fullname": "雅安市", "id": "511800", "location": { "lat": 30.01053, "lng": 103.0424 }, "name": "雅安", "pinyin": ["ya", "an"] }, { "cidx": [2044, 2048], "fullname": "巴中市", "id": "511900", "location": { "lat": 31.86715, "lng": 106.74733 }, "name": "巴中", "pinyin": ["ba", "zhong"] }, { "cidx": [2049, 2051], "fullname": "资阳市", "id": "512000", "location": { "lat": 30.12859, "lng": 104.62798 }, "name": "资阳", "pinyin": ["zi", "yang"] }, { "cidx": [2052, 2064], "fullname": "阿坝藏族羌族自治州", "id": "513200", "location": { "lat": 31.8994, "lng": 102.22477 }, "name": "阿坝", "pinyin": ["a", "ba"] }, { "cidx": [2065, 2082], "fullname": "甘孜藏族自治州", "id": "513300", "location": { "lat": 30.04932, "lng": 101.96254 }, "name": "甘孜", "pinyin": ["gan", "zi"] }, { "cidx": [2083, 2099], "fullname": "凉山彝族自治州", "id": "513400", "location": { "lat": 27.88164, "lng": 102.26746 }, "name": "凉山", "pinyin": ["liang", "shan"] }, { "cidx": [2100, 2109], "fullname": "贵阳市", "id": "520100", "location": { "lat": 26.64702, "lng": 106.63024 }, "name": "贵阳", "pinyin": ["gui", "yang"] }, { "cidx": [2110, 2113], "fullname": "六盘水市", "id": "520200", "location": { "lat": 26.59336, "lng": 104.83023 }, "name": "六盘水", "pinyin": ["liu", "pan", "shui"] }, { "cidx": [2114, 2127], "fullname": "遵义市", "id": "520300", "location": { "lat": 27.72545, "lng": 106.92723 }, "name": "遵义", "pinyin": ["zun", "yi"] }, { "cidx": [2128, 2133], "fullname": "安顺市", "id": "520400", "location": { "lat": 26.25367, "lng": 105.9462 }, "name": "安顺", "pinyin": ["an", "shun"] }, { "cidx": [2134, 2141], "fullname": "毕节市", "id": "520500", "location": { "lat": 27.29847, "lng": 105.30504 }, "name": "毕节", "pinyin": ["bi", "jie"] }, { "cidx": [2142, 2151], "fullname": "铜仁市", "id": "520600", "location": { "lat": 27.69066, "lng": 109.18099 }, "name": "铜仁", "pinyin": ["tong", "ren"] }, { "cidx": [2152, 2159], "fullname": "黔西南布依族苗族自治州", "id": "522300", "location": { "lat": 25.08988, "lng": 104.90437 }, "name": "黔西南", "pinyin": ["qian", "xi", "nan"] }, { "cidx": [2160, 2175], "fullname": "黔东南苗族侗族自治州", "id": "522600", "location": { "lat": 26.58364, "lng": 107.98416 }, "name": "黔东南", "pinyin": ["qian", "dong", "nan"] }, { "cidx": [2176, 2187], "fullname": "黔南布依族苗族自治州", "id": "522700", "location": { "lat": 26.25427, "lng": 107.52226 }, "name": "黔南", "pinyin": ["qian", "nan"] }, { "cidx": [2188, 2201], "fullname": "昆明市", "id": "530100", "location": { "lat": 24.87966, "lng": 102.83322 }, "name": "昆明", "pinyin": ["kun", "ming"] }, { "cidx": [2202, 2210], "fullname": "曲靖市", "id": "530300", "location": { "lat": 25.49002, "lng": 103.79625 }, "name": "曲靖", "pinyin": ["qu", "jing"] }, { "cidx": [2211, 2219], "fullname": "玉溪市", "id": "530400", "location": { "lat": 24.3518, "lng": 102.54714 }, "name": "玉溪", "pinyin": ["yu", "xi"] }, { "cidx": [2220, 2224], "fullname": "保山市", "id": "530500", "location": { "lat": 25.11205, "lng": 99.16181 }, "name": "保山", "pinyin": ["bao", "shan"] }, { "cidx": [2225, 2235], "fullname": "昭通市", "id": "530600", "location": { "lat": 27.33817, "lng": 103.7168 }, "name": "昭通", "pinyin": ["zhao", "tong"] }, { "cidx": [2236, 2240], "fullname": "丽江市", "id": "530700", "location": { "lat": 26.85648, "lng": 100.2271 }, "name": "丽江", "pinyin": ["li", "jiang"] }, { "cidx": [2241, 2250], "fullname": "普洱市", "id": "530800", "location": { "lat": 22.82521, "lng": 100.96624 }, "name": "普洱", "pinyin": ["pu", "er"] }, { "cidx": [2251, 2258], "fullname": "临沧市", "id": "530900", "location": { "lat": 23.88426, "lng": 100.08884 }, "name": "临沧", "pinyin": ["lin", "cang"] }, { "cidx": [2259, 2268], "fullname": "楚雄彝族自治州", "id": "532300", "location": { "lat": 25.04495, "lng": 101.52767 }, "name": "楚雄", "pinyin": ["chu", "xiong"] }, { "cidx": [2269, 2281], "fullname": "红河哈尼族彝族自治州", "id": "532500", "location": { "lat": 23.36422, "lng": 103.3756 }, "name": "红河", "pinyin": ["hong", "he"] }, { "cidx": [2282, 2289], "fullname": "文山壮族苗族自治州", "id": "532600", "location": { "lat": 23.39849, "lng": 104.21504 }, "name": "文山", "pinyin": ["wen", "shan"] }, { "cidx": [2290, 2292], "fullname": "西双版纳傣族自治州", "id": "532800", "location": { "lat": 22.00749, "lng": 100.79739 }, "name": "西双版纳", "pinyin": ["xi", "shuang", "ban", "na"] }, { "cidx": [2293, 2304], "fullname": "大理白族自治州", "id": "532900", "location": { "lat": 25.60648, "lng": 100.26764 }, "name": "大理", "pinyin": ["da", "li"] }, { "cidx": [2305, 2309], "fullname": "德宏傣族景颇族自治州", "id": "533100", "location": { "lat": 24.43232, "lng": 98.58486 }, "name": "德宏", "pinyin": ["de", "hong"] }, { "cidx": [2310, 2313], "fullname": "怒江傈僳族自治州", "id": "533300", "location": { "lat": 25.81763, "lng": 98.8567 }, "name": "怒江", "pinyin": ["nu", "jiang"] }, { "cidx": [2314, 2316], "fullname": "迪庆藏族自治州", "id": "533400", "location": { "lat": 27.81908, "lng": 99.70305 }, "name": "迪庆", "pinyin": ["di", "qing"] }, { "cidx": [2317, 2324], "fullname": "拉萨市", "id": "540100", "location": { "lat": 29.64415, "lng": 91.1145 }, "name": "拉萨", "pinyin": ["la", "sa"] }, { "cidx": [2325, 2342], "fullname": "日喀则市", "id": "540200", "location": { "lat": 29.26705, "lng": 88.88116 }, "name": "日喀则", "pinyin": ["ri", "ka", "ze"] }, { "cidx": [2343, 2353], "fullname": "昌都市", "id": "540300", "location": { "lat": 31.14073, "lng": 97.17225 }, "name": "昌都", "pinyin": ["chang", "du"] }, { "cidx": [2354, 2360], "fullname": "林芝市", "id": "540400", "location": { "lat": 29.64895, "lng": 94.36155 }, "name": "林芝", "pinyin": ["lin", "zhi"] }, { "cidx": [2361, 2372], "fullname": "山南市", "id": "540500", "location": { "lat": 29.23705, "lng": 91.77313 }, "name": "山南", "pinyin": ["shan", "nan"] }, { "cidx": [2373, 2383], "fullname": "那曲市", "id": "540600", "location": { "lat": 31.47614, "lng": 92.05136 }, "name": "那曲", "pinyin": ["na", "qu"] }, { "cidx": [2384, 2390], "fullname": "阿里地区", "id": "542500", "location": { "lat": 30.40051, "lng": 81.1454 }, "name": "阿里", "pinyin": ["a", "li"] }, { "cidx": [2391, 2403], "fullname": "西安市", "id": "610100", "location": { "lat": 34.34127, "lng": 108.93984 }, "name": "西安", "pinyin": ["xi", "an"] }, { "cidx": [2404, 2407], "fullname": "铜川市", "id": "610200", "location": { "lat": 34.89673, "lng": 108.94515 }, "name": "铜川", "pinyin": ["tong", "chuan"] }, { "cidx": [2408, 2419], "fullname": "宝鸡市", "id": "610300", "location": { "lat": 34.36194, "lng": 107.23732 }, "name": "宝鸡", "pinyin": ["bao", "ji"] }, { "cidx": [2420, 2433], "fullname": "咸阳市", "id": "610400", "location": { "lat": 34.32932, "lng": 108.70929 }, "name": "咸阳", "pinyin": ["xian", "yang"] }, { "cidx": [2434, 2444], "fullname": "渭南市", "id": "610500", "location": { "lat": 34.49997, "lng": 109.51015 }, "name": "渭南", "pinyin": ["wei", "nan"] }, { "cidx": [2445, 2457], "fullname": "延安市", "id": "610600", "location": { "lat": 36.58529, "lng": 109.48978 }, "name": "延安", "pinyin": ["yan", "an"] }, { "cidx": [2458, 2468], "fullname": "汉中市", "id": "610700", "location": { "lat": 33.06761, "lng": 107.02377 }, "name": "汉中", "pinyin": ["han", "zhong"] }, { "cidx": [2469, 2480], "fullname": "榆林市", "id": "610800", "location": { "lat": 38.2852, "lng": 109.73458 }, "name": "榆林", "pinyin": ["yu", "lin"] }, { "cidx": [2481, 2490], "fullname": "安康市", "id": "610900", "location": { "lat": 32.68486, "lng": 109.02932 }, "name": "安康", "pinyin": ["an", "kang"] }, { "cidx": [2491, 2497], "fullname": "商洛市", "id": "611000", "location": { "lat": 33.87036, "lng": 109.94041 }, "name": "商洛", "pinyin": ["shang", "luo"] }, { "cidx": [2498, 2505], "fullname": "兰州市", "id": "620100", "location": { "lat": 36.06138, "lng": 103.83417 }, "name": "兰州", "pinyin": ["lan", "zhou"] }, { "cidx": [2506, 2506], "fullname": "嘉峪关市", "id": "620200", "location": { "lat": 39.77194, "lng": 98.28971 }, "name": "嘉峪关", "pinyin": ["jia", "yu", "guan"] }, { "cidx": [2507, 2508], "fullname": "金昌市", "id": "620300", "location": { "lat": 38.52006, "lng": 102.18759 }, "name": "金昌", "pinyin": ["jin", "chang"] }, { "cidx": [2509, 2513], "fullname": "白银市", "id": "620400", "location": { "lat": 36.5447, "lng": 104.13773 }, "name": "白银", "pinyin": ["bai", "yin"] }, { "cidx": [2514, 2520], "fullname": "天水市", "id": "620500", "location": { "lat": 34.58085, "lng": 105.72486 }, "name": "天水", "pinyin": ["tian", "shui"] }, { "cidx": [2521, 2524], "fullname": "武威市", "id": "620600", "location": { "lat": 37.9282, "lng": 102.63797 }, "name": "武威", "pinyin": ["wu", "wei"] }, { "cidx": [2525, 2530], "fullname": "张掖市", "id": "620700", "location": { "lat": 38.92592, "lng": 100.44981 }, "name": "张掖", "pinyin": ["zhang", "ye"] }, { "cidx": [2531, 2537], "fullname": "平凉市", "id": "620800", "location": { "lat": 35.54303, "lng": 106.6653 }, "name": "平凉", "pinyin": ["ping", "liang"] }, { "cidx": [2538, 2544], "fullname": "酒泉市", "id": "620900", "location": { "lat": 39.73255, "lng": 98.49394 }, "name": "酒泉", "pinyin": ["jiu", "quan"] }, { "cidx": [2545, 2552], "fullname": "庆阳市", "id": "621000", "location": { "lat": 35.70978, "lng": 107.64292 }, "name": "庆阳", "pinyin": ["qing", "yang"] }, { "cidx": [2553, 2559], "fullname": "定西市", "id": "621100", "location": { "lat": 35.58113, "lng": 104.62524 }, "name": "定西", "pinyin": ["ding", "xi"] }, { "cidx": [2560, 2568], "fullname": "陇南市", "id": "621200", "location": { "lat": 33.401, "lng": 104.92166 }, "name": "陇南", "pinyin": ["long", "nan"] }, { "cidx": [2569, 2576], "fullname": "临夏回族自治州", "id": "622900", "location": { "lat": 35.60122, "lng": 103.21091 }, "name": "临夏", "pinyin": ["lin", "xia"] }, { "cidx": [2577, 2584], "fullname": "甘南藏族自治州", "id": "623000", "location": { "lat": 34.98327, "lng": 102.91102 }, "name": "甘南", "pinyin": ["gan", "nan"] }, { "cidx": [2585, 2591], "fullname": "西宁市", "id": "630100", "location": { "lat": 36.61729, "lng": 101.77782 }, "name": "西宁", "pinyin": ["xi", "ning"] }, { "cidx": [2592, 2597], "fullname": "海东市", "id": "630200", "location": { "lat": 36.48209, "lng": 102.40173 }, "name": "海东", "pinyin": ["hai", "dong"] }, { "cidx": [2598, 2601], "fullname": "海北藏族自治州", "id": "632200", "location": { "lat": 36.95454, "lng": 100.90096 }, "name": "海北", "pinyin": ["hai", "bei"] }, { "cidx": [2602, 2605], "fullname": "黄南藏族自治州", "id": "632300", "location": { "lat": 35.51991, "lng": 102.01507 }, "name": "黄南", "pinyin": ["huang", "nan"] }, { "cidx": [2606, 2610], "fullname": "海南藏族自治州", "id": "632500", "location": { "lat": 36.28663, "lng": 100.62037 }, "name": "海南", "pinyin": ["hai", "nan"] }, { "cidx": [2611, 2616], "fullname": "果洛藏族自治州", "id": "632600", "location": { "lat": 34.47141, "lng": 100.24475 }, "name": "果洛", "pinyin": ["guo", "luo"] }, { "cidx": [2617, 2622], "fullname": "玉树藏族自治州", "id": "632700", "location": { "lat": 33.00528, "lng": 97.0065 }, "name": "玉树", "pinyin": ["yu", "shu"] }, { "cidx": [2623, 2629], "fullname": "海西蒙古族藏族自治州", "id": "632800", "location": { "lat": 37.3771, "lng": 97.37122 }, "name": "海西", "pinyin": ["hai", "xi"] }, { "cidx": [2630, 2635], "fullname": "银川市", "id": "640100", "location": { "lat": 38.48644, "lng": 106.23248 }, "name": "银川", "pinyin": ["yin", "chuan"] }, { "cidx": [2636, 2638], "fullname": "石嘴山市", "id": "640200", "location": { "lat": 38.9841, "lng": 106.38418 }, "name": "石嘴山", "pinyin": ["shi", "zui", "shan"] }, { "cidx": [2639, 2643], "fullname": "吴忠市", "id": "640300", "location": { "lat": 37.99755, "lng": 106.19879 }, "name": "吴忠", "pinyin": ["wu", "zhong"] }, { "cidx": [2644, 2648], "fullname": "固原市", "id": "640400", "location": { "lat": 36.0158, "lng": 106.24259 }, "name": "固原", "pinyin": ["gu", "yuan"] }, { "cidx": [2649, 2651], "fullname": "中卫市", "id": "640500", "location": { "lat": 37.50026, "lng": 105.19676 }, "name": "中卫", "pinyin": ["zhong", "wei"] }, { "cidx": [2652, 2659], "fullname": "乌鲁木齐市", "id": "650100", "location": { "lat": 43.82663, "lng": 87.61688 }, "name": "乌鲁木齐", "pinyin": ["wu", "lu", "mu", "qi"] }, { "cidx": [2660, 2663], "fullname": "克拉玛依市", "id": "650200", "location": { "lat": 45.57999, "lng": 84.88927 }, "name": "克拉玛依", "pinyin": ["ke", "la", "ma", "yi"] }, { "cidx": [2664, 2666], "fullname": "吐鲁番市", "id": "650400", "location": { "lat": 42.9513, "lng": 89.18954 }, "name": "吐鲁番", "pinyin": ["tu", "lu", "fan"] }, { "cidx": [2667, 2669], "fullname": "哈密市", "id": "650500", "location": { "lat": 42.81855, "lng": 93.51538 }, "name": "哈密", "pinyin": ["ha", "mi"] }, { "cidx": [2670, 2676], "fullname": "昌吉回族自治州", "id": "652300", "location": { "lat": 44.01117, "lng": 87.30822 }, "name": "昌吉", "pinyin": ["chang", "ji"] }, { "cidx": [2677, 2680], "fullname": "博尔塔拉蒙古自治州", "id": "652700", "location": { "lat": 44.90597, "lng": 82.06665 }, "name": "博州", "pinyin": ["bo", "zhou"] }, { "cidx": [2681, 2689], "fullname": "巴音郭楞蒙古自治州", "id": "652800", "location": { "lat": 41.76404, "lng": 86.14517 }, "name": "巴州", "pinyin": ["ba", "zhou"] }, { "cidx": [2690, 2698], "fullname": "阿克苏地区", "id": "652900", "location": { "lat": 41.16842, "lng": 80.26008 }, "name": "阿克苏", "pinyin": ["a", "ke", "su"] }, { "cidx": [2699, 2702], "fullname": "克孜勒苏柯尔克孜自治州", "id": "653000", "location": { "lat": 39.7153, "lng": 76.16661 }, "name": "克州", "pinyin": ["ke", "zhou"] }, { "cidx": [2703, 2714], "fullname": "喀什地区", "id": "653100", "location": { "lat": 39.47042, "lng": 75.98976 }, "name": "喀什", "pinyin": ["ka", "shi"] }, { "cidx": [2715, 2722], "fullname": "和田地区", "id": "653200", "location": { "lat": 37.11431, "lng": 79.92247 }, "name": "和田", "pinyin": ["he", "tian"] }, { "cidx": [2723, 2733], "fullname": "伊犁哈萨克自治州", "id": "654000", "location": { "lat": 43.91689, "lng": 81.32416 }, "name": "伊犁", "pinyin": ["yi", "li"] }, { "cidx": [2734, 2740], "fullname": "塔城地区", "id": "654200", "location": { "lat": 46.74532, "lng": 82.98046 }, "name": "塔城", "pinyin": ["ta", "cheng"] }, { "cidx": [2741, 2747], "fullname": "阿勒泰地区", "id": "654300", "location": { "lat": 47.84564, "lng": 88.14023 }, "name": "阿勒泰", "pinyin": ["a", "le", "tai"] }, { "fullname": "石河子市", "id": "659001", "location": { "lat": 44.30653, "lng": 86.07893 }, "name": "石河子", "pinyin": ["shi", "he", "zi"] }, { "fullname": "阿拉尔市", "id": "659002", "location": { "lat": 40.54798, "lng": 81.28067 }, "name": "阿拉尔", "pinyin": ["a", "la", "er"] }, { "fullname": "图木舒克市", "id": "659003", "location": { "lat": 39.86495, "lng": 79.06902 }, "name": "图木舒克", "pinyin": ["tu", "mu", "shu", "ke"] }, { "fullname": "五家渠市", "id": "659004", "location": { "lat": 44.16799, "lng": 87.54017 }, "name": "五家渠", "pinyin": ["wu", "jia", "qu"] }, { "fullname": "北屯市", "id": "659005", "location": { "lat": 47.36327, "lng": 87.80014 }, "name": "北屯", "pinyin": ["bei", "tun"] }, { "fullname": "铁门关市", "id": "659006", "location": { "lat": 41.86868, "lng": 85.67583 }, "name": "铁门关", "pinyin": ["tie", "men", "guan"] }, { "fullname": "双河市", "id": "659007", "location": { "lat": 44.84418, "lng": 82.35501 }, "name": "双河", "pinyin": ["shuang", "he"] }, { "fullname": "可克达拉市", "id": "659008", "location": { "lat": 43.94799, "lng": 81.04476 }, "name": "可克达拉", "pinyin": ["ke", "ke", "da", "la"] }, { "fullname": "昆玉市", "id": "659009", "location": { "lat": 37.20948, "lng": 79.29133 }, "name": "昆玉", "pinyin": ["kun", "yu"] }, { "cidx": [2748, 2759], "fullname": "台北市", "id": "710100", "location": { "lat": 25.030724, "lng": 121.520076 }, "name": "台北", "pinyin": ["tai", "bei"] }, { "cidx": [2760, 2797], "fullname": "高雄市", "id": "710200", "location": { "lat": 22.630576, "lng": 120.306839 }, "name": "高雄", "pinyin": ["gao", "xiong"] }, { "cidx": [2798, 2834], "fullname": "台南市", "id": "710300", "location": { "lat": 22.998601, "lng": 120.187817 }, "name": "台南", "pinyin": ["tai", "nan"] }, { "cidx": [2835, 2863], "fullname": "台中市", "id": "710400", "location": { "lat": 24.143171, "lng": 120.679882 }, "name": "台中", "pinyin": ["tai", "zhong"] }, { "cidx": [2864, 2876], "fullname": "南投县", "id": "710600", "location": { "lat": 23.919619, "lng": 120.670008 }, "name": "南投", "pinyin": ["nan", "tou"] }, { "cidx": [2877, 2883], "fullname": "基隆市", "id": "710700", "location": { "lat": 25.122105, "lng": 121.741526 }, "name": "基隆", "pinyin": ["ji", "long"] }, { "cidx": [2884, 2886], "fullname": "新竹市", "id": "710800", "location": { "lat": 24.784924, "lng": 120.990745 }, "name": "新竹", "pinyin": ["xin", "zhu"] }, { "cidx": [2887, 2888], "fullname": "嘉义市", "id": "710900", "location": { "lat": 23.485079, "lng": 120.472462 }, "name": "嘉义", "pinyin": ["jia", "yi"] }, { "cidx": [2889, 2917], "fullname": "新北市", "id": "711100", "location": { "lat": 25.1853, "lng": 121.663675 }, "name": "新北", "pinyin": ["xin", "bei"] }, { "cidx": [2918, 2929], "fullname": "宜兰县", "id": "711200", "location": { "lat": 24.759707, "lng": 121.754442 }, "name": "宜兰", "pinyin": ["yi", "lan"] }, { "cidx": [2930, 2942], "fullname": "新竹县", "id": "711300", "location": { "lat": 24.839233, "lng": 121.002012 }, "name": "新竹", "pinyin": ["xin", "zhu"] }, { "cidx": [2943, 2955], "fullname": "桃园市", "id": "711400", "location": { "lat": 24.982757, "lng": 121.213608 }, "name": "桃园", "pinyin": ["tao", "yuan"] }, { "cidx": [2956, 2973], "fullname": "苗栗县", "id": "711500", "location": { "lat": 24.696762, "lng": 120.884337 }, "name": "苗栗", "pinyin": ["miao", "li"] }, { "cidx": [2974, 2999], "fullname": "彰化县", "id": "711700", "location": { "lat": 24.068523, "lng": 120.557479 }, "name": "彰化", "pinyin": ["zhang", "hua"] }, { "cidx": [3000, 3017], "fullname": "嘉义县", "id": "711900", "location": { "lat": 23.434473, "lng": 120.624255 }, "name": "嘉义", "pinyin": ["jia", "yi"] }, { "cidx": [3018, 3037], "fullname": "云林县", "id": "712100", "location": { "lat": 23.664943, "lng": 120.480738 }, "name": "云林", "pinyin": ["yun", "lin"] }, { "cidx": [3038, 3070], "fullname": "屏东县", "id": "712400", "location": { "lat": 22.666716, "lng": 120.492005 }, "name": "屏东", "pinyin": ["ping", "dong"] }, { "cidx": [3071, 3086], "fullname": "台东县", "id": "712500", "location": { "lat": 22.764364, "lng": 121.113207 }, "name": "台东", "pinyin": ["tai", "dong"] }, { "cidx": [3087, 3099], "fullname": "花莲县", "id": "712600", "location": { "lat": 24.000674, "lng": 121.59729 }, "name": "花莲", "pinyin": ["hua", "lian"] }, { "cidx": [3100, 3105], "fullname": "澎湖县", "id": "712700", "location": { "lat": 23.552351, "lng": 119.58457 }, "name": "澎湖", "pinyin": ["peng", "hu"] }, { "fullname": "中西区", "id": "810101", "location": { "lat": 22.27629, "lng": 114.16368 }, "name": "中西区", "pinyin": ["zhong", "xi", "qu"] }, { "fullname": "东区", "id": "810102", "location": { "lat": 22.28137, "lng": 114.22914 }, "name": "东区", "pinyin": ["dong", "qu"] }, { "fullname": "九龙城区", "id": "810103", "location": { "lat": 22.30818, "lng": 114.18895 }, "name": "九龙", "pinyin": ["jiu", "long"] }, { "fullname": "观塘区", "id": "810104", "location": { "lat": 22.31057, "lng": 114.2306 }, "name": "观塘区", "pinyin": ["guan", "tang", "qu"] }, { "fullname": "南区", "id": "810105", "location": { "lat": 22.24543, "lng": 114.15806 }, "name": "南区", "pinyin": ["nan", "qu"] }, { "fullname": "深水埗区", "id": "810106", "location": { "lat": 22.32921, "lng": 114.16856 }, "name": "深水埗区", "pinyin": ["shen", "shui", "bu", "qu"] }, { "fullname": "湾仔区", "id": "810107", "location": { "lat": 22.27469, "lng": 114.17778 }, "name": "湾仔区", "pinyin": ["wan", "zi", "qu"] }, { "fullname": "黄大仙区", "id": "810108", "location": { "lat": 22.34003, "lng": 114.19584 }, "name": "黄大仙区", "pinyin": ["huang", "da", "xian", "qu"] }, { "fullname": "油尖旺区", "id": "810109", "location": { "lat": 22.31898, "lng": 114.17738 }, "name": "油尖旺区", "pinyin": ["you", "jian", "wang", "qu"] }, { "fullname": "离岛区", "id": "810110", "location": { "lat": 22.2817, "lng": 113.94691 }, "name": "离岛区", "pinyin": ["li", "dao", "qu"] }, { "fullname": "葵青区", "id": "810111", "location": { "lat": 22.36055, "lng": 114.13654 }, "name": "葵青区", "pinyin": ["kui", "qing", "qu"] }, { "fullname": "北区", "id": "810112", "location": { "lat": 22.49181, "lng": 114.14312 }, "name": "北区", "pinyin": ["bei", "qu"] }, { "fullname": "西贡区", "id": "810113", "location": { "lat": 22.37943, "lng": 114.27699 }, "name": "西贡区", "pinyin": ["xi", "gong", "qu"] }, { "fullname": "沙田区", "id": "810114", "location": { "lat": 22.3827, "lng": 114.19191 }, "name": "沙田区", "pinyin": ["sha", "tian", "qu"] }, { "fullname": "屯门区", "id": "810115", "location": { "lat": 22.38767, "lng": 113.98029 }, "name": "屯门区", "pinyin": ["tun", "men", "qu"] }, { "fullname": "大埔区", "id": "810116", "location": { "lat": 22.448, "lng": 114.16946 }, "name": "大埔区", "pinyin": ["da", "pu", "qu"] }, { "fullname": "荃湾区", "id": "810117", "location": { "lat": 22.37145, "lng": 114.12001 }, "name": "荃湾区", "pinyin": ["quan", "wan", "qu"] }, { "fullname": "元朗区", "id": "810118", "location": { "lat": 22.44243, "lng": 114.03181 }, "name": "元朗区", "pinyin": ["yuan", "lang", "qu"] }, { "fullname": "澳门半岛", "id": "820101", "location": { "lat": 22.18684, "lng": 113.54294 }, "name": "澳门半岛", "pinyin": ["ao", "men", "ban", "dao"] }, { "fullname": "凼仔", "id": "820102", "location": { "lat": 22.15473, "lng": 113.55929 }, "name": "凼仔", "pinyin": ["dang", "zi"] }, { "fullname": "路凼城", "id": "820103", "location": { "lat": 22.13867, "lng": 113.56828 }, "name": "路凼城", "pinyin": ["lu", "dang", "cheng"] }, { "fullname": "路环", "id": "820104", "location": { "lat": 22.11501, "lng": 113.55724 }, "name": "路环", "pinyin": ["lu", "huan"] }]

================================================
FILE: examples/address-book/pages/index/index.js
================================================
import {cityData} from './data'

Component({
  data: {
    list: [],
  },
  lifetimes: {
    attached() {
      const cities = cityData
      // 按拼音排序
      cities.sort((c1, c2) => {
        const pinyin1 = c1.pinyin.join('')
        const pinyin2 = c2.pinyin.join('')
        return pinyin1.localeCompare(pinyin2)
      })
      // 添加首字母
      const map = new Map()
      for (const city of cities) {
        const alpha = city.pinyin[0].charAt(0).toUpperCase()
        if (!map.has(alpha)) map.set(alpha, [])
        map.get(alpha).push({ name: city.fullname })
      }

      const keys = []
      for (const key of map.keys()) {
        keys.push(key)
      }
      keys.sort()

      const list = []
      for (const key of keys) {
        list.push({
          alpha: key,
          subItems: map.get(key)
        })
      }

      console.log('address-book list:', list)
      this.setData({ list })
    },
  },
})


================================================
FILE: examples/address-book/pages/index/index.json
================================================
{
  "usingComponents": {
    "navigation-bar": "../../components/navigation-bar",
    "address-book": "../../components/address-book"
  },
  "disableScroll": true,
  "navigationStyle": "custom"
}

================================================
FILE: examples/address-book/pages/index/index.wxml
================================================
<navigation-bar title="通讯录" back="{{true}}"></navigation-bar>
<view class="page-container">
  <address-book list="{{list}}">
    <view class="page">
      <view class="page__hd">
        <view class="page__title">Address Book</view>
        <view class="page__desc">类通讯录列表</view>
      </view>
      <view class="page__bd">
      </view>
    </view>
  </address-book>
</view>


================================================
FILE: examples/address-book/pages/index/index.wxss
================================================
page {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  height: 100vh;
  background-color: #f7f7f7;
}

.page-container {
  width: 100vw;
  flex: 1;
  overflow: hidden;
}

.page {
  color: rgba(0, 0, 0, .9);
  font-size: 16px;
  font-family: -apple-system-font, Helvetica Neue, Helvetica, sans-serif;
}

.page__hd {
  padding: 40px
}

.page__bd {
  padding-bottom: 40px
}

.page__title {
  text-align: left;
  font-size: 20px;
  font-weight: 400
}

.page__desc {
  margin-top: 5px;
  color: rgba(0, 0, 0, .5);
  text-align: left;
  font-size: 14px
}

.header {
  height: 100px;
}

.cell {
  height: 50px; 
  justify-content: center;
  align-items: center;
}

================================================
FILE: examples/address-book/project.config.json
================================================
{
  "appid": "wxe5f52902cf4de896",
  "compileType": "miniprogram",
  "libVersion": "latest",
  "packOptions": {
    "ignore": [],
    "include": []
  },
  "setting": {
    "coverView": true,
    "es6": true,
    "postcss": true,
    "minified": true,
    "enhance": true,
    "showShadowRootInWxmlPanel": true,
    "packNpmRelationList": [],
    "babelSetting": {
      "ignore": [],
      "disablePlugins": [],
      "outputPath": ""
    },
    "condition": false,
    "skylineRenderEnable": true,
    "compileWorklet": true
  },
  "condition": {},
  "editorSetting": {
    "tabIndent": "insertSpaces",
    "tabSize": 2
  },
  "projectname": "address-book"
}

================================================
FILE: examples/address-book/project.private.config.json
================================================
{
  "description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html",
  "projectname": "address-book",
  "setting": {
    "compileHotReLoad": false,
    "skylineRenderEnable": true
  },
  "libVersion": "latest"
}

================================================
FILE: examples/address-book/sitemap.json
================================================
{
    "desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html",
    "rules": [{
    "action": "allow",
    "page": "*"
    }]
}

================================================
FILE: examples/album/app.js
================================================
App({})


================================================
FILE: examples/album/app.json
================================================
{
  "pages": [
    "pages/album/index",
    "pages/preview/index"
  ],
  "window": {
    "backgroundColor": "#ffffff",
    "backgroundTextStyle": "dark",
    "navigationBarBackgroundColor": "#ffffff",
    "navigationBarTitleText": "",
    "navigationBarTextStyle": "black"
  },
  "style": "v2",
  "sitemapLocation": "sitemap.json",
  "lazyCodeLoading": "requiredComponents",
  "componentFramework": "glass-easel",
  "renderer": "skyline",
  "rendererOptions": {
    "skyline": {
      "defaultDisplayBlock": true,
      "disableABTest": true,
      "sdkVersionBegin": "3.0.0",
      "sdkVersionEnd": "15.255.255"
    }
  }
}

================================================
FILE: examples/album/app.wxss
================================================


================================================
FILE: examples/album/components/album/album-image/index.js
================================================
import EventBus from '../../../utils/event-bus'
import { getShared, getRunOnUI } from '../../../utils/worklet'

const IMAGE_INIT_WIDTH = 0
const IMAGE_INIT_HEIGHT = 1
const IMAGE_WIDTH = 2
const IMAGE_HEIGHT = 3
const IMAGE_TARGET_WIDTH = 4
const IMAGE_TARGET_HEIGHT = 5
const IMAGE_RATIO = 6
const IN_PREVIEW = 7

let screenWidth = 0
let screenHeight = 0

Component({
  properties: {
    image: {
      type: Object,
      value: {},
    },
    src: {
      type: String,
      value: '',
    },
    width: {
      type: Number,
      value: 0,
    },
    height: {
      type: Number,
      value: 0,
    },
  },

  observers: {
    'width, height'() {
      this.renderImage()
    },
  },

  lifetimes: {
    created() {
      const shared = getShared(this.renderer)

      this.sharedValues = [
        shared(0), // IMAGE_INIT_WIDTH
        shared(0), // IMAGE_INIT_HEIGHT
        shared(0), // IMAGE_WIDTH
        shared(0), // IMAGE_HEIGHT
        shared(0), // IMAGE_TARGET_WIDTH
        shared(0), // IMAGE_TARGET_HEIGHT
        shared(0), // IMAGE_RATIO
        shared(false), // IN_PREVIEW
      ]
    },

    attached() {
      const pageId = this.getPageId()
      const uniqueId = `${pageId}-${this.data.image.id}`
      const sharedValues = this.sharedValues ?? []
      this.uniqueId = uniqueId

      getRunOnUI(this.renderer)(() => {
        'worklet'
        if (!globalThis.temp[`${uniqueId}CustomRouteBack`]) {
          globalThis.temp[`${uniqueId}CustomRouteBack`] = args => {
            if (!sharedValues[IN_PREVIEW].value) return

            // 在预览页拖拽返回时会有 scale 效果,所以需要矫正第 0 帧时的宽高,不然会在切 share-element 时突然失去 scale 效果
            const targetImageWidth = sharedValues[IMAGE_TARGET_WIDTH].value
            const targetImageHeight = sharedValues[IMAGE_TARGET_HEIGHT].value
            const scale = args.scale
            sharedValues[IMAGE_WIDTH].value = targetImageWidth * scale
            sharedValues[IMAGE_HEIGHT].value = targetImageHeight * scale
          }
          globalThis.eventBus.on(`${pageId}CustomRouteBack`, globalThis.temp[`${uniqueId}CustomRouteBack`])
        }
      })()

      this.applyAnimatedStyle('.img', () => {
        'worklet'
        let width = `${sharedValues[IMAGE_WIDTH].value}px`
        if (sharedValues[IMAGE_WIDTH].value === 0) {
          width = ``
        }
        let height = `${sharedValues[IMAGE_HEIGHT].value}px`
        if (sharedValues[IMAGE_HEIGHT].value === 0) {
          height = ``
        }
        return {
          width,
          height,
        }
      })

      const resetShareValues = () => {
        sharedValues[IMAGE_WIDTH].value = sharedValues[IMAGE_INIT_WIDTH].value
        sharedValues[IMAGE_HEIGHT].value = sharedValues[IMAGE_INIT_HEIGHT].value
        sharedValues[IN_PREVIEW].value = false
      }

      // 监听预览页图片切换
      this._onPreviewerChange = image => {
        if (image.id === this.data.image.id) {
          // 切到当前图片了
          sharedValues[IN_PREVIEW].value = true
        } else {
          // 切到其他图片了,恢复原样
          resetShareValues()
        }
      }
      EventBus.on(`${pageId}PreviewerChange`, this._onPreviewerChange)

      this._onPreviewerHide = () => {
        // 预览页销毁了,恢复原样
        // 这里可能有返回动画,所以延迟 reset
        setTimeout(resetShareValues, 500)
      }
      EventBus.on(`${pageId}PreviewerDestroy`, this._onPreviewerHide)
    },

    detached() {
      const pageId = this.getPageId()
      const uniqueId = this.uniqueId
      getRunOnUI(this.renderer)(() => {
        'worklet'
        if (globalThis.temp[`${uniqueId}CustomRouteBack`]) {
          globalThis.eventBus.off(`${pageId}CustomRouteBack`, globalThis.temp[`${uniqueId}CustomRouteBack`])
          delete globalThis.temp[`${uniqueId}CustomRouteBack`]
        }
      })()

      EventBus.off(`${pageId}PreviewerChange`, this._onPreviewerChange)
      EventBus.off(`${pageId}PreviewerDestroy`, this._onPreviewerHide)
    },
  },

  methods: {
    onFrame(evt) {
      'worklet'
      console.log('worklet onFrame', evt)
      // 进入预览页的动画,会逐帧调用
      // 在此回调中需要根据当前容器的大小来调整图片的大小,因为图片是自己设置宽高渲染的,不能根据容器宽高自适应
      const rect = evt.current
      const sharedValues = this.sharedValues ?? []
      const cntWidth = rect.width
      const cntHeight = rect.height
      const progress = evt.progress // 当前动画进度
      const imageRatio = sharedValues[IMAGE_RATIO].value
      const isPop = evt.direction === 1

      let width = cntWidth
      let height = cntHeight
      if (imageRatio) {
        const cntRatio = cntWidth / cntHeight

        if (cntRatio > imageRatio) height = cntWidth / imageRatio
        else if (cntRatio <= imageRatio) width = cntHeight * imageRatio

        // 获取图片的初始大小和目标大小
        const initImageWidth = sharedValues[IMAGE_INIT_WIDTH].value
        const initImageHeight = sharedValues[IMAGE_INIT_HEIGHT].value
        const targetImageWidth = sharedValues[IMAGE_TARGET_WIDTH].value
        const targetImageHeight = sharedValues[IMAGE_TARGET_HEIGHT].value
        if (initImageWidth && initImageHeight && targetImageWidth && targetImageHeight) {
          if (isPop) {
            // 退出动画
            width = targetImageWidth - (targetImageWidth - initImageWidth) * progress
            height = targetImageHeight - (targetImageHeight - initImageHeight) * progress
          } else {
            // 进入动画
            width = initImageWidth + (targetImageWidth - initImageWidth) * progress
            height = initImageHeight + (targetImageHeight - initImageHeight) * progress
          }
        }
      }

      sharedValues[IMAGE_WIDTH].value = width
      sharedValues[IMAGE_HEIGHT].value = height
    },

    onImageLoad(evt) {
      const { width, height } = evt.detail
      const sharedValues = this.sharedValues ?? []
      const imageRatio = width / height

      this.imageRatio = imageRatio
      sharedValues[IMAGE_RATIO].value = imageRatio
      this.renderImage()
    },

    renderImage() {
      // 因为目标预览页的 mode 是 aspectFill,为了保证进入预览页的动画过程中不会发生 mode 跳变问题,故此处使用 aspectFill,然后手动裁剪成 aspectFit
      const sharedValues = this.sharedValues ?? []
      const { width: cntWidth, height: cntHeight } = this.data
      const imageRatio = this.imageRatio

      if (!screenWidth || !screenHeight) {
        const systemInfo = wx.getSystemInfoSync()
        screenWidth = systemInfo.screenWidth
        screenHeight = systemInfo.screenHeight
      }

      if (cntWidth && cntHeight && imageRatio) {
        let initWidth = cntWidth
        let initHeight = cntHeight
        let targetImageWidth = screenWidth
        let targetImageHeight = screenHeight
        const cntRatio = cntWidth / cntHeight
        const targetRatio = screenWidth / screenHeight

        if (cntRatio > imageRatio) {
          initHeight = cntWidth / imageRatio
        } else if (cntRatio < imageRatio) {
          initWidth = cntHeight * imageRatio
        }

        if (targetRatio > imageRatio) {
          targetImageWidth = targetImageHeight * imageRatio
        } else if (targetRatio < imageRatio) {
          targetImageHeight = targetImageWidth / imageRatio
        }

        // 在相册页面时的初始大小
        sharedValues[IMAGE_INIT_WIDTH].value = initWidth
        sharedValues[IMAGE_INIT_HEIGHT].value = initHeight

        // 当前图片的大小
        sharedValues[IMAGE_WIDTH].value = initWidth
        sharedValues[IMAGE_HEIGHT].value = initHeight

        // 动画到预览页时的目标大小
        sharedValues[IMAGE_TARGET_WIDTH].value = targetImageWidth
        sharedValues[IMAGE_TARGET_HEIGHT].value = targetImageHeight
      }
    },
  },
})


================================================
FILE: examples/album/components/album/album-image/index.json
================================================
{
  "component": true,
  "usingComponents": {},
  "componentFramework": "glass-easel"
}

================================================
FILE: examples/album/components/album/album-image/index.wxml
================================================
<share-element class="share-element" key="{{image.id}}" rect-tween-type="cubic-bezier(0.4, 0, 0.2, 1.0)" worklet:onframe="onFrame">
  <view class="img-cut-cnt">
    <image class="img" src="{{src}}" mode="aspectFill" bindload="onImageLoad"></image>
  </view>
</share-element>


================================================
FILE: examples/album/components/album/album-image/index.wxss
================================================
.share-element {
  position: relative;
  width: 100%;
  height: 100%;
}

.img-cut-cnt {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: transparent;
  overflow: hidden;
}

.img {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 100%;
  height: 100%;
  transform: translate(-50%, -50%);
  transform-origin: center;
  z-index: 5;
}


================================================
FILE: examples/album/components/album/index.js
================================================
import EventBus from '../../utils/event-bus'
import { initRoute } from './route'

function transformListToLineBlock(list, lineLimit) {
  const lineList = []
  for (let i = 0, len = list.length; i < len; i += lineLimit) {
    const line = { index: Math.floor(i / lineLimit), list: [] }
    for (let j = 0; j < lineLimit; j++) {
      const index = i + j
      const item = list[index]
      if (item) line.list.push({
        ...item,
        index,
      })
    }
    lineList.push(line)
  }
  return lineList
}

Component({
  properties: {
    list: {
      type: Array,
      value: [],
    },

    imageWidth: {
      type: Number,
      value: 0,
    },

    imageMargin: {
      type: Number,
      value: 0,
    },

    lineLimit: {
      type: Number,
      value: 3,
    },
  },

  data: {
    showList: [],
    scrollIntoView: '',
  },

  observers: {
    'list, lineLimit'(list, lineLimit) {
      if (!list.length || !lineLimit) return

      // 调整为行结构,每行自己排版
      this.setData({
        showList: transformListToLineBlock(list, lineLimit),
      })
    },
  },

  lifetimes: {
    created() {
      EventBus.initWorkletEventBus(this.renderer) // 初始化 ui 线程的 eventBus
      initRoute() // 初始化自定义路由
    },

    attached() {
      // 预览页发生图片切换时,要将对应 image 滚动到到可视范围内
      const pageId = this.getPageId()
      let scrollIntoViewTimer = null
      this._onPreviewerChange = image => {
        const list = this.data.list
        const index = list.findIndex(item => item.id === image.id)
  
        if (index !== -1) {
          if (scrollIntoViewTimer) clearTimeout(scrollIntoViewTimer)
          scrollIntoViewTimer = setTimeout(() => {
            // 可能处于页面切换动画中,故加个延迟再滚动
            let lineIndex = Math.floor(index / this.data.lineLimit)
            this.setData({ scrollIntoView: `line-${lineIndex}` })
          }, 500)
        }
      }
      EventBus.on(`${pageId}PreviewerChange`, this._onPreviewerChange)
    },

    detached() {
      const pageId = this.getPageId()
      EventBus.off(`${pageId}PreviewerChange`, this._onPreviewerChange)
    },
  },

  methods: {
    onTapImage(evt) {
      const { index } = evt.currentTarget.dataset || {}
      const image = this.data.list[index]
      if (!image) return

      // 跳转到预览页
      wx.navigateTo({
        url: `../../pages/preview/index?imageid=${image.id}&sourcepageid=${this.getPageId()}`,
        routeType: 'fadeToggle',
      })
    },
  },
})


================================================
FILE: examples/album/components/album/index.json
================================================
{
  "component": true,
  "usingComponents": {
    "album-image": "./album-image/index"
  },
  "componentFramework": "glass-easel"
}

================================================
FILE: examples/album/components/album/index.wxml
================================================
  <scroll-view
    class="scroll-list"
    style="padding-top: {{imageMargin}}px;"
    scroll-y
    type="list"
    scroll-into-view="{{scrollIntoView}}"
    scroll-into-view-alignment="nearest"
  >
    <view
      wx:for="{{showList}}"
      wx:key="index"
      wx:for-item="line"
      id="line-{{index}}"
      class="line"
      style="padding-bottom: {{imageMargin}}px;"
    >
      <view wx:for="{{line.list}}" wx:key="id" style="width: {{imageWidth}}px; height: {{imageWidth}}px; margin-left: {{imageMargin}}px;">
        <album-image
          class="album-image"
          image="{{item}}"
          src="{{item.src}}"
          width="{{imageWidth}}"
          height="{{imageWidth}}"
          data-index="{{item.index}}"
          bindtap="onTapImage"
        ></album-image>
      </view>
    </view>
  </scroll-view>

================================================
FILE: examples/album/components/album/index.wxss
================================================
.scroll-list {
  width: 100%;
  height: 100%;
  overflow: hidden;
}

.line {
  display: flex;
  flex-direction: row;
  justify-content: flex-start;
}

.album-image {
  width: 100%;
  height: 100%;
}


================================================
FILE: examples/album/components/album/route.js
================================================
const fastOutSlowIn = wx.worklet.Easing.bezier(0.4, 0.0, 0.2, 1.0).factory()

export function initRoute() {
  wx.router.addRouteBuilder('fadeToggle', ({ primaryAnimation }) => {
    const handlePrimaryAnimation = () => {
      'worklet'
      return {
        opacity: fastOutSlowIn(primaryAnimation.value),
      }
    }

    return {
      opaque: false,
      handlePrimaryAnimation,
      transitionDuration: 300,
      reverseTransitionDuration: 300,
      canTransitionTo: false,
      canTransitionFrom: false,
    }
  })
}


================================================
FILE: examples/album/components/navigation-bar/index.js
================================================
Component({
  options: {
    multipleSlots: true // 在组件定义时的选项中启用多slot支持
  },
  /**
   * 组件的属性列表
   */
  properties: {
    extClass: {
      type: String,
      value: ''
    },
    title: {
      type: String,
      value: ''
    },
    background: {
      type: String,
      value: ''
    },
    color: {
      type: String,
      value: ''
    },
    back: {
      type: Boolean,
      value: true
    },
    loading: {
      type: Boolean,
      value: false
    },
    animated: {
      // 显示隐藏的时候opacity动画效果
      type: Boolean,
      value: true
    },
    show: {
      // 显示隐藏导航,隐藏的时候navigation-bar的高度占位还在
      type: Boolean,
      value: true,
      observer: '_showChange'
    },
    // back为true的时候,返回的页面深度
    delta: {
      type: Number,
      value: 1
    }
  },
  /**
   * 组件的初始数据
   */
  data: {
    displayStyle: ''
  },
  attached() {
    const rect = wx.getMenuButtonBoundingClientRect()
    wx.getSystemInfo({
      success: (res) => {
        this.setData({
          statusBarHeight: res.statusBarHeight,
          innerPaddingRight: `padding-right:${res.windowWidth - rect.left}px`,
          leftWidth: `width:${res.windowWidth - rect.left}px`,
          navBarHeight: rect.bottom + rect.top - res.statusBarHeight,
        })
      }
    })
  },
  /**
   * 组件的方法列表
   */
  methods: {
    _showChange(show) {
      const animated = this.data.animated
      let displayStyle = ''
      if (animated) {
        displayStyle = `opacity: ${show ? '1' : '0'};transition: opacity 0.5s;`
      } else {
        displayStyle = `display: ${show ? '' : 'none'}`
      }
      this.setData({
        displayStyle
      })
    },
    back() {
      const data = this.data
      if (data.delta) {
        wx.navigateBack({
          delta: data.delta
        })
      }
      this.triggerEvent('back', { delta: data.delta }, {})
    }
  }
})


================================================
FILE: examples/album/components/navigation-bar/index.json
================================================
{
  "component": true,
  "usingComponents": {},
  "addGlobalClass": true,
  "componentFramework": "glass-easel"
}

================================================
FILE: examples/album/components/navigation-bar/index.wxml
================================================
<view class="weui-navigation-bar {{extClass}}">
  <view class="weui-navigation-bar__inner" style="padding-top: {{statusBarHeight}}px; height: {{navBarHeight}}px; color: {{color}}; background: {{background}}; {{displayStyle}}; {{innerPaddingRight}};">
    <view class='weui-navigation-bar__left' style="{{leftWidth}}">
      <block wx:if="{{back}}">
        <view class="weui-navigation-bar__buttons">
          <view bindtap="back" class="weui-navigation-bar__btn_goback_wrapper" hover-class="weui-active" aria-role="button" aria-label="返回">
            <view class="weui-navigation-bar__button weui-navigation-bar__btn_goback"></view>
          </view>
        </view>
      </block>
      <block wx:else>
        <slot name="left"></slot>
      </block>
    </view>

    <view class='weui-navigation-bar__center'>
      <view wx:if="{{loading}}" class="weui-navigation-bar__loading" aria-role="alert">
        <view class="weui-loading" style="width:{{size.width}}rpx;height:{{size.height}}rpx;" aria-role="img" aria-label="加载中"></view>
      </view>
      <block wx:if="{{title}}">
        <text>{{title}}</text>
      </block>
      <block wx:else>
        <slot name="center"></slot>
      </block>
    </view>

    <view class='weui-navigation-bar__right'>
      <slot name="right"></slot>
    </view>
  </view>
</view>


================================================
FILE: examples/album/components/navigation-bar/index.wxss
================================================
.weui-navigation-bar {
  overflow: hidden;
  color: rgba(0, 0, 0, .9);
  width: 100vw;
}

.weui-navigation-bar__placeholder {
  background: #f7f7f7;
  position: relative;
}

.weui-navigation-bar__inner, .weui-navigation-bar__inner .weui-navigation-bar__left {
  display: flex;
  align-items: center;
  flex-direction: row;
}

.weui-navigation-bar__inner {
  position: relative;
  padding-right: 95px;
  width: 100vw;
  box-sizing: border-box;
}

.weui-navigation-bar__inner .weui-navigation-bar__left {
  position: relative;
  width: 95px;
  padding-left: 16px;
  box-sizing: border-box;
}

.weui-navigation-bar__btn_goback_wrapper {
  padding: 11px 18px 11px 16px;
  margin: -11px -18px -11px -16px;
}

.weui-navigation-bar__inner .weui-navigation-bar__left .weui-navigation-bar__btn_goback {
  font-size: 12px;
  width: 12px;
  height: 24px;
  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%;
  background-size: cover;
}

.weui-navigation-bar__inner .weui-navigation-bar__center {
  font-size: 17px;
  text-align: center;
  position: relative;
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  font-weight: bold;
}

@media(prefers-color-scheme: dark) {
  .weui-navigation-bar {
    color: hsla(0, 0%, 100%, .8);
  }
  .weui-navigation-bar__inner {
    background-color: #1f1f1f;
  }
}


================================================
FILE: examples/album/components/previewer/index.js
================================================
import EventBus from '../../utils/event-bus'
import { getShared, getTiming, getRunOnUI } from '../../utils/worklet'

const PreviewerGesture = {
  Init: 0, // 初始
  Moving: 1, // 移动图片
  Toggle: 2, // 切换图片
  Back: 3, // 退出页面
}

const PrimaryAnimationStatus = {
  DISMISSED: 0,
  FORWARD: 1,
  REVERSE: 2,
  COMPLETED: 3,
}

const GestureState = {
  POSSIBLE: 0,
  BEGIN: 1,
  ACTIVE: 2,
  END: 3,
  CANCELLED: 4,
}

// sharedValues
const TRANSLATE_X = 0
const TRANSLATE_Y = 1
const START_Y = 2
const OPACITY = 3
const SCALE = 4
const MIN_SCALE = 5
const USER_GESTURE_IN_PROGRESS = 6
const GESTURE_STATE = 7
const PAGE_ID = 8
const TEMP_LAST_SCALE = 9
const RENDERER = 10

function clamp(value, min, max) {
  'worklet'
  return Math.min(max, Math.max(min, value))
}

function recoverTiming(target, renderer, callback) {
  'worklet'
  return getTiming(renderer)(target, { duration: 200 }, callback)
}

function calcOpacity(moveY, screenHeight) {
  'worklet'
  const opacityRatio = moveY / (screenHeight / 2)
  return clamp((1 - opacityRatio) ** 3, 0, 1) // 最透明程度为 0
}

function calcScale(moveY, screenHeight) {
  'worklet'
  const scaleRange = 0.4
  const scaleRatio = moveY / (screenHeight / 3 * 2)
  return clamp(1 - scaleRange * scaleRatio, 0.6, 1) // 最小为 0.6
}

Component({
  properties: {
    imageId: {
      type: String,
      value: '',
    },
    sourcePageId: {
      type: String,
      value: '',
    },
    list: {
      type: Array,
      value: [],
    },
  },

  lifetimes: {
    created() {
      EventBus.initWorkletEventBus(this.renderer) // 初始化 ui 线程的 eventBus

      const shared = getShared(this.renderer)

      this.sharedValues = [
        shared(0), // TRANSLATE_X
        shared(0), // TRANSLATE_Y
        shared(0), // START_Y
        shared(1), // OPACITY
        shared(1), // SCALE
        shared(1), // MIN_SCALE
        shared(false), // USER_GESTURE_IN_PROGRESS
        shared(0), // GESTURE_STATE
        shared(0), // PAGE_ID
        shared(1), // TEMP_LAST_SCALE
        shared(this.renderer), // RENDERER
      ]
    },

    attached() {
      const sourcePageId = this.data.sourcePageId
      const { screenHeight } = wx.getSystemInfoSync()
      const pageId = this.getPageId()
      const sharedValues = this.sharedValues ?? []

      sharedValues[PAGE_ID].value = pageId

      this.customRouteContext = wx.router.getRouteContext(this)

      getRunOnUI(this.renderer)(() => {
        'worklet'
        // 监听拖拽返回手势
        if (!globalThis.temp[`${pageId}GestureBack`]) {
          globalThis.temp[`${pageId}GestureBack`] = args => {
            if (sharedValues[GESTURE_STATE].value === PreviewerGesture.Moving) return
            sharedValues[GESTURE_STATE].value = PreviewerGesture.Back

            const { moveX, moveY, offsetY } = args

            // 横向永远跟手走
            sharedValues[TRANSLATE_X].value += moveX

            // 竖向在手指回到原处再往上时增加阻尼
            if (sharedValues[TRANSLATE_Y].value < 0) {
              const fy = 0.52 * ((1 - Math.min(offsetY / screenHeight, 1)) ** 2)
              const translateY = sharedValues[TRANSLATE_Y].value + Math.ceil(moveY * fy)
              sharedValues[TRANSLATE_Y].value = translateY
            } else {
              sharedValues[TRANSLATE_Y].value += moveY
            }

            // 拖动时的渐变
            sharedValues[OPACITY].value = calcOpacity(offsetY, screenHeight)

            // 拖动时的大小变化
            const scale = calcScale(offsetY, screenHeight)
            sharedValues[SCALE].value = scale
            sharedValues[MIN_SCALE].value = Math.min(scale, sharedValues[MIN_SCALE].value)
          }
          globalThis.eventBus.on(`${pageId}Back`, globalThis.temp[`${pageId}GestureBack`])
        }

        // 监听拖拽返回手势结束
        if (!globalThis.temp[`${pageId}GestureBackEnd`]) {
          globalThis.temp[`${pageId}GestureBackEnd`] = () => {
            const moveY = sharedValues[TRANSLATE_Y].value
            const scale = sharedValues[SCALE].value
            const minScale = sharedValues[MIN_SCALE].value
            const { didPop } = this.customRouteContext || {}

            if (moveY > 1 && scale <= (minScale + 0.01)) {
              // 必须是一直处于缩小行为才退页面,否则恢复
              globalThis.eventBus.emit(`${sourcePageId}CustomRouteBack`, { scale })
              didPop()
            } else {
              const renderer = sharedValues[RENDERER].value
              sharedValues[OPACITY].value = recoverTiming(1, renderer)
              sharedValues[TRANSLATE_X].value = recoverTiming(0, renderer)
              sharedValues[TRANSLATE_Y].value = recoverTiming(0, renderer)
              sharedValues[SCALE].value = recoverTiming(1, renderer, () => {
                'worklet'
                sharedValues[GESTURE_STATE].value = PreviewerGesture.Init
              })
              sharedValues[MIN_SCALE].value = 1
            }
          }
          globalThis.eventBus.on(`${pageId}BackEnd`, globalThis.temp[`${pageId}GestureBackEnd`])
        }

        // 监听图片切换手势
        if (!globalThis.temp[`${pageId}GestureToggle`]) {
          globalThis.temp[`${pageId}GestureToggle`] = () => {
            if (sharedValues[GESTURE_STATE].value === PreviewerGesture.Moving) return
            sharedValues[GESTURE_STATE].value = PreviewerGesture.Toggle
          }
          globalThis.eventBus.on(`${pageId}Toggle`, globalThis.temp[`${pageId}GestureToggle`])
        }

        // 监听图片拖动手势
        if (!globalThis.temp[`${pageId}GestureMoving`]) {
          globalThis.temp[`${pageId}GestureMoving`] = () => {
            sharedValues[GESTURE_STATE].value = PreviewerGesture.Moving
          }
          globalThis.eventBus.on(`${pageId}Moving`, globalThis.temp[`${pageId}GestureMoving`])
        }
      })()

      // 拖拽返回时,被拖动的 share-element,因为放手时的返回动画是以两个页面的 share-element 之间的位置进行移动,故这里移动的是 share-element
      this.applyAnimatedStyle('#preview-home >>> .need-transform-on-back', () => {
        'worklet'
        return {
          transform: `translate(${sharedValues[TRANSLATE_X].value}px, ${sharedValues[TRANSLATE_Y].value}px) scale(${sharedValues[SCALE].value})`,
        }
      })

      const { primaryAnimation, primaryAnimationStatus } = this.customRouteContext || {}

      // 拖拽返回时,previewer 本体要隐藏
      this.applyAnimatedStyle('#preview-home >>> .need-hide-on-back', () => {
        'worklet'
        const status = primaryAnimationStatus.value
        const isRunningAnimation = status === 1 || status === 2

        return {
          left: (isRunningAnimation || (sharedValues[GESTURE_STATE].value === PreviewerGesture.Back)) ? '9999px' : '0',
        }
      })

      // 图片背景渐变消失
      this.applyAnimatedStyle('#preview-home >>> .preview-middle-self', () => {
        'worklet'
        const status = primaryAnimationStatus.value
        const opacity = sharedValues[OPACITY].value

        if (!sharedValues[USER_GESTURE_IN_PROGRESS].value) {
          // 非手势触发,则加速动画
          const value = primaryAnimation.value
          let factor = value
          if (status === PrimaryAnimationStatus.FORWARD) {
            factor *= 3
            if (factor > 1) factor = 1
          } else if (status === PrimaryAnimationStatus.REVERSE) {
            factor = 1 - ((1 - factor) * 3)
            if (factor < 0) factor = 0
          }

          const newOpacity = opacity * factor
          return { opacity: newOpacity > 1 ? 1 : newOpacity }
        } else {
          // 手势触发
          return { opacity }
        }
      })
    },

    detached() {
      const pageId = this.getPageId()
      getRunOnUI(this.renderer)(() => {
        'worklet'
        const removeList = ['Back', 'BackEnd', 'Toggle', 'Moving']
        removeList.forEach(item => {
          'worklet'
          const globalKey = `${pageId}Gesture${item}`
          if (globalThis.temp[globalKey]) {
            globalThis.eventBus.off(`${pageId}${item}`, globalThis.temp[globalKey])
            delete globalThis.temp[globalKey]
          }
        })
      })()
    },
  },

  methods: {
    onScale(evt) {
      'worklet'
      const sharedValues = this.sharedValues ?? []
      const pageId = sharedValues[PAGE_ID].value

      if (evt.state === GestureState.BEGIN) {
        sharedValues[START_Y].value = evt.focalY
        sharedValues[TEMP_LAST_SCALE].value = 1
        sharedValues[GESTURE_STATE].value = PreviewerGesture.Init
        sharedValues[USER_GESTURE_IN_PROGRESS].value = true
      } else if (evt.state === GestureState.ACTIVE) {
        const focalX = evt.focalX
        const focalY = evt.focalY
        const moveX = evt.focalDeltaX
        const moveY = evt.focalDeltaY
        const offsetY = focalY - sharedValues[START_Y].value

        if (evt.pointerCount === 2) {
          // 双指放缩
          const pageId = sharedValues[PAGE_ID].value
          const realScale = evt.scale / sharedValues[TEMP_LAST_SCALE].value
          sharedValues[TEMP_LAST_SCALE].value = evt.scale

          globalThis.eventBus.emit(`${pageId}Scale`, {
            scale: realScale,
            centerX: focalX,
            centerY: focalY,
          })
        } else if (sharedValues[GESTURE_STATE].value === PreviewerGesture.Back) {
          // 处于拖拽返回手势中
          globalThis.eventBus.emit(`${pageId}Back`, {
            moveX,
            moveY,
            offsetY,
          })
        } else if (sharedValues[GESTURE_STATE].value === PreviewerGesture.Toggle) {
          // 处于切换图片手势中
          // ignore
        } else {
          // 单指拖动图片
          globalThis.eventBus.emit(`${pageId}Move`, {
            moveX,
            moveY,
            offsetY,
            origin: 'move',
          })
        }
      } else if (evt.state === GestureState.END || evt.state === GestureState.CANCELLED) {
        const velocityX = evt.velocityX
        const velocityY = evt.velocityY
        sharedValues[USER_GESTURE_IN_PROGRESS].value = false

        if (sharedValues[GESTURE_STATE].value === PreviewerGesture.Back) {
          // 拖拽返回手势结束
          globalThis.eventBus.emit(`${pageId}BackEnd`)
        } else if (sharedValues[GESTURE_STATE].value === PreviewerGesture.Toggle) {
          // 切换图片手势结束
          sharedValues[GESTURE_STATE].value = PreviewerGesture.Init
        } else {
          // 其他手势结束
          globalThis.eventBus.emit(`${pageId}End`, {
            velocityX,
            velocityY,
          })
          sharedValues[GESTURE_STATE].value = PreviewerGesture.Init
        }
      }
    },

    onBack() {
      // 进入动画返回状态
      const sharedValues = this.sharedValues ?? []
      sharedValues[GESTURE_STATE].value = PreviewerGesture.Back
    },

    shouldResponseOnMove() {
      'worklet'
      return true
    },
  },
})


================================================
FILE: examples/album/components/previewer/index.json
================================================
{
  "component": true,
  "usingComponents": {
    "preview-home": "./preview-home/index"
  },
  "componentFramework": "glass-easel"
}

================================================
FILE: examples/album/components/previewer/index.wxml
================================================
<scale-gesture-handler
  tag="scale"
  simultaneousHandlers="{{['swiper']}}"
  worklet:ongesture="onScale"
  worklet:should-response-on-move="shouldResponseOnMove"
>
  <preview-home
    id="preview-home"
    class="preview-home"
    imageId="{{imageId}}"
    sourcePageId="{{sourcePageId}}"
    list="{{list}}"
    bindback="onBack"
  ></preview-home>
</scale-gesture-handler>

================================================
FILE: examples/album/components/previewer/index.wxss
================================================
.preview-home {
  width: 100%;
  height: 100%;
  display: block;
}


================================================
FILE: examples/album/components/previewer/preview-home/index.js
================================================
import EventBus from '../../../utils/event-bus'

Component({
  properties: {
    imageId: {
      type: String,
      value: '',
    },
    sourcePageId: {
      type: String,
      value: '',
    },
    list: {
      type: Array,
      value: [],
    },
  },

  data: {
    index: 0,
    tempIndex: -1,
    pretty: false,
  },

  observers: {
    tempIndex(tempIndex) {
      // 切换图片时会影响前一个页面的图片
      const { list, sourcePageId } = this.data
      const image = list[tempIndex]
      if (image) EventBus.emit(`${sourcePageId}PreviewerChange`, image)
    },
  },

  lifetimes: {
    attached() {
      const imageId = this.data.imageId     
      const list = this.data.list
      let index = 0
      if (imageId) {
        const currentIndex = list.findIndex(item => item.id === imageId)
        if (currentIndex !== -1) index = currentIndex
      }

      this.setData({ index })
    },

    detached() {
      // 告诉前一个页面 previewer 将要销毁
      EventBus.emit(`${this.data.sourcePageId}PreviewerDestroy`)
    },
  },

  methods: {
    onBeforeRender(evt) {
      const { index } = evt.detail

      this.data.index = index // 切换可能来自 preview-list 里面,为避免造成循环触发 beforeRender,此处只改 data 不进行 setData
      this.setData({ tempIndex: index }) // 先更新快速预览栏
    },

    onTapImage() {
      this.setData({ pretty: !this.data.pretty })
    },

    onBack(evt) {
      this.triggerEvent('back', evt.detail)
    },
  },
})


================================================
FILE: examples/album/components/previewer/preview-home/index.json
================================================
{
  "component": true,
  "usingComponents": {
    "preview-list": "../preview-list/index",
    "navigation-bar": "../../navigation-bar/index"
  },
  "componentFramework": "glass-easel"
}

================================================
FILE: examples/album/components/previewer/preview-home/index.wxml
================================================
<view class="navigation-bar-cnt {{pretty ? 'hide' : 'show'}}">
  <share-element key="navigation-bar">
    <navigation-bar class="navigation-bar preview-top-self" back bindback="onBack"></navigation-bar>
  </share-element>
</view>
<view class="preview-extra middle preview-middle-self"></view>
<view class="preview-cnt">
  <view class="need-hide-on-back">
    <preview-list
      class="preview-list"
      index="{{index}}"
      list="{{list}}"
      bindbeforerender="onBeforeRender"
      bindtapimage="onTapImage"
    ></preview-list>
  </view>
  <share-element
    key="{{list[tempIndex] && list[tempIndex].id}}"
    class="share-element-image need-transform-on-back"
    shuttleOnPush="to"
  >
    <view class="temp-image">
      <image src="{{list[tempIndex] && list[tempIndex].src}}" mode="aspectFit"></image>
    </view>
  </share-element>
</view>

================================================
FILE: examples/album/components/previewer/preview-home/index.wxss
================================================
.preview-cnt {
  position: absolute;
  left: 0;
  top: 0;
  width: 100vw;
  height: 100vh;
  z-index: 5;
}

.preview-list {
  width: 100vw;
  height: 100vh;
  background-color: #fff;
}

.need-hide-on-back {
  position: absolute;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
}

.share-element-image {
  position: absolute;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  z-index: -1;
  background-color: transparent;
}

.share-element-image .temp-image {
  background-color: transparent;
  height: 100%;
  width: 100%;
}

.share-element-image .temp-image image {
  width: 100%;
  height: 100%;
}

.preview-middle-self {
  position: absolute;
  height: 100vh;
  width: 100vw;
  z-index: 0;
  background-color: #fff;
}

.navigation-bar-cnt {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  z-index: 10;
  transition: transform .3s ease, opacity .3s ease;
}

.navigation-bar-cnt.show {
  transform: none;
  opacity: 1;
}

.navigation-bar-cnt.hide {
  transform: translateY(-50px);
  opacity: 0;
}

.navigation-bar {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  z-index: 5;
}


================================================
FILE: examples/album/components/previewer/preview-image/index.js
================================================
import { getShared, getTiming, getRunOnUI, getRunOnJS } from '../../../utils/worklet'

// sharedValues
const MOVE_X = 0
const MOVE_Y = 1
const SCALE = 2
const IMG_WIDTH = 3
const IMG_HEIGHT = 4
const IMG_MAX_SCALE = 5
const IMG_MIN_SCALE = 6
const IMG_MIN_MOVE_X = 7
const IMG_MAX_MOVE_X = 8
const IMG_MIN_MOVE_Y = 9
const IMG_MAX_MOVE_Y = 10
const GESTURE_STATE = 11
const TEMP_MOVE_X = 12
const TEMP_MOVE_Y = 13
const TEMP_SCALE = 14
const INIT_MOVE_X = 15
const INIT_MOVE_Y = 16
const INIT_SCALE = 17
const CURRENT_ID = 18
const PAGE_ID = 19
const RENDERER = 20

const DEFAULT_IMG_SCALE_MAX = 10

let screenWidth = 0
let screenHeight = 0

function adjustTiming(target, renderer, callback) {
  'worklet'
  return getTiming(renderer)(target, { duration: 300 }, callback)
}

function recoverTiming(target, renderer, callback) {
  'worklet'
  return getTiming(renderer)(target, { duration: 200 }, callback)
}

function vibrateShort(type = 'light') {
  wx.vibrateShort({ type })
}

Component({
  properties: {
    status: {
      type: Number,
      value: 0, // 1 切到当前,2 当前相邻
    },
    image: {
      type: Object,
      value: {},
    },
  },

  observers: {
    status(status) {
      if (!this.isAttached) return

      const oldStatus = this.oldStatus
      if (status === oldStatus) return
      this.oldStatus = status

      if (status === 1) {
        if (this.isImgLoaded) this.triggerEvent('render', this.data.image)
      } else {
        this.resetImg()
      }
    },
  },

  lifetimes: {
    created() {
      const shared = getShared(this.renderer)
      
      this.sharedValues = [
        shared(0), // MOVE_X
        shared(0), // MOVE_Y
        shared(1), // SCALE
        shared(0), // IMG_WIDTH
        shared(0), // IMG_HEIGHT
        shared(1), // IMG_MAX_SCALE
        shared(1), // IMG_MIN_SCALE
        shared(0), // IMG_MIN_MOVE_X
        shared(0), // IMG_MAX_MOVE_X
        shared(0), // IMG_MIN_MOVE_Y
        shared(0), // IMG_MAX_MOVE_Y
        shared(0), // GESTURE_STATE 0 - 初始,1 - 移动图片,2 - 放缩图片,3 - 惯性移动中
        shared(0), // TEMP_MOVE_X
        shared(0), // TEMP_MOVE_Y
        shared(1), // TEMP_SCALE
        shared(0), // INIT_MOVE_X
        shared(0), // INIT_MOVE_Y
        shared(1), // INIT_SCALE
        shared(''), // CURRENT_ID
        shared(''), // PAGE_ID
        shared(this.renderer), // RENDERER
      ]
    },

    attached() {
      this.isAttached = true
      const pageId = this.getPageId()
      const id = this.data.image.id
      const sharedValues = this.sharedValues ?? []

      if (!screenWidth || !screenHeight) {
        const systemInfo = wx.getSystemInfoSync()
        screenWidth = systemInfo.screenWidth
        screenHeight = systemInfo.screenHeight
      }

      sharedValues[PAGE_ID].value = pageId
      sharedValues[CURRENT_ID].value = id

      // 应用放缩和拖动
      this.applyAnimatedStyle('#image', () => {
        'worklet'
        return {
          width: `${sharedValues[IMG_WIDTH].value}px`,
          height: `${sharedValues[IMG_HEIGHT].value}px`,
          transform: `translateX(${sharedValues[MOVE_X].value}px) translateY(${sharedValues[MOVE_Y].value}px) translateZ(0px) scale(${sharedValues[SCALE].value})`,
        }
      })

      // 计算图片边界
      function calcImgLimit(scale, imgWidth, imgHeight) {
        'worklet'
        const viewWidth = imgWidth * scale
        const viewHeight = imgHeight * scale

        if (viewWidth > screenWidth) {
          sharedValues[IMG_MAX_MOVE_X].value = (viewWidth / 2) - (imgWidth / 2)
          sharedValues[IMG_MIN_MOVE_X].value = screenWidth - (imgWidth / 2) - (viewWidth / 2)
        } else {
          sharedValues[IMG_MAX_MOVE_X].value = sharedValues[IMG_MIN_MOVE_X].value = (screenWidth - imgWidth) / 2
        }

        if (viewHeight > screenHeight) {
          sharedValues[IMG_MAX_MOVE_Y].value = (viewHeight / 2) - (imgHeight / 2)
          sharedValues[IMG_MIN_MOVE_Y].value = screenHeight - (imgHeight / 2) - (viewHeight / 2)
        } else {
          sharedValues[IMG_MAX_MOVE_Y].value = sharedValues[IMG_MIN_MOVE_Y].value = (screenHeight - imgHeight) / 2
        }
      }
      this.calcImgLimit = calcImgLimit

      // 监听上层的 move/scale 事件
      getRunOnUI(this.renderer)(() => {
        'worklet'
        const renderer = sharedValues[RENDERER].value
        
        function adjustImg(args) {
          const {
            moveX = null,
            moveY = null,
            scale = null,
            centerX = null,
            centerY = null,
            withAnimation = false,
          } = args

          if (moveX !== null && moveY !== null) {
            if (!moveX && !moveY) return

            const oldMoveX = sharedValues[MOVE_X].value
            const oldMoveY = sharedValues[MOVE_Y].value
            let newMoveX = oldMoveX + moveX
            let newMoveY = oldMoveY + moveY

            const minMoveX = sharedValues[IMG_MIN_MOVE_X].value
            const maxMoveX = sharedValues[IMG_MAX_MOVE_X].value
            const minMoveY = sharedValues[IMG_MIN_MOVE_Y].value
            const maxMoveY = sharedValues[IMG_MAX_MOVE_Y].value

            const isReachXEdge = (newMoveX <= minMoveX || newMoveX >= maxMoveX)
            const isReachYEdge = (newMoveY <= minMoveY || newMoveY >= maxMoveY)
            const isScaleBigger = sharedValues[SCALE].value - sharedValues[INIT_SCALE].value > 0.001
            const moveGap = Math.abs(moveY) - Math.abs(moveX)

            if (!sharedValues[GESTURE_STATE].value && isReachXEdge && moveGap < 0) {
              // 图片本身不在移动中 & 到达水平边缘 & 横向移动
              globalThis.eventBus.emit(`${pageId}Toggle`, args)
            } else if (!sharedValues[GESTURE_STATE].value && isReachYEdge && moveGap > 0 && moveY > 0) {
              // 图片本身不在移动中 & 到达垂直边缘 & 纵向移动
              globalThis.eventBus.emit(`${pageId}Back`, args)
            } else {
              // 移动图片
              const tempOldMoveX = sharedValues[TEMP_MOVE_X].value || oldMoveX
              const tempOldMoveY = sharedValues[TEMP_MOVE_Y].value || oldMoveY

              if (isReachXEdge) {
                // 到达水平边缘,增加阻尼
                const offset = tempOldMoveX - oldMoveX
                const f = 0.52 * ((1 - Math.min(Math.abs(offset) / screenWidth, 1)) ** 2)
                newMoveX = oldMoveX + Math.ceil(moveX * f)
              }

              if (isReachYEdge && isScaleBigger) {
                // 放大情况下到达垂直边缘,增加阻尼
                const offset = tempOldMoveY - oldMoveY
                const f = 0.52 * ((1 - Math.min(Math.abs(offset) / screenHeight, 1)) ** 2)
                newMoveY = oldMoveY + Math.ceil(moveY * f)
              }

              if (sharedValues[GESTURE_STATE].value === 3) {
                // 惯性移动中
                const tempNewMoveX = Math.min(Math.max(newMoveX, minMoveX), maxMoveX)
                sharedValues[MOVE_X].value = tempNewMoveX
                sharedValues[TEMP_MOVE_X].value = tempNewMoveX
                const tempNewMoveY = Math.min(Math.max(newMoveY, minMoveY), maxMoveY)
                sharedValues[MOVE_Y].value = tempNewMoveY
                sharedValues[TEMP_MOVE_Y].value = tempNewMoveY
              } else {
                // 水平方向
                sharedValues[MOVE_X].value = newMoveX
                const tempNewMoveX = tempOldMoveX + moveX // 这是真正预期的位置,用于阻尼恢复
                sharedValues[TEMP_MOVE_X].value = Math.min(Math.max(tempNewMoveX, minMoveX), maxMoveX)

                // 垂直方向
                if (isScaleBigger) {
                  // 只有放大情况下需要阻尼
                  sharedValues[MOVE_Y].value = newMoveY
                  const tempNewMoveY = tempOldMoveY + moveY // 这是真正预期的位置,用于阻尼恢复
                  sharedValues[TEMP_MOVE_Y].value = Math.min(Math.max(tempNewMoveY, minMoveY), maxMoveY)
                } else {
                  const tempNewMoveY = Math.min(Math.max(newMoveY, minMoveY), maxMoveY)
                  sharedValues[MOVE_Y].value = tempNewMoveY
                  sharedValues[TEMP_MOVE_Y].value = tempNewMoveY
                }

                sharedValues[GESTURE_STATE].value = 1
                globalThis.eventBus.emit(`${pageId}Moving`)
              }
            }
          } else if (scale !== null && centerX !== null && centerY !== null) {
            const oldMoveX = sharedValues[MOVE_X].value
            const oldMoveY = sharedValues[MOVE_Y].value
            const oldScale = sharedValues[SCALE].value
            const newScale = oldScale * scale
            const tempNewScale = Math.min(Math.max(newScale, sharedValues[IMG_MIN_SCALE].value), sharedValues[IMG_MAX_SCALE].value) // 这是真正预期的 scale,用于阻尼恢复
            const realScale = tempNewScale / oldScale

            // 其实就是求放缩时图片中心的偏移变化
            const imgWidth = sharedValues[IMG_WIDTH].value
            const imgHeight = sharedValues[IMG_HEIGHT].value
            const gapX = centerX - (imgWidth / 2)
            let newMoveX = gapX - ((gapX - oldMoveX) * realScale)
            const gapY = centerY - (imgHeight / 2)
            let newMoveY = gapY - ((gapY - oldMoveY) * realScale)

            calcImgLimit(tempNewScale, imgWidth, imgHeight)
            newMoveX = Math.min(Math.max(newMoveX, sharedValues[IMG_MIN_MOVE_X].value), sharedValues[IMG_MAX_MOVE_X].value)
            newMoveY = Math.min(Math.max(newMoveY, sharedValues[IMG_MIN_MOVE_Y].value), sharedValues[IMG_MAX_MOVE_Y].value)

            sharedValues[MOVE_X].value = withAnimation ? adjustTiming(newMoveX, renderer) : newMoveX
            sharedValues[MOVE_Y].value = withAnimation ? adjustTiming(newMoveY, renderer) : newMoveY
            if (withAnimation) {
              // 有动画,表示是双击放大,不需要考虑阻尼
              sharedValues[SCALE].value = adjustTiming(tempNewScale, renderer, () => {
                sharedValues[GESTURE_STATE].value = 0 // 动画结束,状态恢复初始
              })
              sharedValues[TEMP_SCALE].value = tempNewScale
            } else {
              let calcNewScale = newScale
              if (Math.abs(newScale - tempNewScale) > 0.001) {
                // 超出了边界,补充阻尼计算
                const gap = newScale - oldScale
                const dampingLimit = gap < 0 ? (newScale / tempNewScale) : (tempNewScale / newScale)
                const f = (gap < 0 ? 0.3 : 0.6) * (Math.min(dampingLimit, 1) ** 2) // 不要问为什么是这个值,凭感觉定的
                calcNewScale = oldScale + (gap  * f)
              }

              sharedValues[SCALE].value = calcNewScale
              sharedValues[TEMP_SCALE].value = tempNewScale
            }

            // 回弹是延迟的,所以这里需要确保没有回弹
            sharedValues[TEMP_MOVE_X].value = newMoveX
            sharedValues[TEMP_MOVE_Y].value = newMoveY

            sharedValues[GESTURE_STATE].value = 2
            globalThis.eventBus.emit(`${pageId}Moving`)
          }
        }

        // 监听图片拖动手势
        if (!globalThis.temp[`${pageId}${id}ImgMove`]) {
          globalThis.temp[`${pageId}${id}ImgMove`] = args => adjustImg(args)
          globalThis.eventBus.on(`${pageId}${id}Move`, globalThis.temp[`${pageId}${id}ImgMove`])
        }

        // 监听图片放缩手势
        if (!globalThis.temp[`${pageId}${id}ImgScale`]) {
          globalThis.temp[`${pageId}${id}ImgScale`] = args => adjustImg(args)
          globalThis.eventBus.on(`${pageId}${id}Scale`, globalThis.temp[`${pageId}${id}ImgScale`])
        }

        // 监听手势结束事件
        if (!globalThis.temp[`${pageId}${id}ImgEnd`]) {
          globalThis.temp[`${pageId}${id}ImgEnd`] = args => {
            // 手势结束
            sharedValues[GESTURE_STATE].value = 0

            const moveX = sharedValues[MOVE_X].value
            const targetMoveX = sharedValues[TEMP_MOVE_X].value
            const needRecoverX = Math.abs(moveX - targetMoveX) > 0.001
            const moveY = sharedValues[MOVE_Y].value
            const targetMoveY = sharedValues[TEMP_MOVE_Y].value
            const needRecoverY = Math.abs(moveY - targetMoveY) > 0.001
            const scale = sharedValues[SCALE].value
            const targetScale = sharedValues[TEMP_SCALE].value
            const needRecoverScale = Math.abs(scale - targetScale) > 0.001

            const isScaleBigger = sharedValues[SCALE].value - sharedValues[INIT_SCALE].value > 0.001
            const { velocityX, velocityY } = args
            const vx = Math.min(Math.abs(velocityX), 700)
            const vy = Math.min(Math.abs(velocityY), 700)

            if (needRecoverX || needRecoverY || needRecoverScale) {
              // 阻尼回弹
              if (needRecoverX) sharedValues[MOVE_X].value = recoverTiming(targetMoveX, renderer)
              if (needRecoverY) sharedValues[MOVE_Y].value = recoverTiming(targetMoveY, renderer)
              if (needRecoverScale) {
                sharedValues[SCALE].value = recoverTiming(targetScale, renderer)
                getRunOnJS(sharedValues[RENDERER].value)(vibrateShort)()
              }
            } else if (isScaleBigger && (vx > 50 || vy > 50)) {
              // 惯性计算
              sharedValues[GESTURE_STATE].value = 3

              const a = -0.0015
              const directionX = Math.sign(velocityX)
              const directionY = Math.sign(velocityY)
              let vx0 = vx / 1000
              let vy0 = vy / 1000
              const t = 16

              const nextTick = () => {
                'worklet'
                // 如果此时进入其他状态,则取消惯性
                if (sharedValues[GESTURE_STATE].value !== 3) return

                let moveX = 0
                let moveY = 0

                if (vx0 > 0) {
                  // 还有水平速度
                  const vx1 = a * t + vx0
                  if (vx1 > 0) {
                    const s = (vx0 * t) + ((a * (t ** 2)) / 2)
                    moveX = s * directionX
                    vx0 = vx1
                  } else {
                    vx0 = 0
                  }
                }

                if (vy0 > 0) {
                  // 还有垂直速度
                  const vy1 = a * t + vy0
                  if (vy1 > 0) {
                    const s = (vy0 * t) + ((a * (t ** 2)) / 2)
                    moveY = s * directionY
                    vy0 = vy1
                  } else {
                    vy0 = 0
                  }
                }

                if (moveX || moveY) {
                  adjustImg({ moveX, moveY })
                  setTimeout(nextTick, t)
                } else {
                  // 回归初始状态
                  sharedValues[GESTURE_STATE].value = 0
                }
              }

              setTimeout(nextTick, t)
            }
          }
          globalThis.eventBus.on(`${pageId}${id}End`, globalThis.temp[`${pageId}${id}ImgEnd`])
        }

        // 监听图片双击手势
        if (!globalThis.temp[`${pageId}${id}ImgDoubleTap`]) {
          globalThis.temp[`${pageId}${id}ImgDoubleTap`] = args => adjustImg(args)
          globalThis.eventBus.on(`${pageId}${id}DoubleTap`, globalThis.temp[`${pageId}${id}ImgDoubleTap`])
        }
      })()
    },

    detached() {
      this.isAttached = false
      const id = this.data.image.id
      const pageId = this.getPageId()

      getRunOnUI(this.renderer)(() => {
        'worklet'
        const removeList = ['Move', 'Scale', 'End', 'DoubleTap']
        removeList.forEach(item => {
          'worklet'
          const globalKey = `${pageId}${id}Img${item}`
          if (globalThis.temp[globalKey]) {
            globalThis.eventBus.off(`${pageId}${id}${item}`, globalThis.temp[globalKey])
            delete globalThis.temp[globalKey]
          }
        })
      })()
    },
  },

  methods: {
    resetImg() {
      const sharedValues = this.sharedValues ?? []
      const initMoveX = sharedValues[INIT_MOVE_X].value
      const initMoveY = sharedValues[INIT_MOVE_Y].value
      const initScale = sharedValues[INIT_SCALE].value

      this.calcImgLimit(initScale, sharedValues[IMG_WIDTH].value, sharedValues[IMG_HEIGHT].value)

      sharedValues[MOVE_X].value = initMoveX
      sharedValues[MOVE_Y].value = initMoveY
      sharedValues[TEMP_MOVE_X].value = initMoveX
      sharedValues[TEMP_MOVE_Y].value = initMoveY
      sharedValues[SCALE].value = initScale
      sharedValues[TEMP_SCALE].value = initScale
    },

    onImgLoad(evt) {
      const { width: imgWidth, height: imgHeight } = evt.detail
      const sharedValues = this.sharedValues ?? []

      if (!screenWidth || !screenHeight) {
        const systemInfo = wx.getSystemInfoSync()
        screenWidth = systemInfo.screenWidth
        screenHeight = systemInfo.screenHeight
      }
      const windowRatio = screenWidth / screenHeight

      sharedValues[IMG_WIDTH].value = imgWidth
      sharedValues[IMG_HEIGHT].value = imgHeight

      if (!imgWidth || !imgHeight) return

      const imgRatio = imgWidth / imgHeight

      let scale = 1
      let moveX = 0
      let moveY = 0

      if (imgRatio > windowRatio) {
        scale = screenWidth / imgWidth
        moveX = (screenWidth - imgWidth) / 2
        const scaleHeight = imgHeight * scale
        moveY = ((screenHeight - scaleHeight) / 2) - ((imgHeight - scaleHeight) / 2)

        sharedValues[IMG_MAX_SCALE].value = imgWidth > screenWidth ? 2 : DEFAULT_IMG_SCALE_MAX
        sharedValues[IMG_MIN_SCALE].value = imgWidth > screenWidth ? screenWidth / imgWidth : 1
      } else {
        scale = screenHeight / imgHeight
        moveY = (screenHeight - imgHeight) / 2
        const scaleWidth = imgWidth * scale
        moveX = ((screenWidth - scaleWidth) / 2) - ((imgWidth - scaleWidth) / 2)

        sharedValues[IMG_MAX_SCALE].value = imgHeight > screenHeight ? 2 : DEFAULT_IMG_SCALE_MAX
        sharedValues[IMG_MIN_SCALE].value = imgHeight > screenHeight ? screenHeight / imgHeight : 1
      }

      this.calcImgLimit(scale, imgWidth, imgHeight)

      sharedValues[MOVE_X].value = moveX
      sharedValues[MOVE_Y].value = moveY
      sharedValues[TEMP_MOVE_X].value = moveX
      sharedValues[TEMP_MOVE_Y].value = moveY
      sharedValues[SCALE].value = scale
      sharedValues[TEMP_SCALE].value = scale

      sharedValues[INIT_MOVE_X].value = moveX
      sharedValues[INIT_MOVE_Y].value = moveY
      sharedValues[INIT_SCALE].value = scale

      this.isImgLoaded = true

      if (this.data.status === 1) {
        // 处于 current 状态,直接扔 render 事件
        this.triggerEvent('render', this.data.image)
      }
    },

    onDoubleTap(evt) {
      'worklet'
      const sharedValues = this.sharedValues ?? []
      const currentScale = sharedValues[SCALE].value
      const minScale = sharedValues[IMG_MIN_SCALE].value
      globalThis.eventBus.emit(`${sharedValues[PAGE_ID].value}${sharedValues[CURRENT_ID].value}DoubleTap`, {
        scale: currentScale <= minScale ? 2 : 0.0001, // 如果放大过,就缩回默认大小;如果没有放大过则放大
        centerX: evt.absoluteX,
        centerY: evt.absoluteY,
        withAnimation: true,
      })
    },
  },
})


================================================
FILE: examples/album/components/previewer/preview-image/index.json
================================================
{
  "component": true,
  "usingComponents": {},
  "componentFramework": "glass-easel"
}

================================================
FILE: examples/album/components/previewer/preview-image/index.wxml
================================================
<double-tap-gesture-handler class="double-tap-gesture-handler" worklet:ongesture="onDoubleTap">
  <view id="image" class="image-wrapper">
    <image
      wx:if="{{status}}"
      class="image"
      src="{{image.src}}"
      mode="aspectFit"
      bindload="onImgLoad"
    ></image>
  </view>
</double-tap-gesture-handler>


================================================
FILE: examples/album/components/previewer/preview-image/index.wxss
================================================
.double-tap-gesture-handler {
  display: block;
  width: 100%;
  height: 100%;
}

.image-wrapper {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  transform-origin: center;
  will-change: transform;
}

.image {
  width: 100%;
  height: 100%;
}


================================================
FILE: examples/album/components/previewer/preview-list/index.js
================================================
import { getShared, getRunOnUI, getRunOnJS } from '../../../utils/worklet'

const PreviewerGesture = {
  Init: 0, // 初始
  Moving: 1, // 移动图片
  Toggle: 2, // 切换图片
  Back: 3, // 退出页面
}

// sharedValues
const GESTURE_STATE = 0
const CURRENT_ID = 1
const RENDERER = 2

Component({
  properties: {
    index: {
      type: Number,
      value: 0,
    },
    list: {
      type: Array,
      value: [],
    },
  },

  data: {
    currentIndex: -99,
    needSwiperAnimation: true,
  },

  observers: {
    list(list) {
      const index = this.data.index
      const current = list[index]
      if (!current) return

      const sharedValues = this.sharedValues ?? []
      sharedValues[CURRENT_ID].value = current.id

      this.toggleImage(index, true)
    },

    index(index) {
      const len = this.data.list.length
      if (!len) return

      if (index !== this.data.currentIndex && index >= 0 && index < len) {
        this.toggleImage(index, true)
      } else {
        // 设置相同的 index 也给一下 render 事件
        const image = this.data.list[index]
        if (image && image.id === this.currentRenderImage) {
          // 要求 image 已经渲染完成
          this.onImageRender({ detail: image })
        }
      }
    },
  },

  lifetimes: {
    created() {
      const shared = getShared(this.renderer)

      this.sharedValues = [
        shared(0), // GESTURE_STATE
        shared(''), // CURRENT_ID
        shared(this.renderer), // RENDERER
      ]
    },

    async attached() {
      const pageId = this.getPageId()
      const sharedValues = this.sharedValues ?? []

      getRunOnUI(this.renderer)(() => {
        'worklet'
        // 监听拖拽返回手势
        if (!globalThis.temp[`${pageId}PreviewerBack`]) {
          globalThis.temp[`${pageId}PreviewerBack`] = () => sharedValues[GESTURE_STATE].value = PreviewerGesture.Back
          globalThis.eventBus.on(`${pageId}Back`, globalThis.temp[`${pageId}PreviewerBack`])
        }

        // 监听图片切换手势
        if (!globalThis.temp[`${pageId}PreviewerToggle`]) {
          globalThis.temp[`${pageId}PreviewerToggle`] = () => sharedValues[GESTURE_STATE].value = PreviewerGesture.Toggle
          globalThis.eventBus.on(`${pageId}Toggle`, globalThis.temp[`${pageId}PreviewerToggle`])
        }

        // 监听图片拖动中事件
        if (!globalThis.temp[`${pageId}PreviewerMoving`]) {
          globalThis.temp[`${pageId}PreviewerMoving`] = () => sharedValues[GESTURE_STATE].value = PreviewerGesture.Moving
          globalThis.eventBus.on(`${pageId}Moving`, globalThis.temp[`${pageId}PreviewerMoving`])
        }

        // 监听图片拖动手势
        if (!globalThis.temp[`${pageId}PreviewerMove`]) {
          globalThis.temp[`${pageId}PreviewerMove`] = args => {
            // 此处只做转发
            const currentId = sharedValues[CURRENT_ID].value
            globalThis.eventBus.emit(`${pageId}${currentId}Move`, args)
          }
          globalThis.eventBus.on(`${pageId}Move`, globalThis.temp[`${pageId}PreviewerMove`])
        }

        // 监听图片放缩手势
        if (!globalThis.temp[`${pageId}PreviewerScale`]) {
          globalThis.temp[`${pageId}PreviewerScale`] = args => {
            // 此处只做转发
            const currentId = sharedValues[CURRENT_ID].value
            globalThis.eventBus.emit(`${pageId}${currentId}Scale`, args)
          }
          globalThis.eventBus.on(`${pageId}Scale`, globalThis.temp[`${pageId}PreviewerScale`])
        }

        // 监听手势结束事件
        if (!globalThis.temp[`${pageId}PreviewerEnd`]) {
          globalThis.temp[`${pageId}PreviewerEnd`] = args => {
            // 此处只做转发
            const currentId = sharedValues[CURRENT_ID].value
            globalThis.eventBus.emit(`${pageId}${currentId}End`, args)
          }
          globalThis.eventBus.on(`${pageId}End`, globalThis.temp[`${pageId}PreviewerEnd`])
        }
      })()
    },

    detached() {
      const pageId = this.getPageId()
      getRunOnUI(this.renderer)(() => {
        'worklet'
        const removeList = ['Back', 'Toggle', 'Moving', 'Move', 'Scale', 'End']
        removeList.forEach(item => {
          'worklet'
          const globalKey = `${pageId}Previewer${item}`
          if (globalThis.temp[globalKey]) {
            globalThis.eventBus.off(`${pageId}${item}`, globalThis.temp[globalKey])
            delete globalThis.temp[globalKey]
          }
        })
      })()
    },
  },

  methods: {
    async toggleImage(index, disableAnimation = false) {
      const image = this.data.list[index]
      if (!image) return

      const sharedValues = this.sharedValues ?? []
      sharedValues[CURRENT_ID].value = image.id

      this.setData({
        currentIndex: index,
        needSwiperAnimation: !disableAnimation,
      })
      this.data.index = index // index 也更新一下,方便其他地方取用

      this.triggerEvent('beforerender', { index, image })
    },

    onImageRender(evt) {
      const list = this.data.list
      const index = this.data.currentIndex
      const image = list[index] || {}

      if (evt.detail.id !== image.id) return

      this.currentRenderImage = image.id
    },

    onTapImage() {
      'worklet'
      getRunOnJS(this.sharedValues[RENDERER].value)(this.triggerEvent.bind(this))('tapimage')
    },

    shouldResponseOnMove() {
      'worklet'
      // 当触发图片切换手势时,才让 swiper 工作
      const sharedValues = this.sharedValues ?? []
      return sharedValues[GESTURE_STATE].value === PreviewerGesture.Toggle
    },

    onSwiperChange(evt) {
      const { current, source } = evt.detail
      if (source === 'touch') this.toggleImage(current, false)
    },
  },
})


================================================
FILE: examples/album/components/previewer/preview-list/index.json
================================================
{
  "component": true,
  "usingComponents": {
    "preview-image": "../preview-image/index"
  },
  "componentFramework": "glass-easel"
}

================================================
FILE: examples/album/components/previewer/preview-list/index.wxml
================================================
<view class="image-previewer">
  <horizontal-drag-gesture-handler
    tag="swiper"
    simultaneousHandlers="{{['scale']}}"
    native-view="swiper"
    worklet:should-response-on-move="shouldResponseOnMove"
  >
    <tap-gesture-handler worklet:ongesture="onTapImage">
      <swiper
        class="swiper-cnt"
        current="{{currentIndex}}"
        duration="300"
        cache-extent="2"
        scrollWithAnimation="{{needSwiperAnimation}}"
        bindchange="onSwiperChange"
      >
        <swiper-item wx:for="{{list}}" wx:key="id">
          <preview-image
            class="image"
            status="{{currentIndex === index ? 1 : ((index >= currentIndex - 1 && index <= currentIndex + 1) ? 2 : 0)}}"
            image="{{item}}"
            bindrender="onImageRender"
          ></preview-image>
        </swiper-item>
      </swiper>
    </tap-gesture-handler>
  </horizontal-drag-gesture-handler>
</view>


================================================
FILE: examples/album/components/previewer/preview-list/index.wxss
================================================

.image-previewer {
  width: 100vw;
  height: 100vh;
  overflow: hidden;
}

.swiper-cnt {
  display: flex;
  flex-direction: row;
  position: absolute;
  left: 0;
  top: 0;
  width: 100vw;
  height: 100vh;
  z-index: 20;
}

.image {
  display: block;
  width: 100%;
  height: 100%;
}


================================================
FILE: examples/album/pages/album/index.js
================================================
import { getAlbum } from '../../utils/store'

Page({
  data: {
    imageWidth: 0,
    imageMargin: 12, // 图片间距
    lineLimit: 3, // 每行多少张图片
    list: [],
  },

  onLoad() {
    const { imageMargin, lineLimit } = this.data
    const { screenWidth } = wx.getSystemInfoSync()
    this.setData({
      imageWidth: (screenWidth - imageMargin * 4) / lineLimit, // 图片宽度
      list: getAlbum(),
    })
  },
})

================================================
FILE: examples/album/pages/album/index.json
================================================
{
  "usingComponents": {
    "navigation-bar": "../../components/navigation-bar/index",
    "album": "../../components/album/index"
  },
  "disableScroll": true,
  "navigationStyle": "custom"
}

================================================
FILE: examples/album/pages/album/index.wxml
================================================
<view class="cnt">
  <share-element key="navigation-bar">
    <navigation-bar title="相册图片预览" back></navigation-bar>
  </share-element>
  <album
    class="album"
    list="{{list}}"
    imageWidth="{{imageWidth}}"
    imageMargin="{{imageMargin}}"
    lineLimit="{{lineLimit}}"
  ></album>
  <view class="safe-area-inset-bottom"></view>
</view>


================================================
FILE: examples/album/pages/album/index.wxss
================================================
.cnt {
  position: absolute;
  top: 0;
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
}

.album {
  height: 0;
  flex: 1;
  margin-bottom: 12px;
}

.safe-area-inset-bottom {
  height: env(safe-area-inset-bottom);
}


================================================
FILE: examples/album/pages/preview/index.js
================================================
import { getAlbum } from '../../utils/store'

Component({
  properties: {
    imageid: {
      type: String,
      value: '',
    },
    sourcepageid: {
      type: String,
      value: '',
    },
  },

  data: {
    imageId: '',
    sourcePageId: '',
    list: [],
  },

  lifetimes: {
    attached() {
      // 因为页面的 onLoad 太迟,所以选用 component 构造器的 attached 生命周期来设置 shareKey,确保 share-element 动画正常执行
      const query = this.data
      const imageId = decodeURIComponent(query.imageid || '')
      const sourcePageId = decodeURIComponent(query.sourcepageid || '')
      const list = getAlbum()
      this.setData({ imageId, sourcePageId, list })
    },
  },
})


================================================
FILE: examples/album/pages/preview/index.json
================================================
{
  "usingComponents": {
    "previewer": "../../components/previewer/index"
  },
  "navigationStyle": "custom",
  "backgroundColorContent": "#00000000",
  "disableScroll": true,
  "componentFramework": "glass-easel",
  "renderer": "skyline"
}


================================================
FILE: examples/album/pages/preview/index.wxml
================================================
<view class="box-cotainer">
  <previewer
    imageId="{{imageId}}"
    sourcePageId="{{sourcePageId}}"
    list="{{list}}"
  ></previewer>
</view>

================================================
FILE: examples/album/pages/preview/index.wxss
================================================
page {
  background-color: transparent;
}

.box-cotainer {
  width: 100vw;
  height: 100vh;
  position: relative;
}

.previewer {
  width: 100%;
  height: 100%;
}


================================================
FILE: examples/album/project.config.json
================================================
{
  "description": "项目配置文件",
  "packOptions": {
    "ignore": [],
    "include": []
  },
  "setting": {
    "bundle": false,
    "userConfirmedBundleSwitch": false,
    "urlCheck": true,
    "scopeDataCheck": false,
    "coverView": true,
    "es6": true,
    "postcss": true,
    "compileHotReLoad": false,
    "lazyloadPlaceholderEnable": false,
    "preloadBackgroundData": false,
    "minified": true,
    "autoAudits": false,
    "newFeature": false,
    "uglifyFileName": false,
    "uploadWithSourceMap": true,
    "useIsolateContext": true,
    "nodeModules": false,
    "enhance": true,
    "useMultiFrameRuntime": true,
    "useApiHook": true,
    "useApiHostProcess": true,
    "showShadowRootInWxmlPanel": true,
    "packNpmManually": false,
    "enableEngineNative": false,
    "packNpmRelationList": [],
    "minifyWXSS": true,
    "showES6CompileOption": false,
    "minifyWXML": true,
    "babelSetting": {
      "ignore": [],
      "disablePlugins": [],
      "outputPath": ""
    },
    "condition": false,
    "skylineRenderEnable": false,
    "compileWorklet": true
  },
  "compileType": "miniprogram",
  "libVersion": "latest",
  "appid": "wxe5f52902cf4de896",
  "projectname": "album-demo",
  "condition": {},
  "editorSetting": {
    "tabIndent": "insertSpaces",
    "tabSize": 2
  }
}

================================================
FILE: examples/album/project.private.config.json
================================================
{
  "description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html",
  "projectname": "album",
  "setting": {
    "compileHotReLoad": false,
    "skylineRenderEnable": true
  },
  "libVersion": "latest"
}

================================================
FILE: examples/album/sitemap.json
================================================
{
  "desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html",
  "rules": [{
  "action": "allow",
  "page": "*"
  }]
}

================================================
FILE: examples/album/utils/event-bus.js
================================================
import { getRunOnUI } from './worklet'

const map = {}

function on(eventName, handler) {
  map[eventName] = map[eventName] || []
  map[eventName].push(handler)
}

function off(eventName, handler) {
  const handlerList = map[eventName]
  if (!handlerList || !handlerList.length) return

  const index = handlerList.indexOf(handler)
  if (index !== -1) handlerList.splice(index, 1)
}

function emit(eventName, ...args) {
  const handlerList = map[eventName]
  if (!handlerList || !handlerList.length) return

  for (let i = handlerList.length - 1; i >= 0; i--) {
    handlerList[i](...args)
  }
}

function initWorkletEventBus(renderer) {
  getRunOnUI(renderer)(() => {
    'worklet'
    if (!globalThis.temp) globalThis.temp = {}
    if (!globalThis.eventBus) {
      const eventBus = {
        map: {},
        on(eventName, handler) {
          eventBus.map[eventName] = eventBus.map[eventName] || []
          eventBus.map[eventName].push(handler)
        },
        off(eventName, handler) {
          const handlerList = eventBus.map[eventName]
          if (!handlerList || !handlerList.length) return

          const index = handlerList.indexOf(handler)
          if (index !== -1) handlerList.splice(index, 1)
        },
        emit(eventName, args) {
          const handlerList = eventBus.map[eventName]
          if (!handlerList || !handlerList.length) return

          for (let i = handlerList.length - 1; i >= 0; i--) {
            handlerList[i](args)
          }
        },
      }
      globalThis.eventBus = eventBus
    }
  })()
}

export default {
  on,
  off,
  emit,
  initWorkletEventBus,
}


================================================
FILE: examples/album/utils/store.js
================================================
const imageList = []
export function getAlbum() {
  if (!imageList.length) {
    const srcList = [
      'https://res.wx.qq.com/op_res/7_miJnK0wxIrh5bV2QqvYcv7mQABQVg50gh51-Kb1mlBq0c8Difu3rXn0ldrZdZwVx9REPbKVyZb3E9Wq6YFLA',
      'https://res.wx.qq.com/op_res/7_miJnK0wxIrh5bV2QqvYVtRBEXZ74JLECYN4Hc3Cdml3x7cJcbcBj3sIdYb2L_7DJ14X8TAHiZ7Ydct52WIYA',
      'https://res.wx.qq.com/op_res/7_miJnK0wxIrh5bV2QqvYfaqohk6ndcC6_CBkUZszfSpKbqUAV7S2xWRbAQ459YsPWAmLKkicEOPS1L3NmnnRA',
      'https://res.wx.qq.com/op_res/7_miJnK0wxIrh5bV2QqvYYa7k4CAG71Ci0SRPExPB1sGiiVPcYwSD5CAYgq8Ni2RhGQlqIrIwnBlt90mUzL7Lg',
      'https://res.wx.qq.com/op_res/7_miJnK0wxIrh5bV2QqvYYjda9Dp372N3T05q_nn3PgvoXBoReXvaXBfkthtXQLN7m5_YI6FoTre-xvJBDFLMA',
      'https://res.wx.qq.com/op_res/7_miJnK0wxIrh5bV2QqvYTIqRBCdQgzZm3KO3usZT7zM2O0EoylisontlH4TZAC_qfVjFVU4L4CPjLm0mppQwg',
      'https://res.wx.qq.com/op_res/7_miJnK0wxIrh5bV2QqvYfa6mRnywhNbBFV5eAt7oTz3zjlNJeujfQx0PVA1ufenPHBvxYXRNJ5chyi6RPaE7A',
      'https://res.wx.qq.com/op_res/7_miJnK0wxIrh5bV2QqvYYY1OalScOn4EMcQpkPaJ1Sxhri8CScjnhqVfjAZnLuVFl0JAM4VziHhSzHLZXtAaQ',
      'https://res.wx.qq.com/op_res/7_miJnK0wxIrh5bV2QqvYSPfXw5qxNvP3f5uJhy0kdkaTAbIZ187IFWmBiluEs8Puw0tXgBlBgGKN-irLPOIDw',
      'https://res.wx.qq.com/op_res/7_miJnK0wxIrh5bV2QqvYZB1p48LLH-Pc7Rzr4nN0YF-uZg7FW7zksw_Kjp0BNDHcZp9R9SRKbg0rA1HBaeK3Q',
      'https://res.wx.qq.com/op_res/7_miJnK0wxIrh5bV2QqvYYXMoGlbo8DkSiia6d-_3Dv15DjMGCEhBkPYd5BrNkSUTPtomAm0CVeHgC244sapKw',
      'https://res.wx.qq.com/op_res/7_miJnK0wxIrh5bV2QqvYf3q0W302-kseD8VxLKoItZ6HgneLkgpQSEMIgEKz_xVE7putZxs2YEYqB13Uh37_w',
      'https://res.wx.qq.com/op_res/7_miJnK0wxIrh5bV2QqvYRu0VRyVvePJ4pB4_Dvj0ytF-ovjQzMl6WMLyuCeKk3579HNjKLIeNrHE7OprTBx5w',
      'https://res.wx.qq.com/op_res/7_miJnK0wxIrh5bV2QqvYc-vygvNNpz1fcZZjZ6B0Jm0X2dpOWJBn4u4T15gwL-1Qr70v6fkFgUswldiPhQG0Q',
      'https://res.wx.qq.com/op_res/7_miJnK0wxIrh5bV2QqvYUo-SgGpk2gpFNixuaCMxDadRvvWxqC5jc1ma-oobJf4mWVg3F3iRt1Bkv-sR0l3-Q',
      'https://res.wx.qq.com/op_res/0-l2fyKjv3_BR62E3KwTJCk-lm-hNrvdJ9paSPqTXkCKLE6eIuc6zAs3Lr1Qh6jEMxdfgP_rvTftB0SQiZeQNQ',
      'https://res.wx.qq.com/op_res/0-l2fyKjv3_BR62E3KwTJImpE8Sm-oMoeJizjFr8mxotXQSFlSm8ZUD6GLf_ptM5ozLvnc2eczwSN09Y5M0ovg',
      'https://res.wx.qq.com/op_res/0-l2fyKjv3_BR62E3KwTJBAK7KJg9KId_6N1-rJ4OyCCQoJGVMOaTabboo2viRucoxkPvHRkn2fVl6tectlzBg',
      'https://res.wx.qq.com/op_res/0-l2fyKjv3_BR62E3KwTJGVi_kGQppwXClflw43wtANVzuw0_Y8ij9VzW1O8hr6cR195D87X7zQS_1gjRo8IdQ',
      'https://res.wx.qq.com/op_res/0-l2fyKjv3_BR62E3KwTJHhlMVj_svRRdDMHjtAvwGwU2d_VAJ-y3SigDx2XjjA22Y63oStS-fw5gooV5rX42Q',
      'https://res.wx.qq.com/op_res/0-l2fyKjv3_BR62E3KwTJPRaN5CDI6NZFg_qbSxeqF8UBpM4lXJ_1o9S9bsOOxMpuXGLeKyAKleWlAXmVLmQOw',
      'https://res.wx.qq.com/op_res/0-l2fyKjv3_BR62E3KwTJMQYuLq5q6_CWdtW3RnWbYMaNhzew60nGsQfBtyeogj3vRfGimJBi87ThS577HC6ag',
      'https://res.wx.qq.com/op_res/0-l2fyKjv3_BR62E3KwTJBalQKoYXBze_mRhoUHIh5OfHiR95JEa18ob-y7uu8W1gpOjO87BbOcki3xM_RrO1Q',
      'https://res.wx.qq.com/op_res/0-l2fyKjv3_BR62E3KwTJAqHss14EPHStg3OpHjtIYzOGQgxvsDcACMxQc2waTpAMsJBFxVlp1JkZQJy2gXu3g',
      'https://res.wx.qq.com/op_res/0-l2fyKjv3_BR62E3KwTJH2f0R4uXyqnNGlrivO8cKbn0nz1DE_6s22rc91zluwIrqiAVZNREvCeVYAUS8aaZw',
      'https://res.wx.qq.com/op_res/SPJ17foR6CQ_1kS3N3iWEk2lg3OAXWsGLLFfwHR64LgMfJQm0jK0YWSG9rVD9cysd0AddG5ZhacUE5mm2jPelQ',
    ]
    const thumbnailList = [
      'https://res.wx.qq.com/op_res/0-l2fyKjv3_BR62E3KwTJDaOeA5r3yDpl5AjlRxMmKPaX0WbJIRr0PjZzsfxIGq1n5Q0o65EpxFGpGpbT9e8QQ',
      'https://res.wx.qq.com/op_res/0-l2fyKjv3_BR62E3KwTJACGFAh31lY9OxoD1iSXsyYpk2adWITN6b7gT7RcBEeDXhppBLYI3JhSMJDyIvPrcg',
      'https://res.wx.qq.com/op_res/0-l2fyKjv3_BR62E3KwTJJX5J79IIhayRchEZTln15RdpFkFfsqsvng5dqMa12Vm9rmcT-hhw1alfHvxTXVVRw',
      'https://res.wx.qq.com/op_res/0-l2fyKjv3_BR62E3KwTJApluxMePb-2yj-XeDSDlr-pNZnbKpaNwl4BUXyZ0bKXWMcqKQSGDdOWFPOP08-4Sw',
      'https://res.wx.qq.com/op_res/0-l2fyKjv3_BR62E3KwTJI8Xazme5-MIIJYUg9t2ibxTp-PtGPUXes9XZj8rRIfyhZJgyfejqwzwpSDBh-K5eg',
      'https://res.wx.qq.com/op_res/0-l2fyKjv3_BR62E3KwTJHOt1gRAQQbf2Bx8mJoYj_8hoN17WusJ_kEzxqYbkN6X1dRjDMdp0gS9jJf-VAezfg',
      'https://res.wx.qq.com/op_res/0-l2fyKjv3_BR62E3KwTJNLlVMP9qArsQkkz294mrVFbI2pxwKxf0I1F8S86W4zZ8bcpuDv4xIWioikrD-85Dw',
      'https://res.wx.qq.com/op_res/0-l2fyKjv3_BR62E3KwTJOY6-yX_tVBt6ZC4ffTUqdnMXaCEKf0mYb8ebfl0l-VUKHzayRrbipPLqsynrTN0FA',
      'https://res.wx.qq.com/op_res/0-l2fyKjv3_BR62E3KwTJMgKiLq4XOYd9BtY9HCvD4BvuYDo9ro9XBb3_fQk90z8odHLs4eYvoHwkyKaM3ztZA',
      'https://res.wx.qq.com/op_res/0-l2fyKjv3_BR62E3KwTJH3eO7DeTKRV0Ys2vZ2aqUom-xWvymxzS3uiu06syi2vlj8hzWyIK1_inNHTVkuWPw',
      'https://res.wx.qq.com/op_res/0-l2fyKjv3_BR62E3KwTJA7-uaVSCPgd7Q32x1_vmHrDLaretZxRboZv2wZiNBkRdgihEvRhcWRHrm0vBUggzw',
      'https://res.wx.qq.com/op_res/0-l2fyKjv3_BR62E3KwTJBUmVY1MDz1vsXTJlQCPd-fHF8AsVCi6yVK4BxhjBXs085BQZaI6LoWW4GfnqMRqbg',
      'https://res.wx.qq.com/op_res/0-l2fyKjv3_BR62E3KwTJKh4kMbGYKCPnBu-ZWsQnn3NEFKDEN0DgdKH_R9v8Snkp-cfiU8dZd_abw5QcyiWBQ',
      'https://res.wx.qq.com/op_res/0-l2fyKjv3_BR62E3KwTJKPDdtcGoJzhB8HdWlDtWaxeIOvdYSmQoihkYQPrHDoGr2PJD31RPzqcz5u8b3rpoQ',
      'https://res.wx.qq.com/op_res/0-l2fyKjv3_BR62E3KwTJFryDUHWInyL4LeRP6y_wIUpf7kQSfrcGPcGeZbLuOtan8ml9SbJ1k0Qdgelf6iEBg',
      'https://res.wx.qq.com/op_res/0-l2fyKjv3_BR62E3KwTJE1YvpBMZCjoKqX1Sy1xqlqntchR2vwtu82wt0XLsCMUtsJ0x2K5fFvEiaouWbViFg',
      'https://res.wx.qq.com/op_res/0-l2fyKjv3_BR62E3KwTJIJE5jTu_BNqZ_LR4E82Kj6hBC7UlZ1BDeqhJEKDtQ-vTzpwv8m3Rj16kJtE2dSBAg',
      'https://res.wx.qq.com/op_res/0-l2fyKjv3_BR62E3KwTJBi8YFt3WToEbW0L6-BmqV4_HjXOvB0Z5IJ3GLVtBj8hcRP_O4mf9Ia6T8ITbfkKBw',
      'https://res.wx.qq.com/op_res/0-l2fyKjv3_BR62E3KwTJFIvGogPbbDumfRVNxlgPRqYwmSTuhsE2OyzcnJXRc49-6SanEHKsiPM-vIlUlGOFQ',
      'https://res.wx.qq.com/op_res/0-l2fyKjv3_BR62E3KwTJNt8AklXWChR3D1545zHosDzkcT6gNUv9UwevKbgsGE6_Skgr9Et86OA8tw3PgW0ew',
      'https://res.wx.qq.com/op_res/0-l2fyKjv3_BR62E3KwTJMNA5xeVo8u0lFyyFwLvexHmQTRi_oaiYuS6wCrZHm3931x3KbVeeLJv8hI2YvL1yQ',
      'https://res.wx.qq.com/op_res/0-l2fyKjv3_BR62E3KwTJD3V9rkvi7OQ852nZavb3k2sdVOl_JEjqRbhYBhgPPqhgaIkawklFj-4w5oQ9BR1xg',
      'https://res.wx.qq.com/op_res/0-l2fyKjv3_BR62E3KwTJDLPwxnddCKwDrDOjA9lWQkB1_2KcFc9L48-AjNV7lMTDV7EvpwWRy3aLVmvXmmi-w',
      'https://res.wx.qq.com/op_res/0-l2fyKjv3_BR62E3KwTJNMTtzowAlaXSt-ZZajhbZeYcZj9njs9Czy2iRLoh6m-PrGRaCb7koaoeVzHvMwrFg',
      'https://res.wx.qq.com/op_res/0-l2fyKjv3_BR62E3KwTJMQV_yLC-b3ewPS_sYPnmdwvIlB-IlyEjoyVtv13rE7Qulx6GR2H-p5JIIZNDWXg6Q',
      'https://res.wx.qq.com/op_res/SPJ17foR6CQ_1kS3N3iWEozVgUwwyXBMXhm7WFzcvPMGQH8Nqoh1jLUayawk0flboyz1IDNkU3foqBvNIgI11Q',
    ]
    const now = Date.now()
    srcList.forEach((src, index) => {
      const id = (now + index).toString()
      imageList.push({
        id,
        src,
        thumbnail: thumbnailList[index],
        createTime: now - (index * 3600 * 1000)
      })
    })
  }

  return imageList
}


================================================
FILE: examples/album/utils/worklet.js
================================================
export function getShared(renderer) {
  if (renderer === 'skyline') return wx.worklet.shared
  else return val => ({ value: val })
}

export function getTiming(renderer) {
  'worklet'
  if (renderer === 'skyline') return wx.worklet.timing
  else return (target, options, callback) => {
    if (typeof callback === 'function') setTimeout(callback, 0)
    return target
  }
}

export function getRunOnUI(renderer) {
  if (renderer === 'skyline') return wx.worklet.runOnUI
  else return func => func
}

export function getRunOnJS(renderer) {
  'worklet'
  if (renderer === 'skyline') return wx.worklet.runOnJS
  else return func => func
}


================================================
FILE: examples/app-bar/.eslintrc.js
================================================
/*
 * Eslint config file
 * Documentation: https://eslint.org/docs/user-guide/configuring/
 * Install the Eslint extension before using this feature.
 */
module.exports = {
  env: {
    es6: true,
    browser: true,
    node: true,
  },
  ecmaFeatures: {
    modules: true,
  },
  parserOptions: {
    ecmaVersion: 2018,
    sourceType: 'module',
  },
  globals: {
    wx: true,
    App: true,
    Page: true,
    getCurrentPages: true,
    getApp: true,
    Component: true,
    requirePlugin: true,
    requireMiniProgram: true,
  },
  // extends: 'eslint:recommended',
  rules: {},
}


================================================
FILE: examples/app-bar/app-bar/index.js
================================================
// components/app-bar/index.js

const { shared, timing, Easing } = wx.worklet

export const GestureState = {
  POSSIBLE: 0,
  BEGIN: 1,
  ACTIVE: 2,
  END: 3,
  CANCELLED: 4,
}

export const lerp = function (begin, end, t) {
  'worklet'
  return begin + (end - begin) * t
}

export const clamp = function (cur, lowerBound, upperBound) {
  'worklet'
  if (cur > upperBound) return upperBound
  if (cur < lowerBound) return lowerBound
  return cur
}

const systemInfo = wx.getSystemInfoSync()
const { statusBarHeight, screenHeight, screenWidth, safeArea } = systemInfo
console.info('@@@ systemInfo', systemInfo)
Component({
  properties: {

  },

  data: {
    maxCoverSize: 0,
    statusBarHeight: 0,
    musicCover: 'https://res.wx.qq.com/op_res/Nu9XXzXcXnD1j5EgWQ2ElxNcl1yMvnKypRo4MTbjOv7FC3saigGoOBTZibyESC7EXaClnPYhB6pvfb-IRmso6g'
  },

  lifetimes: {
    attached() {
      const progress = shared(0)
      const initCoverSize = 60 // 初始图片大小
      const pagePadding = 24
      const maxCoverSize = screenWidth - 2 * pagePadding
      const safeAreaInsetBottom = screenHeight - safeArea.bottom
      const isIOS = systemInfo.system.indexOf('iOS') >= 0
      this.setData({ statusBarHeight, maxCoverSize })

      this.applyAnimatedStyle('.cover', () => {
        'worklet'
        const height = initCoverSize + (maxCoverSize - initCoverSize) * progress.value
        return {
          width: `${height}px`,
          height:`${height}px`,
        }
      })

      this.applyAnimatedStyle('.expand-container', () => {
        'worklet'
        const t = progress.value
        const maxRadius = 30
        const radius = isIOS ? maxRadius * t : 0
        const initBarHeight = initCoverSize + 8 * 2 + safeAreaInsetBottom
        return {
          top: `${(screenHeight - initBarHeight) * (1 - t)}px`,
          borderRadius: `${radius}px ${radius}px 0px 0px`
        }
      })

      this.applyAnimatedStyle('.title-wrap', () => {
        'worklet'
        return {
          opacity: 1 - progress.value
        }
      })

      const navBarHeight = statusBarHeight + (isIOS ? 40 : 44)
      this.applyAnimatedStyle('.nav-bar', () => {
        'worklet'
        const t = progress.value
        const threshold = 0.8
        const opacity = t < threshold ? 0 : (t - threshold) / (1 - threshold)

        return {
          opacity,
          height: `${navBarHeight * progress.value}px`
        }
      })

      this.progress = progress
    }
  },

  methods: {
    close() {
      this.progress.value = timing(0, {
        duration: 250,
        easing: Easing.ease
      })
    },

    expand() {
      this.progress.value = timing(1, {
        duration: 250,
        easing: Easing.ease
      })
    },

    handleDragUpdate(delta) {
      'worklet'
      const curValue = this.progress.value
      const newVal = curValue - delta
      this.progress.value = clamp(newVal, 0.0, 1.0)
    },

    handleDragEnd(velocity) {
      'worklet'
      const t = this.progress.value
      let animateForward = false
      if (Math.abs(velocity) >= 1) {
        animateForward = velocity <= 0
      } else {
        animateForward = t > 0.7
      }
      const animationCurve = Easing.out(Easing.ease)
      if (animateForward) {
        this.progress.value = timing(
          1.0, {
          duration: 200,
          easing: animationCurve,
        })
      } else {
        this.progress.value = timing(
          0.0, {
          duration: 250,
          easing: animationCurve,
        })
      }
    },

    handleVerticalDrag(evt) {
      'worklet'
      if (evt.state === GestureState.ACTIVE) {
        const delta = evt.deltaY / screenHeight
        this.handleDragUpdate(delta)
      } else if (evt.state === GestureState.END) {
        const velocity = evt.velocityY / screenHeight
        this.handleDragEnd(velocity)
      } else if (evt.state === GestureState.CANCELLED) {
        this.handleDragEnd(0.0)
      }
    },
  },

})

================================================
FILE: examples/app-bar/app-bar/index.json
================================================
{
  "component": true,
  "usingComponents": {}
}

================================================
FILE: examples/app-bar/app-bar/index.wxml
================================================
<!-- components/app-bar/index.wxml -->
<vertical-drag-gesture-handler worklet:ongesture="handleVerticalDrag">
	<view class="expand-container">
		<!-- 放大模式:nav-bar -->
		<view class="nav-bar column">
			<view style="height: {{statusBarHeight}}px;" />
			<view style="flex: 1;" class="column-main-center">
				<image
				 class="icon--back"
				 mode="aspectFill"
				 src="/assets/arrow-down.png"
				 bind:tap="close"
				/>
			</view>
		</view>

		<!-- 跟着手势变化 -->
		<view class="cover-area" style="height: {{maxCoverSize}}px;">
			<view class="row " bind:tap="expand">
				<image class="cover" mode="aspectFill" src="{{musicCover}}" />
				<view class="title-wrap row-between">
					<view class="title column">
						<text overflow="ellipsis" max-lines="1">Skyline 渲染框架入门与实践</text>
						<text class="name" overflow="ellipsis" max-lines="1">小程序技术专员 - binnie</text>
					</view>
					<view class="row">
						<image class="icon" style="margin-right: 24px;" src="/assets/play.png" />
						<image class="icon" src="/assets/next.png" />
					</view>
				</view>
			</view>
		</view>

		<!-- 放大模式:小字 -->
		<view class="row-between">
			<text>微信学堂</text>
			<text>88 人在学</text>
		</view>

		<!-- 放大模式:标题 -->
		<view class="music-title column" style="margin-top: 50px;">
			<text>Skyline 渲染框架入门与实践</text>
			<text class="name">小程序技术专员 - binnie</text>
		</view>

		<!-- 底部操作栏 -->
		<view class="footer row-between" style="margin-top: 50px;">
			<image class="icon" src="/assets/next.png" style="transform: rotate(180deg);" />
			<image class="icon" src="/assets/play.png" />
			<image class="icon" src="/assets/next.png" />
		</view>
	</view>
</vertical-drag-gesture-handler>



================================================
FILE: examples/app-bar/app-bar/index.wxss
================================================
.expand-container {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  padding: 0 24px;
  padding-bottom: env(safe-area-inset-bottom);
  pointer-events: auto;
  overflow: hidden;
  background-color: #e9f8f7;
  color: #7e8081;
}

.hide {
  display: none;
}

.nav-bar {
  overflow: hidden;
  box-sizing: border-box;
}

.icon--back {
  width: 30px;
  height: 30px;
}

.title {
  margin-left: 10px;
  min-width: 160px;
  flex: 1;
}
.title .name {
  margin-top: 4px;
  font-size: 12px;
}

.title-wrap {
  flex: 1;
  min-width: 240px;
}

.footer {
  padding: 0 24px;
}

.footer .icon {
  width: 40px;
  height: 40px;
}

.expand-cover {
  width: 100%;
  height: 100%;
}

.music-title {
  margin-top: 48px;
  font-size: 20px;
  font-weight: bold;
  color: #07c160;
}
.music-title .name {
  margin-top: 12px;
  font-size: 14px;
  font-weight: 200;
  color: #b1b2b3;
}

.cover-area {
  margin: 8px 0;
  width: 100%;
  aspect-ratio: 1 / 1;
  overflow: hidden;
}

.cover {
  /* aspect-ratio: 1 / 1; */
  flex-shrink: 0;
}

.icon {
  width: 18px;
  height: 18px;
}

.row {
  display: flex;
  flex-direction: row;
  align-items: center;
}

.row-between {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  align-items: center;
}

.column {
  display: flex;
  flex-direction: column;
}

.column-main-center {
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.column-cross-center {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.center {
  display: flex;
  align-items: center;
  justify-content: center;
}

.circle {
  width: 100%;
  height: 100%;
  overflow: hidden;
  border-radius: 50%;
}

================================================
FILE: examples/app-bar/app.js
================================================
// app.js
App({})


================================================
FILE: examples/app-bar/app.json
================================================
{
  "pages": [
    "pages/index/index",
    "pages/detail/index"
  ],
  "window": {
    "navigationBarTextStyle": "black",
    "navigationStyle": "custom"
  },
  "style": "v2",
  "renderer": "skyline",
  "appBar": {},
  "rendererOptions": {
    "skyline": {
      "defaultDisplayBlock": true,
      "defaultContentBox": true,
      "disableABTest": true,
      "sdkVersionBegin": "3.0.0",
      "sdkVersionEnd": "15.255.255"
    }
  },
  "componentFramework": "glass-easel",
  "sitemapLocation": "sitemap.json",
  "lazyCodeLoading": "requiredComponents"
}

================================================
FILE: examples/app-bar/app.wxss
================================================
/**app.wxss**/
.container {
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-between;
  padding: 200rpx 0;
  box-sizing: border-box;
} 


================================================
FILE: examples/app-bar/components/navigation-bar/navigation-bar.js
================================================
Component({
  options: {
      multipleSlots: true // 在组件定义时的选项中启用多slot支持
  },
  /**
   * 组件的属性列表
   */
  properties: {
      extClass: {
          type: String,
          value: ''
      },
      title: {
          type: String,
          value: ''
      },
      background: {
          type: String,
          value: ''
      },
      color: {
          type: String,
          value: ''
      },
      back: {
          type: Boolean,
          value: true
      },
      loading: {
          type: Boolean,
          value: false
      },
      animated: {
          // 显示隐藏的时候opacity动画效果
          type: Boolean,
          value: true
      },
      show: {
          // 显示隐藏导航,隐藏的时候navigation-bar的高度占位还在
          type: Boolean,
          value: true,
          observer: '_showChange'
      },
      // back为true的时候,返回的页面深度
      delta: {
          type: Number,
          value: 1
      }
  },
  /**
   * 组件的初始数据
   */
  data: {
      displayStyle: ''
  },
  attached() {
    const isSupport = !!wx.getMenuButtonBoundingClientRect
    const rect = wx.getMenuButtonBoundingClientRect
        ? wx.getMenuButtonBoundingClientRect()
        : null
    wx.getSystemInfo({
        success: (res) => {
            const ios = !!(res.system.toLowerCase().search('ios') + 1)
            this.setData({
                ios,
                statusBarHeight: res.statusBarHeight,
                navBarHeight: rect.bottom - rect.top + 10,
                innerWidth: isSupport ? `width:${rect.left}px` : '',
                innerPaddingRight: isSupport
                    ? `padding-right:${res.windowWidth - rect.left}px`
                    : '',
                leftWidth: isSupport ? `width:${res.windowWidth - rect.left}px` : '',
                theme: res.theme || 'light',
            })
        }
    })

    if (wx.onThemeChange) {
      wx.onThemeChange(({theme}) => {
        this.setData({theme})
      })
    }
  },
  detached() {
    if (wx.offThemeChange) {
      wx.offThemeChange()
    }
  },
  /**
   * 组件的方法列表
   */
  methods: {
      _showChange(show) {
          const animated = this.data.animated
          let displayStyle = ''
          if (animated) {
              displayStyle = `opacity: ${
                  show ? '1' : '0'
              };-webkit-transition:opacity 0.5s;transition:opacity 0.5s;`
          } else {
              displayStyle = `display: ${show ? '' : 'none'}`
          }
          this.setData({
              displayStyle
          })
      },
      back() {
          const data = this.data
          console.log('---------222',getCurrentPages().length)
          if (data.delta) {
              wx.navigateBack({
                  delta: data.delta
              })
          }
          // 如果是直接打开的,就默认回首页
          if (getCurrentPages().length == 1) {
            console.log('---------333')
            wx.switchTab({
              url: '/page/component/index',
              complete: (res) => {
                console.log(res)
              }
            })
          }
          this.triggerEvent('back', { delta: data.delta }, {})
      }
  }
})


================================================
FILE: examples/app-bar/components/navigation-bar/navigation-bar.json
================================================
{
  "component": true,
  "usingComponents": {},
  "componentFramework": "glass-easel",
  "renderer": "skyline",
  "styleIsolation": "apply-shared"
}


================================================
FILE: examples/app-bar/components/navigation-bar/navigation-bar.wxml
================================================
<view class="weui-navigation-bar {{extClass}}" data-weui-theme="{{theme}}">
  <view class="weui-navigation-bar__inner" style="padding-top: {{statusBarHeight}}px; height: {{navBarHeight}}px; color: {{color}}; background: {{background}}; {{displayStyle}}; {{innerPaddingRight}};">
    <view class='weui-navigation-bar__left' style="{{leftWidth}}">
      <block wx:if="{{back}}">
        <view class="weui-navigation-bar__buttons">
          <view
            bindtap="back"
            class="weui-navigation-bar__btn_goback_wrapper"
            hover-class="weui-active"
            aria-role="button"
            aria-label="返回"
          >
            <view class="weui-navigation-bar__button weui-navigation-bar__btn_goback"></view>
          </view>
        </view>
      </block>
      <block wx:else>
        <slot name="left"></slot>
      </block>
    </view>

    <view class='weui-navigation-bar__center'>
      <view wx:if="{{loading}}" class="weui-navigation-bar__loading" aria-role="alert">
        <view
          class="weui-loading"
          style="width:{{size.width}}rpx;height:{{size.height}}rpx;"
          aria-role="img"
          aria-label="加载中"
        ></view>
      </view>
      <block wx:if="{{title}}">
        <text>{{title}}</text>
      </block>
      <block wx:else>
        <slot name="center"></slot>
      </block>
    </view>

    <view class='weui-navigation-bar__right'>
      <slot name="right"></slot>
    </view>
  </view>
</view>


================================================
FILE: examples/app-bar/components/navigation-bar/navigation-bar.wxss
================================================
.weui-navigation-bar {
  display: flex;
  overflow: hidden;
  color: rgba(0, 0, 0, .9);
  width: 100vw;
}

.weui-navigation-bar__placeholder {
  background: #f7f7f7;
  position: relative;
}

.weui-navigation-bar__inner, .weui-navigation-bar__inner .weui-navigation-bar__left {
  display: flex;
  align-items: center;
  flex-direction: row;
}

.weui-navigation-bar__inner {
  position: relative;
  padding-right: 95px;
  width: 100vw;
}

.weui-navigation-bar__inner .weui-navigation-bar__left {
  position: relative;
  width: 95px;
  padding-left: 16px;
}

.weui-navigation-bar__btn_goback_wrapper {
  padding: 11px 18px 11px 16px;
  margin: -11px -18px -11px -16px;
}

.weui-navigation-bar__inner .weui-navigation-bar__left .weui-navigation-bar__btn_goback {
  font-size: 12px;
  width: 12px;
  height: 24px;
  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%;
  background-color: currentColor;
  background-size: cover;
}

.weui-navigation-bar__inner .weui-navigation-bar__center {
  font-size: 17px;
  text-align: center;
  position: relative;
  flex: 1;
  display: flex; 
  align-items: center;
  justify-content: center;
  font-weight: bold;
}

[data-weui-theme=dark].weui-navigation-bar {
  color: hsla(0, 0%, 100%, .8);
}
[data-weui-theme=dark] .weui-navigation-bar__inner {
  background-color: #1f1f1f;
}


================================================
FILE: examples/app-bar/pages/detail/index.js
================================================
// pages/detail/index.js
const musicList = [
  {
    id: 0,
    coverImg: 'https://res.wx.qq.com/op_res/Nu9XXzXcXnD1j5EgWQ2ElxNcl1yMvnKypRo4MTbjOv7FC3saigGoOBTZibyESC7EXaClnPYhB6pvfb-IRmso6g',
    title: 'Skyline 渲染框架'
  },
  {
    id: 1,
    coverImg: 'https://res.wx.qq.com/op_res/Nu9XXzXcXnD1j5EgWQ2El3JJ3FgQX_YP9sI6kJD_nLjnkdN19yZ5nLtS3cqtNUx621vrni0Kjy5uoX_QMlBJgQ',
    title: '小程序性能优化'
  },
  {
    id: 2,
    coverImg: 'https://res.wx.qq.com/op_res/Nu9XXzXcXnD1j5EgWQ2ElwWbBogi5f0NNRBkuJWfE8HQzysKxBaoCJ-YBr7irwn_uE37dHQTWcHK2uOHIWsQ3Q',
    title: '医疗行业实践'
  },

]
Page({
  data: {
    music: musicList[0],
    albumMusicList: [
      {
      id: 0,
      coverImg: 'https://res.wx.qq.com/op_res/Nu9XXzXcXnD1j5EgWQ2ElxNcl1yMvnKypRo4MTbjOv7FC3saigGoOBTZibyESC7EXaClnPYhB6pvfb-IRmso6g',
      name: 'Skyline 渲染框架',
      author: '小程序技术专员 - binnie'
    },
    {
      id: 1,
      coverImg: 'https://res.wx.qq.com/op_res/Nu9XXzXcXnD1j5EgWQ2El3JJ3FgQX_YP9sI6kJD_nLjnkdN19yZ5nLtS3cqtNUx621vrni0Kjy5uoX_QMlBJgQ',
      name: '小程序性能优化',
      author: '小程序性能优化专家'
    },
    {
      id: 2,
      coverImg: 'https://res.wx.qq.com/op_res/Nu9XXzXcXnD1j5EgWQ2ElwWbBogi5f0NNRBkuJWfE8HQzysKxBaoCJ-YBr7irwn_uE37dHQTWcHK2uOHIWsQ3Q',
      name: '医疗行业实践',
      author: '小程序医疗行业专家'
    },
    ]
  },

  onLoad(query) {
    const idx = query.idx
    if (idx) {
      this.setData({
        music: musicList[idx]
      })
    }
  },

  onReady() {

  },


  onShow() {

  },
})

================================================
FILE: examples/app-bar/pages/detail/index.json
================================================
{
  "usingComponents": {
    "navigation-bar": "../../components/navigation-bar/navigation-bar"
  }
}

================================================
FILE: examples/app-bar/pages/detail/index.wxml
================================================
<navigation-bar
 title="微信学堂"
 back="{{true}}"
 color="black"
 background="#FFF"
/>
<scroll-view
 class="scroll-area"
 type="list"
 scroll-y
 show-scrollbar="{{false}}"
>
	<view class="cover-wrap center">
		<image class="cover" src="{{music.coverImg}}" mode="aspectFill" />
	</view>

	<view style="margin: 60px 0 24px;">为你推荐</view>
	<view class="album-music row" wx:for="{{albumMusicList}}" wx:key="id">
		<image class="album-music-cover" src="{{item.coverImg}}" mode="aspectFill" />
		<view class="column">
			<view>{{item.name}}</view>
			<view class="author">{{item.author}}</view>
		</view>
	</view>
</scroll-view>



================================================
FILE: examples/app-bar/pages/detail/index.wxss
================================================
page {
  display: flex;
  flex-direction: column;
  height: 100vh;
}

.scroll-area {
  flex: 1;
  overflow-y: hidden;
  padding: 0 24px;
  box-sizing: border-box;
  margin-bottom: calc(84px + env(safe-area-inset-bottom));
}

.intro {
  padding: 30px;
  text-align: center;
}

.cover {
  width: 250px;
  height: 250px;
}

.album-music {
  padding: 16px 0;
  border-top: 0.5px solid #f1e9e9;
}

.album-music-cover {
  width: 48px;
  height: 48px;
  margin-right: 16px;
}

.row {
  display: flex;
  flex-direction: row;
}

.row-between {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  align-items: center;
}

.column {
  display: flex;
  flex-direction: column;
}

.column-main-center {
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.column-cross-center {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.center {
  display: flex;
  align-items: center;
  justify-content: center;
}

.circle {
  width: 100%;
  height: 100%;
  overflow: hidden;
  border-radius: 50%;
}
.author {
  font-size: 12px;
  color: #7e8081;
  margin-top: 6px;
}


================================================
FILE: examples/app-bar/pages/index/index.js
================================================
const app = getApp()

Page({
  data: {
    back: false,
    maxCoverSize: 0,
    musicList: [
      {
        id: 0,
        coverImg: 'https://res.wx.qq.com/op_res/Nu9XXzXcXnD1j5EgWQ2ElxNcl1yMvnKypRo4MTbjOv7FC3saigGoOBTZibyESC7EXaClnPYhB6pvfb-IRmso6g',
        title: 'Skyline 渲染框架'
      },
      {
        id: 1,
        coverImg: 'https://res.wx.qq.com/op_res/Nu9XXzXcXnD1j5EgWQ2El3JJ3FgQX_YP9sI6kJD_nLjnkdN19yZ5nLtS3cqtNUx621vrni0Kjy5uoX_QMlBJgQ',
        title: '小程序性能优化'
      },
      {
        id: 2,
        coverImg: 'https://res.wx.qq.com/op_res/Nu9XXzXcXnD1j5EgWQ2ElwWbBogi5f0NNRBkuJWfE8HQzysKxBaoCJ-YBr7irwn_uE37dHQTWcHK2uOHIWsQ3Q',
        title: '医疗行业实践'
      },

    ]
  },
  onLoad() {
    // 在小程序示例中展示返回按钮
    if (this.route.includes('packageSkylineExamples/examples/')) {
      this.setData({
        back: true
      })
    }
  },
  onShow() {
    // 仅在 app-bar demo 页面展示
    if (typeof this.getAppBar === 'function' ) {
      const appBarComp = this.getAppBar()
      // component.getAppBar 在 Skyline 中返回 appBar 组件实例,在 webview 中返回 null
      if (appBarComp !== null) {
        appBarComp.setData({
          showAppbar: true
        })
      }
    }
  },

  goDetail(e) {
    const idx = e.currentTarget.dataset.idx
    wx.navigateTo({
      url: `../detail/index?idx=${idx}`,
    })
  }
})


================================================
FILE: examples/app-bar/pages/index/index.json
================================================
{
  "usingComponents": {
    "navigation-bar": "../../components/navigation-bar/navigation-bar"
  }
}

================================================
FILE: examples/app-bar/pages/index/index.wxml
================================================
<navigation-bar
 title="微信学堂"
 back="{{back}}"
 color="black"
 background="#FFF"
/>
<scroll-view
 class="scroll-area"
 type="list"
 scroll-y
 show-scrollbar="{{false}}"
>
	<view class="title">本月课程上新</view>
	<view class="cards">
		<view
		 class="card"
		 wx:for="{{musicList}}"
     wx:key="id"
     data-idx="{{index}}"
		 bind:tap="goDetail"
		>
			<image class="cover" mode="aspectFill" src="{{item.coverImg}}" />
			<view>{{item.title}}</view>
		</view>
	</view>
	<view class="title">最近学过</view>
	<view class="cards">
		<view
		 class="card"
		 wx:for="{{musicList}}"
     wx:key="id"
     data-idx="{{index}}"
		 bind:tap="goDetail"
		>
			<image class="cover" mode="aspectFill" src="{{item.coverImg}}" />
			<view>{{item.title}}</view>
		</view>
	</view>
</scroll-view>



================================================
FILE: examples/app-bar/pages/index/index.wxss
================================================
page {
  display: flex;
  flex-direction: column;
  height: 100vh;
}

.scroll-area {
  flex: 1;
  overflow-y: hidden;
  padding: 0 8px;
  box-sizing: border-box;
  margin-bottom: calc(84px + env(safe-area-inset-bottom));
}

.intro {
  padding: 30px;
  text-align: center;
}

.app-bar {
  position: absolute;
  width: 100vw;
  height: 100vh;
  pointer-events: none;
}

.title {
  margin-top: 16px;
  margin-left: 8px;
  font-size: 20px;
  font-weight: 600;
}

.cards {
  /* margin: 24px 0; */
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
}

.card {
  display: flex;
  justify-content: center;
  flex-direction: column;
  margin: 8px;
}

.cover {
  width: 43vw;
  height: 43vw;
  margin-bottom: 10px;
}

================================================
FILE: examples/app-bar/project.config.json
================================================
{
    "appid": "wxe5f52902cf4de896",
    "compileType": "miniprogram",
    "libVersion": "3.3.2",
    "packOptions": {
        "ignore": [],
        "include": []
    },
    "setting": {
        "coverView": true,
        "es6": true,
        "postcss": true,
        "minified": true,
        "enhance": true,
        "showShadowRootInWxmlPanel": true,
        "packNpmRelationList": [],
        "babelSetting": {
            "ignore": [],
            "disablePlugins": [],
            "outputPath": ""
        },
        "compileWorklet": true
    },
    "condition": {},
    "editorSetting": {
        "tabIndent": "auto",
        "tabSize": 4
    }
}

================================================
FILE: examples/app-bar/project.private.config.json
================================================
{
    "description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developer
Download .txt
gitextract_s27a10mg/

├── .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
    │   ├── 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
    │   ├── 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
    │   ├── 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/
    │   │   ├── index.json
    │   │   ├── index.less
    │   │   ├── index.ts
    │   │   └── index.wxml
    │   ├── goods.less
    │   ├── goods.wxml
    │   ├── 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
Download .txt
SYMBOL INDEX (252 symbols across 43 files)

FILE: examples/address-book/components/address-book/index.js
  method observer (line 44) | observer(newVal) {
  method created (line 80) | created() {
  method attached (line 87) | attached() {
  method handlePan (line 103) | handlePan(e) {
  method _handlePan (line 106) | _handlePan(e) {
  method cancelPan (line 122) | cancelPan() {
  method computedSize (line 127) | computedSize() {
  method handleScroll (line 138) | handleScroll(e) {
  method updateCurrent (line 157) | updateCurrent(idx) {

FILE: examples/address-book/components/navigation-bar/index.js
  method attached (line 56) | attached() {
  method _showChange (line 73) | _showChange(show) {
  method back (line 85) | back() {

FILE: examples/address-book/pages/index/index.js
  method attached (line 8) | attached() {

FILE: examples/album/components/album/album-image/index.js
  constant IMAGE_INIT_WIDTH (line 4) | const IMAGE_INIT_WIDTH = 0
  constant IMAGE_INIT_HEIGHT (line 5) | const IMAGE_INIT_HEIGHT = 1
  constant IMAGE_WIDTH (line 6) | const IMAGE_WIDTH = 2
  constant IMAGE_HEIGHT (line 7) | const IMAGE_HEIGHT = 3
  constant IMAGE_TARGET_WIDTH (line 8) | const IMAGE_TARGET_WIDTH = 4
  constant IMAGE_TARGET_HEIGHT (line 9) | const IMAGE_TARGET_HEIGHT = 5
  constant IMAGE_RATIO (line 10) | const IMAGE_RATIO = 6
  constant IN_PREVIEW (line 11) | const IN_PREVIEW = 7
  method 'width, height' (line 37) | 'width, height'() {
  method created (line 43) | created() {
  method attached (line 58) | attached() {
  method detached (line 123) | detached() {
  method onFrame (line 140) | onFrame(evt) {
  method onImageLoad (line 183) | onImageLoad(evt) {
  method renderImage (line 193) | renderImage() {

FILE: examples/album/components/album/index.js
  function transformListToLineBlock (line 4) | function transformListToLineBlock(list, lineLimit) {
  method 'list, lineLimit' (line 50) | 'list, lineLimit'(list, lineLimit) {
  method created (line 61) | created() {
  method attached (line 66) | attached() {
  method detached (line 86) | detached() {
  method onTapImage (line 93) | onTapImage(evt) {

FILE: examples/album/components/album/route.js
  function initRoute (line 3) | function initRoute() {

FILE: examples/album/components/navigation-bar/index.js
  method attached (line 56) | attached() {
  method _showChange (line 73) | _showChange(show) {
  method back (line 85) | back() {

FILE: examples/album/components/previewer/index.js
  constant TRANSLATE_X (line 27) | const TRANSLATE_X = 0
  constant TRANSLATE_Y (line 28) | const TRANSLATE_Y = 1
  constant START_Y (line 29) | const START_Y = 2
  constant OPACITY (line 30) | const OPACITY = 3
  constant SCALE (line 31) | const SCALE = 4
  constant MIN_SCALE (line 32) | const MIN_SCALE = 5
  constant USER_GESTURE_IN_PROGRESS (line 33) | const USER_GESTURE_IN_PROGRESS = 6
  constant GESTURE_STATE (line 34) | const GESTURE_STATE = 7
  constant PAGE_ID (line 35) | const PAGE_ID = 8
  constant TEMP_LAST_SCALE (line 36) | const TEMP_LAST_SCALE = 9
  constant RENDERER (line 37) | const RENDERER = 10
  function clamp (line 39) | function clamp(value, min, max) {
  function recoverTiming (line 44) | function recoverTiming(target, renderer, callback) {
  function calcOpacity (line 49) | function calcOpacity(moveY, screenHeight) {
  function calcScale (line 55) | function calcScale(moveY, screenHeight) {
  method created (line 79) | created() {
  method attached (line 99) | attached() {
  method detached (line 235) | detached() {
  method onScale (line 253) | onScale(evt) {
  method onBack (line 322) | onBack() {
  method shouldResponseOnMove (line 328) | shouldResponseOnMove() {

FILE: examples/album/components/previewer/preview-home/index.js
  method tempIndex (line 26) | tempIndex(tempIndex) {
  method attached (line 35) | attached() {
  method detached (line 47) | detached() {
  method onBeforeRender (line 54) | onBeforeRender(evt) {
  method onTapImage (line 61) | onTapImage() {
  method onBack (line 65) | onBack(evt) {

FILE: examples/album/components/previewer/preview-image/index.js
  constant MOVE_X (line 4) | const MOVE_X = 0
  constant MOVE_Y (line 5) | const MOVE_Y = 1
  constant SCALE (line 6) | const SCALE = 2
  constant IMG_WIDTH (line 7) | const IMG_WIDTH = 3
  constant IMG_HEIGHT (line 8) | const IMG_HEIGHT = 4
  constant IMG_MAX_SCALE (line 9) | const IMG_MAX_SCALE = 5
  constant IMG_MIN_SCALE (line 10) | const IMG_MIN_SCALE = 6
  constant IMG_MIN_MOVE_X (line 11) | const IMG_MIN_MOVE_X = 7
  constant IMG_MAX_MOVE_X (line 12) | const IMG_MAX_MOVE_X = 8
  constant IMG_MIN_MOVE_Y (line 13) | const IMG_MIN_MOVE_Y = 9
  constant IMG_MAX_MOVE_Y (line 14) | const IMG_MAX_MOVE_Y = 10
  constant GESTURE_STATE (line 15) | const GESTURE_STATE = 11
  constant TEMP_MOVE_X (line 16) | const TEMP_MOVE_X = 12
  constant TEMP_MOVE_Y (line 17) | const TEMP_MOVE_Y = 13
  constant TEMP_SCALE (line 18) | const TEMP_SCALE = 14
  constant INIT_MOVE_X (line 19) | const INIT_MOVE_X = 15
  constant INIT_MOVE_Y (line 20) | const INIT_MOVE_Y = 16
  constant INIT_SCALE (line 21) | const INIT_SCALE = 17
  constant CURRENT_ID (line 22) | const CURRENT_ID = 18
  constant PAGE_ID (line 23) | const PAGE_ID = 19
  constant RENDERER (line 24) | const RENDERER = 20
  constant DEFAULT_IMG_SCALE_MAX (line 26) | const DEFAULT_IMG_SCALE_MAX = 10
  function adjustTiming (line 31) | function adjustTiming(target, renderer, callback) {
  function recoverTiming (line 36) | function recoverTiming(target, renderer, callback) {
  function vibrateShort (line 41) | function vibrateShort(type = 'light') {
  method status (line 58) | status(status) {
  method created (line 74) | created() {
  method attached (line 102) | attached() {
  method detached (line 395) | detached() {
  method resetImg (line 416) | resetImg() {
  method onImgLoad (line 432) | onImgLoad(evt) {
  method onDoubleTap (line 493) | onDoubleTap(evt) {

FILE: examples/album/components/previewer/preview-list/index.js
  constant GESTURE_STATE (line 11) | const GESTURE_STATE = 0
  constant CURRENT_ID (line 12) | const CURRENT_ID = 1
  constant RENDERER (line 13) | const RENDERER = 2
  method list (line 33) | list(list) {
  method index (line 44) | index(index) {
  method created (line 62) | created() {
  method attached (line 72) | async attached() {
  method detached (line 128) | detached() {
  method toggleImage (line 146) | async toggleImage(index, disableAnimation = false) {
  method onImageRender (line 162) | onImageRender(evt) {
  method onTapImage (line 172) | onTapImage() {
  method shouldResponseOnMove (line 177) | shouldResponseOnMove() {
  method onSwiperChange (line 184) | onSwiperChange(evt) {

FILE: examples/album/pages/album/index.js
  method onLoad (line 11) | onLoad() {

FILE: examples/album/pages/preview/index.js
  method attached (line 22) | attached() {

FILE: examples/album/utils/event-bus.js
  function on (line 5) | function on(eventName, handler) {
  function off (line 10) | function off(eventName, handler) {
  function emit (line 18) | function emit(eventName, ...args) {
  function initWorkletEventBus (line 27) | function initWorkletEventBus(renderer) {

FILE: examples/album/utils/store.js
  function getAlbum (line 2) | function getAlbum() {

FILE: examples/album/utils/worklet.js
  function getShared (line 1) | function getShared(renderer) {
  function getTiming (line 6) | function getTiming(renderer) {
  function getRunOnUI (line 15) | function getRunOnUI(renderer) {
  function getRunOnJS (line 20) | function getRunOnJS(renderer) {

FILE: examples/app-bar/app-bar/index.js
  method attached (line 40) | attached() {
  method close (line 95) | close() {
  method expand (line 102) | expand() {
  method handleDragUpdate (line 109) | handleDragUpdate(delta) {
  method handleDragEnd (line 116) | handleDragEnd(velocity) {
  method handleVerticalDrag (line 141) | handleVerticalDrag(evt) {

FILE: examples/app-bar/components/navigation-bar/navigation-bar.js
  method attached (line 56) | attached() {
  method detached (line 84) | detached() {
  method _showChange (line 93) | _showChange(show) {
  method back (line 107) | back() {

FILE: examples/app-bar/pages/detail/index.js
  method onLoad (line 45) | onLoad(query) {
  method onReady (line 54) | onReady() {
  method onShow (line 59) | onShow() {

FILE: examples/app-bar/pages/index/index.js
  method onLoad (line 26) | onLoad() {
  method onShow (line 34) | onShow() {
  method goDetail (line 47) | goDetail(e) {

FILE: examples/associated-scroll-view/components/category-list/category-list.js
  method created (line 30) | created() {
  method attached (line 37) | attached() {
  method getCanSwipe (line 45) | getCanSwipe() {
  method setSwipingValue (line 48) | setSwipingValue(swiping) {
  method shouldScrollViewResp (line 51) | shouldScrollViewResp(e) {
  method handleScroll (line 59) | handleScroll(e) {

FILE: examples/associated-scroll-view/pages/index/index.js
  method created (line 12) | created() {
  method attached (line 18) | attached() {
  method shouldSwiperResp (line 26) | shouldSwiperResp() {
  method onSwiperStart (line 35) | onSwiperStart() {
  method onSwiperEnd (line 39) | onSwiperEnd() {
  method onChange (line 43) | onChange(e) {

FILE: examples/associated-scroll-view/util.js
  function getCategories (line 1) | function getCategories() {
  function getProducts (line 31) | function getProducts() {

FILE: examples/card_transition/components/card/card.js
  method created (line 27) | created() {
  method attached (line 42) | attached() {
  method navigateTo (line 94) | navigateTo(e) {
  method handleFrame (line 102) | handleFrame(data) {

FILE: examples/card_transition/components/navigation-bar/index.js
  method attached (line 56) | attached() {
  method _showChange (line 73) | _showChange(show) {
  method back (line 85) | back() {

FILE: examples/card_transition/pages/detail/detail.js
  method created (line 49) | created() {
  method attached (line 56) | attached() {
  method handlePanGesture (line 122) | handlePanGesture(e) {

FILE: examples/card_transition/pages/list/list.js
  method created (line 14) | created() {

FILE: examples/card_transition/pages/list/route.js
  function CurveAnimation (line 18) | function CurveAnimation({
  function installRouteBuilder (line 144) | function installRouteBuilder() {

FILE: examples/expanded-scroll-view/pages/index/index.js
  method created (line 43) | created() {
  method attached (line 53) | attached() {
  method onBannerLoaded (line 68) | onBannerLoaded() {
  method updateNavBackColor (line 79) | updateNavBackColor(expand) {
  method bindAnimatedStyle (line 82) | bindAnimatedStyle() {
  method handlePan (line 145) | handlePan(e) {
  method shouldPanResponse (line 202) | shouldPanResponse() {
  method handleScroll (line 206) | handleScroll(e) {
  method shouldScrollViewResponse (line 218) | shouldScrollViewResponse(e) {
  method adjustDeceleration (line 228) | adjustDeceleration(velocity) {

FILE: examples/expanded-scroll-view/util.js
  function getCategory (line 1) | function getCategory() {
  function getProducts (line 17) | function getProducts() {

FILE: examples/half-screen/pages/index/comment-data.js
  function getCommentList (line 2) | function getCommentList() {

FILE: examples/half-screen/pages/index/index.js
  method created (line 18) | created() {
  method ready (line 24) | ready() {
  method onTapOpenComment (line 39) | onTapOpenComment() {
  method openComment (line 42) | openComment(duration) {
  method onTapCloseComment (line 46) | onTapCloseComment() {
  method closeComment (line 49) | closeComment() {
  method shouldPanResponse (line 54) | shouldPanResponse() {
  method shouldScrollViewResponse (line 58) | shouldScrollViewResponse(pointerEvent) {
  method handlePan (line 69) | handlePan(gestureEvent) {
  method adjustDecelerationVelocity (line 88) | adjustDecelerationVelocity(velocity) {
  method handleScroll (line 93) | handleScroll(evt) {

FILE: examples/product-list/components/navigation-bar/index.js
  method attached (line 56) | attached() {
  method _showChange (line 73) | _showChange(show) {
  method back (line 85) | back() {

FILE: examples/product-list/pages/index/index.js
  method created (line 38) | created() {
  method attached (line 42) | attached() {
  method chooseVipCategory (line 71) | chooseVipCategory(evt) {
  method handleScrollUpdate (line 79) | handleScrollUpdate(evt) {

FILE: examples/product-list/util.js
  function getCategory (line 1) | function getCategory() {
  function getGoods (line 34) | function getGoods(num) {
  function getVIPCategory (line 72) | function getVIPCategory() {

FILE: examples/refresher-two-level/components/navigation-bar/index.js
  method attached (line 56) | attached() {
  method _showChange (line 73) | _showChange(show) {
  method back (line 85) | back() {

FILE: examples/refresher-two-level/goods/index.ts
  method back (line 18) | back() {
  method onRouteDone (line 26) | onRouteDone() {
  method onLoad (line 36) | onLoad() {
  method onReady (line 43) | onReady() {
  method onShow (line 50) | onShow() {
  method onHide (line 57) | onHide() {
  method onUnload (line 64) | onUnload() {
  method onPullDownRefresh (line 71) | onPullDownRefresh() {
  method onReachBottom (line 78) | onReachBottom() {
  method onShareAppMessage (line 85) | onShareAppMessage() {

FILE: examples/refresher-two-level/index/index.ts
  type RefreshStatus (line 3) | enum RefreshStatus {
  method created (line 67) | created() {
  method attached (line 71) | attached() {
  method chooseVipCategory (line 110) | chooseVipCategory(evt) {
  method handleScrollStart (line 118) | handleScrollStart(evt) {
  method handleScrollUpdate (line 123) | handleScrollUpdate(evt) {
  method handleScrollEnd (line 132) | handleScrollEnd(evt) {
  method onPulling (line 136) | onPulling(e) {
  method onRefresh (line 140) | onRefresh() {
  method onRestore (line 152) | onRestore(e) {
  method onAbort (line 156) | onAbort(e) {
  method closeTwoLevel (line 160) | closeTwoLevel() {
  method onStatusChange (line 166) | onStatusChange(e) {
  method buildText (line 193) | buildText(status: RefreshStatus) {

FILE: examples/refresher-two-level/util.js
  function getCategory (line 1) | function getCategory() {
  function getGoods (line 34) | function getGoods(num) {
  function getVIPCategory (line 72) | function getVIPCategory() {
  function getExpCategory (line 86) | function getExpCategory() {
  function getVideoList (line 100) | function getVideoList(num) {

FILE: examples/segmented-half-screen/pages/index/comment-data.js
  function getCommentList (line 2) | function getCommentList() {

FILE: examples/segmented-half-screen/pages/index/index.js
  function clamp (line 3) | function clamp(val, min, max) {
  method created (line 26) | created() {
  method attached (line 33) | attached() {
  method ready (line 38) | ready() {
  method setMapScale (line 53) | setMapScale(scale) {
  method scrollTo (line 56) | scrollTo(toValue) {
  method shouldPanResponse (line 67) | shouldPanResponse() {
  method shouldScrollViewResponse (line 71) | shouldScrollViewResponse(pointerEvent) {
  method handlePan (line 84) | handlePan(gestureEvent) {
  method adjustDecelerationVelocity (line 120) | adjustDecelerationVelocity(velocity) {
  method handleScroll (line 125) | handleScroll(evt) {
  method handleTouchEnd (line 130) | handleTouchEnd() {

FILE: examples/tab-indicator/components/navigation-bar/index.js
  method attached (line 56) | attached() {
  method _showChange (line 73) | _showChange(show) {
  method back (line 85) | back() {

FILE: examples/tab-indicator/pages/index/index.js
  method created (line 36) | created() {
  method attached (line 47) | attached() {
  method onTapTab (line 58) | onTapTab(evt) {
  method onTabChanged (line 65) | onTabChanged(evt) {
  method onTabTransition (line 78) | onTabTransition(evt) {
  method onTabTransitionEnd (line 94) | onTabTransitionEnd(evt) {
Condensed preview — 218 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (409K chars).
[
  {
    "path": ".gitignore",
    "chars": 10,
    "preview": ".DS_Store\n"
  },
  {
    "path": "LICENSE",
    "chars": 1075,
    "preview": "MIT License\n\nCopyright (c) 2023 wechat-miniprogram\n\nPermission is hereby granted, free of charge, to any person obtainin"
  },
  {
    "path": "README.md",
    "chars": 552,
    "preview": "# awesome-skyline\n\nSkyline 是微信小程序推出的新渲染引擎,用于替代 WebView 渲染,其能够带来更好的渲染性能,并且添加了诸多增强特性,让小程序拥有更接近原生的交互体验。更多细节可查看[文档](https://"
  },
  {
    "path": "examples/address-book/.eslintrc.js",
    "chars": 587,
    "preview": "/*\n * Eslint config file\n * Documentation: https://eslint.org/docs/user-guide/configuring/\n * Install the Eslint extensi"
  },
  {
    "path": "examples/address-book/app.js",
    "chars": 18,
    "preview": "// app.js\nApp({})\n"
  },
  {
    "path": "examples/address-book/app.json",
    "chars": 567,
    "preview": "{\n  \"pages\": [\n    \"pages/index/index\"\n  ],\n  \"window\": {\n    \"backgroundTextStyle\": \"light\",\n    \"navigationBarBackgrou"
  },
  {
    "path": "examples/address-book/app.wxss",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "examples/address-book/components/address-book/index.js",
    "chars": 4476,
    "preview": "const throttle = function throttle(func, wait, options) {\n  let context\n  let args\n  let result = void 0\n  let timeout\n "
  },
  {
    "path": "examples/address-book/components/address-book/index.json",
    "chars": 114,
    "preview": "{\n  \"component\": true,\n  \"usingComponents\": {},\n  \"addGlobalClass\": false,\n  \"componentFramework\": \"glass-easel\"\n}"
  },
  {
    "path": "examples/address-book/components/address-book/index.wxml",
    "chars": 1455,
    "preview": "<!-- 主列表 -->\n<scroll-view\n  type=\"custom\"\n  scroll-y\n  show-scrollbar=\"{{false}}\"\n  scroll-into-view=\"{{intoView}}\"\n  cl"
  },
  {
    "path": "examples/address-book/components/address-book/index.wxss",
    "chars": 2800,
    "preview": ".wx-flex {\n  display: flex;\n  align-items: center\n}\n\n.scroll-view {\n  height: 100%;\n}\n\n.thin-border-bottom {\n  position:"
  },
  {
    "path": "examples/address-book/components/navigation-bar/index.js",
    "chars": 1854,
    "preview": "Component({\n  options: {\n    multipleSlots: true // 在组件定义时的选项中启用多slot支持\n  },\n  /**\n   * 组件的属性列表\n   */\n  properties: {\n  "
  },
  {
    "path": "examples/address-book/components/navigation-bar/index.json",
    "chars": 113,
    "preview": "{\n  \"component\": true,\n  \"usingComponents\": {},\n  \"addGlobalClass\": true,\n  \"componentFramework\": \"glass-easel\"\n}"
  },
  {
    "path": "examples/address-book/components/navigation-bar/index.wxml",
    "chars": 1186,
    "preview": "<view class=\"weui-navigation-bar {{extClass}}\">\n  <view class=\"weui-navigation-bar__inner\" style=\"padding-top: {{statusB"
  },
  {
    "path": "examples/address-book/components/navigation-bar/index.wxss",
    "chars": 1607,
    "preview": ".weui-navigation-bar {\n  overflow: hidden;\n  color: rgba(0, 0, 0, .9);\n  width: 100vw;\n}\n\n.weui-navigation-bar__placehol"
  },
  {
    "path": "examples/address-book/pages/index/data.js",
    "chars": 72364,
    "preview": "export const cityData = [{ \"fullname\": \"东城区\", \"id\": \"110101\", \"location\": { \"lat\": 39.92855, \"lng\": 116.41637 }, \"name\":"
  },
  {
    "path": "examples/address-book/pages/index/index.js",
    "chars": 922,
    "preview": "import {cityData} from './data'\n\nComponent({\n  data: {\n    list: [],\n  },\n  lifetimes: {\n    attached() {\n      const ci"
  },
  {
    "path": "examples/address-book/pages/index/index.json",
    "chars": 195,
    "preview": "{\n  \"usingComponents\": {\n    \"navigation-bar\": \"../../components/navigation-bar\",\n    \"address-book\": \"../../components/"
  },
  {
    "path": "examples/address-book/pages/index/index.wxml",
    "chars": 376,
    "preview": "<navigation-bar title=\"通讯录\" back=\"{{true}}\"></navigation-bar>\n<view class=\"page-container\">\n  <address-book list=\"{{list"
  },
  {
    "path": "examples/address-book/pages/index/index.wxss",
    "chars": 677,
    "preview": "page {\n  display: flex;\n  flex-direction: column;\n  align-items: flex-end;\n  height: 100vh;\n  background-color: #f7f7f7;"
  },
  {
    "path": "examples/address-book/project.config.json",
    "chars": 659,
    "preview": "{\n  \"appid\": \"wxe5f52902cf4de896\",\n  \"compileType\": \"miniprogram\",\n  \"libVersion\": \"latest\",\n  \"packOptions\": {\n    \"ign"
  },
  {
    "path": "examples/address-book/project.private.config.json",
    "chars": 308,
    "preview": "{\n  \"description\": \"项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/"
  },
  {
    "path": "examples/address-book/sitemap.json",
    "chars": 169,
    "preview": "{\n    \"desc\": \"关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html\",\n    \"rules\": ["
  },
  {
    "path": "examples/album/app.js",
    "chars": 8,
    "preview": "App({})\n"
  },
  {
    "path": "examples/album/app.json",
    "chars": 624,
    "preview": "{\n  \"pages\": [\n    \"pages/album/index\",\n    \"pages/preview/index\"\n  ],\n  \"window\": {\n    \"backgroundColor\": \"#ffffff\",\n "
  },
  {
    "path": "examples/album/app.wxss",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "examples/album/components/album/album-image/index.js",
    "chars": 7526,
    "preview": "import EventBus from '../../../utils/event-bus'\nimport { getShared, getRunOnUI } from '../../../utils/worklet'\n\nconst IM"
  },
  {
    "path": "examples/album/components/album/album-image/index.json",
    "chars": 87,
    "preview": "{\n  \"component\": true,\n  \"usingComponents\": {},\n  \"componentFramework\": \"glass-easel\"\n}"
  },
  {
    "path": "examples/album/components/album/album-image/index.wxml",
    "chars": 275,
    "preview": "<share-element class=\"share-element\" key=\"{{image.id}}\" rect-tween-type=\"cubic-bezier(0.4, 0, 0.2, 1.0)\" worklet:onframe"
  },
  {
    "path": "examples/album/components/album/album-image/index.wxss",
    "chars": 383,
    "preview": ".share-element {\n  position: relative;\n  width: 100%;\n  height: 100%;\n}\n\n.img-cut-cnt {\n  position: absolute;\n  top: 0;\n"
  },
  {
    "path": "examples/album/components/album/index.js",
    "chars": 2421,
    "preview": "import EventBus from '../../utils/event-bus'\nimport { initRoute } from './route'\n\nfunction transformListToLineBlock(list"
  },
  {
    "path": "examples/album/components/album/index.json",
    "chars": 131,
    "preview": "{\n  \"component\": true,\n  \"usingComponents\": {\n    \"album-image\": \"./album-image/index\"\n  },\n  \"componentFramework\": \"gla"
  },
  {
    "path": "examples/album/components/album/index.wxml",
    "chars": 831,
    "preview": "  <scroll-view\n    class=\"scroll-list\"\n    style=\"padding-top: {{imageMargin}}px;\"\n    scroll-y\n    type=\"list\"\n    scro"
  },
  {
    "path": "examples/album/components/album/index.wxss",
    "chars": 199,
    "preview": ".scroll-list {\n  width: 100%;\n  height: 100%;\n  overflow: hidden;\n}\n\n.line {\n  display: flex;\n  flex-direction: row;\n  j"
  },
  {
    "path": "examples/album/components/album/route.js",
    "chars": 531,
    "preview": "const fastOutSlowIn = wx.worklet.Easing.bezier(0.4, 0.0, 0.2, 1.0).factory()\n\nexport function initRoute() {\n  wx.router."
  },
  {
    "path": "examples/album/components/navigation-bar/index.js",
    "chars": 1854,
    "preview": "Component({\n  options: {\n    multipleSlots: true // 在组件定义时的选项中启用多slot支持\n  },\n  /**\n   * 组件的属性列表\n   */\n  properties: {\n  "
  },
  {
    "path": "examples/album/components/navigation-bar/index.json",
    "chars": 113,
    "preview": "{\n  \"component\": true,\n  \"usingComponents\": {},\n  \"addGlobalClass\": true,\n  \"componentFramework\": \"glass-easel\"\n}"
  },
  {
    "path": "examples/album/components/navigation-bar/index.wxml",
    "chars": 1326,
    "preview": "<view class=\"weui-navigation-bar {{extClass}}\">\n  <view class=\"weui-navigation-bar__inner\" style=\"padding-top: {{statusB"
  },
  {
    "path": "examples/album/components/navigation-bar/index.wxss",
    "chars": 1612,
    "preview": ".weui-navigation-bar {\n  overflow: hidden;\n  color: rgba(0, 0, 0, .9);\n  width: 100vw;\n}\n\n.weui-navigation-bar__placehol"
  },
  {
    "path": "examples/album/components/previewer/index.js",
    "chars": 10637,
    "preview": "import EventBus from '../../utils/event-bus'\nimport { getShared, getTiming, getRunOnUI } from '../../utils/worklet'\n\ncon"
  },
  {
    "path": "examples/album/components/previewer/index.json",
    "chars": 133,
    "preview": "{\n  \"component\": true,\n  \"usingComponents\": {\n    \"preview-home\": \"./preview-home/index\"\n  },\n  \"componentFramework\": \"g"
  },
  {
    "path": "examples/album/components/previewer/index.wxml",
    "chars": 376,
    "preview": "<scale-gesture-handler\n  tag=\"scale\"\n  simultaneousHandlers=\"{{['swiper']}}\"\n  worklet:ongesture=\"onScale\"\n  worklet:sho"
  },
  {
    "path": "examples/album/components/previewer/index.wxss",
    "chars": 67,
    "preview": ".preview-home {\n  width: 100%;\n  height: 100%;\n  display: block;\n}\n"
  },
  {
    "path": "examples/album/components/previewer/preview-home/index.js",
    "chars": 1409,
    "preview": "import EventBus from '../../../utils/event-bus'\n\nComponent({\n  properties: {\n    imageId: {\n      type: String,\n      va"
  },
  {
    "path": "examples/album/components/previewer/preview-home/index.json",
    "chars": 186,
    "preview": "{\n  \"component\": true,\n  \"usingComponents\": {\n    \"preview-list\": \"../preview-list/index\",\n    \"navigation-bar\": \"../../"
  },
  {
    "path": "examples/album/components/previewer/preview-home/index.wxml",
    "chars": 856,
    "preview": "<view class=\"navigation-bar-cnt {{pretty ? 'hide' : 'show'}}\">\n  <share-element key=\"navigation-bar\">\n    <navigation-ba"
  },
  {
    "path": "examples/album/components/previewer/preview-home/index.wxss",
    "chars": 1115,
    "preview": ".preview-cnt {\n  position: absolute;\n  left: 0;\n  top: 0;\n  width: 100vw;\n  height: 100vh;\n  z-index: 5;\n}\n\n.preview-lis"
  },
  {
    "path": "examples/album/components/previewer/preview-image/index.js",
    "chars": 18738,
    "preview": "import { getShared, getTiming, getRunOnUI, getRunOnJS } from '../../../utils/worklet'\n\n// sharedValues\nconst MOVE_X = 0\n"
  },
  {
    "path": "examples/album/components/previewer/preview-image/index.json",
    "chars": 87,
    "preview": "{\n  \"component\": true,\n  \"usingComponents\": {},\n  \"componentFramework\": \"glass-easel\"\n}"
  },
  {
    "path": "examples/album/components/previewer/preview-image/index.wxml",
    "chars": 324,
    "preview": "<double-tap-gesture-handler class=\"double-tap-gesture-handler\" worklet:ongesture=\"onDoubleTap\">\n  <view id=\"image\" class"
  },
  {
    "path": "examples/album/components/previewer/preview-image/index.wxss",
    "chars": 272,
    "preview": ".double-tap-gesture-handler {\n  display: block;\n  width: 100%;\n  height: 100%;\n}\n\n.image-wrapper {\n  position: absolute;"
  },
  {
    "path": "examples/album/components/previewer/preview-list/index.js",
    "chars": 5529,
    "preview": "import { getShared, getRunOnUI, getRunOnJS } from '../../../utils/worklet'\n\nconst PreviewerGesture = {\n  Init: 0, // 初始\n"
  },
  {
    "path": "examples/album/components/previewer/preview-list/index.json",
    "chars": 136,
    "preview": "{\n  \"component\": true,\n  \"usingComponents\": {\n    \"preview-image\": \"../preview-image/index\"\n  },\n  \"componentFramework\":"
  },
  {
    "path": "examples/album/components/previewer/preview-list/index.wxml",
    "chars": 922,
    "preview": "<view class=\"image-previewer\">\n  <horizontal-drag-gesture-handler\n    tag=\"swiper\"\n    simultaneousHandlers=\"{{['scale']"
  },
  {
    "path": "examples/album/components/previewer/preview-list/index.wxss",
    "chars": 284,
    "preview": "\n.image-previewer {\n  width: 100vw;\n  height: 100vh;\n  overflow: hidden;\n}\n\n.swiper-cnt {\n  display: flex;\n  flex-direct"
  },
  {
    "path": "examples/album/pages/album/index.js",
    "chars": 401,
    "preview": "import { getAlbum } from '../../utils/store'\n\nPage({\n  data: {\n    imageWidth: 0,\n    imageMargin: 12, // 图片间距\n    lineL"
  },
  {
    "path": "examples/album/pages/album/index.json",
    "chars": 193,
    "preview": "{\n  \"usingComponents\": {\n    \"navigation-bar\": \"../../components/navigation-bar/index\",\n    \"album\": \"../../components/a"
  },
  {
    "path": "examples/album/pages/album/index.wxml",
    "chars": 345,
    "preview": "<view class=\"cnt\">\n  <share-element key=\"navigation-bar\">\n    <navigation-bar title=\"相册图片预览\" back></navigation-bar>\n  </"
  },
  {
    "path": "examples/album/pages/album/index.wxss",
    "chars": 242,
    "preview": ".cnt {\n  position: absolute;\n  top: 0;\n  width: 100%;\n  height: 100%;\n  display: flex;\n  flex-direction: column;\n}\n\n.alb"
  },
  {
    "path": "examples/album/pages/preview/index.js",
    "chars": 660,
    "preview": "import { getAlbum } from '../../utils/store'\n\nComponent({\n  properties: {\n    imageid: {\n      type: String,\n      value"
  },
  {
    "path": "examples/album/pages/preview/index.json",
    "chars": 244,
    "preview": "{\n  \"usingComponents\": {\n    \"previewer\": \"../../components/previewer/index\"\n  },\n  \"navigationStyle\": \"custom\",\n  \"back"
  },
  {
    "path": "examples/album/pages/preview/index.wxml",
    "chars": 146,
    "preview": "<view class=\"box-cotainer\">\n  <previewer\n    imageId=\"{{imageId}}\"\n    sourcePageId=\"{{sourcePageId}}\"\n    list=\"{{list}"
  },
  {
    "path": "examples/album/pages/preview/index.wxss",
    "chars": 163,
    "preview": "page {\n  background-color: transparent;\n}\n\n.box-cotainer {\n  width: 100vw;\n  height: 100vh;\n  position: relative;\n}\n\n.pr"
  },
  {
    "path": "examples/album/project.config.json",
    "chars": 1308,
    "preview": "{\n  \"description\": \"项目配置文件\",\n  \"packOptions\": {\n    \"ignore\": [],\n    \"include\": []\n  },\n  \"setting\": {\n    \"bundle\": fa"
  },
  {
    "path": "examples/album/project.private.config.json",
    "chars": 301,
    "preview": "{\n  \"description\": \"项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/"
  },
  {
    "path": "examples/album/sitemap.json",
    "chars": 159,
    "preview": "{\n  \"desc\": \"关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html\",\n  \"rules\": [{\n  "
  },
  {
    "path": "examples/album/utils/event-bus.js",
    "chars": 1617,
    "preview": "import { getRunOnUI } from './worklet'\n\nconst map = {}\n\nfunction on(eventName, handler) {\n  map[eventName] = map[eventNa"
  },
  {
    "path": "examples/album/utils/store.js",
    "chars": 6925,
    "preview": "const imageList = []\nexport function getAlbum() {\n  if (!imageList.length) {\n    const srcList = [\n      'https://res.wx"
  },
  {
    "path": "examples/album/utils/worklet.js",
    "chars": 636,
    "preview": "export function getShared(renderer) {\n  if (renderer === 'skyline') return wx.worklet.shared\n  else return val => ({ val"
  },
  {
    "path": "examples/app-bar/.eslintrc.js",
    "chars": 587,
    "preview": "/*\n * Eslint config file\n * Documentation: https://eslint.org/docs/user-guide/configuring/\n * Install the Eslint extensi"
  },
  {
    "path": "examples/app-bar/app-bar/index.js",
    "chars": 3944,
    "preview": "// components/app-bar/index.js\n\nconst { shared, timing, Easing } = wx.worklet\n\nexport const GestureState = {\n  POSSIBLE:"
  },
  {
    "path": "examples/app-bar/app-bar/index.json",
    "chars": 48,
    "preview": "{\n  \"component\": true,\n  \"usingComponents\": {}\n}"
  },
  {
    "path": "examples/app-bar/app-bar/index.wxml",
    "chars": 1671,
    "preview": "<!-- components/app-bar/index.wxml -->\n<vertical-drag-gesture-handler worklet:ongesture=\"handleVerticalDrag\">\n\t<view cla"
  },
  {
    "path": "examples/app-bar/app-bar/index.wxss",
    "chars": 1667,
    "preview": ".expand-container {\n  position: absolute;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  padding: 0 24px;\n  padding-bot"
  },
  {
    "path": "examples/app-bar/app.js",
    "chars": 18,
    "preview": "// app.js\nApp({})\n"
  },
  {
    "path": "examples/app-bar/app.json",
    "chars": 555,
    "preview": "{\n  \"pages\": [\n    \"pages/index/index\",\n    \"pages/detail/index\"\n  ],\n  \"window\": {\n    \"navigationBarTextStyle\": \"black"
  },
  {
    "path": "examples/app-bar/app.wxss",
    "chars": 194,
    "preview": "/**app.wxss**/\n.container {\n  height: 100%;\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  justify-"
  },
  {
    "path": "examples/app-bar/components/navigation-bar/navigation-bar.js",
    "chars": 3107,
    "preview": "Component({\n  options: {\n      multipleSlots: true // 在组件定义时的选项中启用多slot支持\n  },\n  /**\n   * 组件的属性列表\n   */\n  properties: {\n"
  },
  {
    "path": "examples/app-bar/components/navigation-bar/navigation-bar.json",
    "chars": 149,
    "preview": "{\n  \"component\": true,\n  \"usingComponents\": {},\n  \"componentFramework\": \"glass-easel\",\n  \"renderer\": \"skyline\",\n  \"style"
  },
  {
    "path": "examples/app-bar/components/navigation-bar/navigation-bar.wxml",
    "chars": 1474,
    "preview": "<view class=\"weui-navigation-bar {{extClass}}\" data-weui-theme=\"{{theme}}\">\n  <view class=\"weui-navigation-bar__inner\" s"
  },
  {
    "path": "examples/app-bar/components/navigation-bar/navigation-bar.wxss",
    "chars": 1580,
    "preview": ".weui-navigation-bar {\n  display: flex;\n  overflow: hidden;\n  color: rgba(0, 0, 0, .9);\n  width: 100vw;\n}\n\n.weui-navigat"
  },
  {
    "path": "examples/app-bar/pages/detail/index.js",
    "chars": 1467,
    "preview": "// pages/detail/index.js\nconst musicList = [\n  {\n    id: 0,\n    coverImg: 'https://res.wx.qq.com/op_res/Nu9XXzXcXnD1j5Eg"
  },
  {
    "path": "examples/app-bar/pages/detail/index.json",
    "chars": 101,
    "preview": "{\n  \"usingComponents\": {\n    \"navigation-bar\": \"../../components/navigation-bar/navigation-bar\"\n  }\n}"
  },
  {
    "path": "examples/app-bar/pages/detail/index.wxml",
    "chars": 620,
    "preview": "<navigation-bar\n title=\"微信学堂\"\n back=\"{{true}}\"\n color=\"black\"\n background=\"#FFF\"\n/>\n<scroll-view\n class=\"scroll-area\"\n t"
  },
  {
    "path": "examples/app-bar/pages/detail/index.wxss",
    "chars": 1111,
    "preview": "page {\n  display: flex;\n  flex-direction: column;\n  height: 100vh;\n}\n\n.scroll-area {\n  flex: 1;\n  overflow-y: hidden;\n  "
  },
  {
    "path": "examples/app-bar/pages/index/index.js",
    "chars": 1314,
    "preview": "const app = getApp()\n\nPage({\n  data: {\n    back: false,\n    maxCoverSize: 0,\n    musicList: [\n      {\n        id: 0,\n   "
  },
  {
    "path": "examples/app-bar/pages/index/index.json",
    "chars": 101,
    "preview": "{\n  \"usingComponents\": {\n    \"navigation-bar\": \"../../components/navigation-bar/navigation-bar\"\n  }\n}"
  },
  {
    "path": "examples/app-bar/pages/index/index.wxml",
    "chars": 777,
    "preview": "<navigation-bar\n title=\"微信学堂\"\n back=\"{{back}}\"\n color=\"black\"\n background=\"#FFF\"\n/>\n<scroll-view\n class=\"scroll-area\"\n t"
  },
  {
    "path": "examples/app-bar/pages/index/index.wxss",
    "chars": 714,
    "preview": "page {\n  display: flex;\n  flex-direction: column;\n  height: 100vh;\n}\n\n.scroll-area {\n  flex: 1;\n  overflow-y: hidden;\n  "
  },
  {
    "path": "examples/app-bar/project.config.json",
    "chars": 654,
    "preview": "{\n    \"appid\": \"wxe5f52902cf4de896\",\n    \"compileType\": \"miniprogram\",\n    \"libVersion\": \"3.3.2\",\n    \"packOptions\": {\n "
  },
  {
    "path": "examples/app-bar/project.private.config.json",
    "chars": 319,
    "preview": "{\n    \"description\": \"项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.co"
  },
  {
    "path": "examples/app-bar/sitemap.json",
    "chars": 169,
    "preview": "{\n    \"desc\": \"关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html\",\n    \"rules\": ["
  },
  {
    "path": "examples/associated-scroll-view/.eslintrc.js",
    "chars": 587,
    "preview": "/*\n * Eslint config file\n * Documentation: https://eslint.org/docs/user-guide/configuring/\n * Install the Eslint extensi"
  },
  {
    "path": "examples/associated-scroll-view/app.js",
    "chars": 18,
    "preview": "// app.js\nApp({})\n"
  },
  {
    "path": "examples/associated-scroll-view/app.json",
    "chars": 568,
    "preview": "{\n  \"pages\": [\n    \"pages/index/index\"\n  ],\n  \"window\": {\n    \"backgroundTextStyle\": \"light\",\n    \"navigationBarBackgrou"
  },
  {
    "path": "examples/associated-scroll-view/app.wxss",
    "chars": 194,
    "preview": "/**app.wxss**/\n.container {\n  height: 100%;\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  justify-"
  },
  {
    "path": "examples/associated-scroll-view/components/category-list/category-list.js",
    "chars": 1614,
    "preview": "const { shared } = wx.worklet\n\nconst GestureState = {\n  POSSIBLE: 0, // 0 此时手势未识别,如 panDown等\n  BEGIN: 1, // 1 手势已识别\n  AC"
  },
  {
    "path": "examples/associated-scroll-view/components/category-list/category-list.json",
    "chars": 52,
    "preview": "{\n    \"component\": true,\n    \"usingComponents\": {}\n}"
  },
  {
    "path": "examples/associated-scroll-view/components/category-list/category-list.wxml",
    "chars": 1049,
    "preview": "<vertical-drag-gesture-handler\n tag=\"scroll-view-{{index}}\"\n native-view=\"scroll-view\"\n simultaneous-handlers=\"{{['swipe"
  },
  {
    "path": "examples/associated-scroll-view/components/category-list/category-list.wxss",
    "chars": 1233,
    "preview": ".product-list {\n  height: 100%;\n}\n.product-item {\n  display: flex;\n  flex-direction: row;\n  padding: 8px;\n}\n.product-ite"
  },
  {
    "path": "examples/associated-scroll-view/pages/index/index.js",
    "chars": 1263,
    "preview": "import { getCategories, getProducts } from \"../../util\"\n\nconst { shared } = wx.worklet\n\nComponent({\n  data: {\n    catego"
  },
  {
    "path": "examples/associated-scroll-view/pages/index/index.json",
    "chars": 154,
    "preview": "{\n  \"usingComponents\": {\n    \"category-list\": \"../../components/category-list/category-list\"\n  },\n  \"disableScroll\": tru"
  },
  {
    "path": "examples/associated-scroll-view/pages/index/index.wxml",
    "chars": 1499,
    "preview": "<!--index.wxml-->\n<view class=\"navigation-bar\">\n  <view class=\"navigation-bar-content black\">\n    <view class=\"back\">ㄑ</"
  },
  {
    "path": "examples/associated-scroll-view/pages/index/index.wxss",
    "chars": 1854,
    "preview": "view {\n  position: relative;\n  box-sizing: border-box;\n}\npage {\n  background-color: #F9F9F9;\n  display: flex;\n  flex-dir"
  },
  {
    "path": "examples/associated-scroll-view/project.config.json",
    "chars": 720,
    "preview": "{\n    \"appid\": \"wxe5f52902cf4de896\",\n    \"compileType\": \"miniprogram\",\n    \"libVersion\": \"latest\",\n    \"packOptions\": {\n"
  },
  {
    "path": "examples/associated-scroll-view/project.private.config.json",
    "chars": 357,
    "preview": "{\n    \"description\": \"项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.co"
  },
  {
    "path": "examples/associated-scroll-view/sitemap.json",
    "chars": 169,
    "preview": "{\n    \"desc\": \"关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html\",\n    \"rules\": ["
  },
  {
    "path": "examples/associated-scroll-view/util.js",
    "chars": 3256,
    "preview": "export function getCategories() {\n  const categories = [\n    '中小商户',\n    '商超零售',\n    '品牌服饰',\n    '餐饮',\n    '医疗',\n    '酒旅"
  },
  {
    "path": "examples/card_transition/app.js",
    "chars": 8,
    "preview": "App({})\n"
  },
  {
    "path": "examples/card_transition/app.json",
    "chars": 592,
    "preview": "{\n  \"pages\": [\n    \"pages/list/list\",\n    \"pages/detail/detail\"\n  ],\n  \"window\": {\n    \"backgroundTextStyle\": \"light\",\n "
  },
  {
    "path": "examples/card_transition/app.wxss",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "examples/card_transition/components/card/card.js",
    "chars": 3265,
    "preview": "const { shared } = wx.worklet\n\nconst FlightDirection = {\n  PUSH: 0,\n  POP: 1,\n}\n\nComponent({\n  options: {\n    virtualHos"
  },
  {
    "path": "examples/card_transition/components/card/card.json",
    "chars": 87,
    "preview": "{\n  \"component\": true,\n  \"usingComponents\": {},\n  \"componentFramework\": \"glass-easel\"\n}"
  },
  {
    "path": "examples/card_transition/components/card/card.wxml",
    "chars": 1166,
    "preview": "<!-- 需要先给定高度,微信 8.0.33 后 share-element 将能够撑开高度 -->\n<view class=\"card\" style=\"height: {{cardWidth / item.imageRatio + 80}"
  },
  {
    "path": "examples/card_transition/components/card/card.wxss",
    "chars": 730,
    "preview": ".card {\n  border-radius: 5px;\n  overflow: hidden;\n  flex-shrink: 0;\n  width: 100%;\n  background-color: white;\n}\n\n.card_w"
  },
  {
    "path": "examples/card_transition/components/navigation-bar/index.js",
    "chars": 1854,
    "preview": "Component({\n  options: {\n    multipleSlots: true // 在组件定义时的选项中启用多slot支持\n  },\n  /**\n   * 组件的属性列表\n   */\n  properties: {\n  "
  },
  {
    "path": "examples/card_transition/components/navigation-bar/index.json",
    "chars": 113,
    "preview": "{\n  \"component\": true,\n  \"usingComponents\": {},\n  \"addGlobalClass\": true,\n  \"componentFramework\": \"glass-easel\"\n}"
  },
  {
    "path": "examples/card_transition/components/navigation-bar/index.wxml",
    "chars": 1326,
    "preview": "<view class=\"weui-navigation-bar {{extClass}}\">\n  <view class=\"weui-navigation-bar__inner\" style=\"padding-top: {{statusB"
  },
  {
    "path": "examples/card_transition/components/navigation-bar/index.wxss",
    "chars": 1612,
    "preview": ".weui-navigation-bar {\n  overflow: hidden;\n  color: rgba(0, 0, 0, .9);\n  width: 100vw;\n}\n\n.weui-navigation-bar__placehol"
  },
  {
    "path": "examples/card_transition/pages/detail/detail.js",
    "chars": 5038,
    "preview": "import { Curves, CurveAnimation, lerp } from '../list/route'\nimport { clamp } from '../list/utils'\n\nconst { screenWidth "
  },
  {
    "path": "examples/card_transition/pages/detail/detail.json",
    "chars": 124,
    "preview": "{\n  \"usingComponents\": {},\n  \"backgroundColorContent\": \"#00000000\",\n  \"disableScroll\": true,\n  \"navigationStyle\": \"custo"
  },
  {
    "path": "examples/card_transition/pages/detail/detail.wxml",
    "chars": 2724,
    "preview": "<pan-gesture-handler worklet:ongesture=\"handlePanGesture\">\n\t<view id=\"fake-host\">\n\t\t<view id=\"page\">\n\t\t\t<view class=\"nav"
  },
  {
    "path": "examples/card_transition/pages/detail/detail.wxss",
    "chars": 1510,
    "preview": "page {\n  display: flex;\n  flex-direction: column;\n  height: 100vh;\n  background-color: transparent;\n}\n\nview, scroll-view"
  },
  {
    "path": "examples/card_transition/pages/list/list.js",
    "chars": 597,
    "preview": "import { installRouteBuilder } from './route'\nimport { generateGridList, compareVersion } from './utils'\n\nconst { screen"
  },
  {
    "path": "examples/card_transition/pages/list/list.json",
    "chars": 190,
    "preview": "{\n  \"usingComponents\": {\n    \"navigation-bar\": \"../../components/navigation-bar/index\",\n    \"card\": \"../../components/ca"
  },
  {
    "path": "examples/card_transition/pages/list/list.wxml",
    "chars": 490,
    "preview": "<navigation-bar back title=\"发现\"></navigation-bar>\n\n<scroll-view\n scroll-y\n style=\"flex: 1; width: 100%; overflow: hidden"
  },
  {
    "path": "examples/card_transition/pages/list/list.wxss",
    "chars": 177,
    "preview": "page {\n  display: flex;\n  flex-direction: column;\n  height: 100vh;\n}\n\nscroll-view {\n  background-color: #f4f4f4;\n}\n\nview"
  },
  {
    "path": "examples/card_transition/pages/list/route.js",
    "chars": 4135,
    "preview": "const AnimationStatus = {\n  dismissed: 0, // The animation is stopped at the beginning.\n  forward: 1, // The animation i"
  },
  {
    "path": "examples/card_transition/pages/list/utils.js",
    "chars": 5060,
    "preview": "export const lightBlue = {\n  0: '#E1F5FE',\n  100: '#B3E5FC',\n  200: '#81D4FA',\n  300: '#4FC3F7',\n  400: '#29B6F6',\n  500"
  },
  {
    "path": "examples/card_transition/project.config.json",
    "chars": 627,
    "preview": "{\n  \"appid\": \"wxe5f52902cf4de896\",\n  \"compileType\": \"miniprogram\",\n  \"libVersion\": \"latest\",\n  \"packOptions\": {\n    \"ign"
  },
  {
    "path": "examples/card_transition/project.private.config.json",
    "chars": 810,
    "preview": "{\n  \"description\": \"项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/"
  },
  {
    "path": "examples/card_transition/sitemap.json",
    "chars": 159,
    "preview": "{\n  \"desc\": \"关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html\",\n  \"rules\": [{\n  "
  },
  {
    "path": "examples/expanded-scroll-view/.eslintrc.js",
    "chars": 587,
    "preview": "/*\n * Eslint config file\n * Documentation: https://eslint.org/docs/user-guide/configuring/\n * Install the Eslint extensi"
  },
  {
    "path": "examples/expanded-scroll-view/app.js",
    "chars": 18,
    "preview": "// app.js\nApp({})\n"
  },
  {
    "path": "examples/expanded-scroll-view/app.json",
    "chars": 457,
    "preview": "{\n  \"pages\": [\n    \"pages/index/index\"\n  ],\n  \"window\": {\n    \"backgroundTextStyle\": \"light\",\n    \"navigationBarBackgrou"
  },
  {
    "path": "examples/expanded-scroll-view/app.wxss",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "examples/expanded-scroll-view/pages/index/index.js",
    "chars": 7439,
    "preview": "import { getCategory, getProducts } from '../../util'\n\nconst { shared, timing, decay, derived, runOnUI, runOnJS } = wx.w"
  },
  {
    "path": "examples/expanded-scroll-view/pages/index/index.json",
    "chars": 147,
    "preview": "{\n  \"usingComponents\": {},\n  \"disableScroll\": true,\n  \"navigationStyle\": \"custom\",\n  \"renderer\": \"skyline\",\n  \"component"
  },
  {
    "path": "examples/expanded-scroll-view/pages/index/index.wxml",
    "chars": 5172,
    "preview": "<view class=\"navigation-bar\" style=\"padding-top: {{statusBarHeight}}px;\">\n  <view class=\"navigation-bar-content {{expand"
  },
  {
    "path": "examples/expanded-scroll-view/pages/index/index.wxss",
    "chars": 4810,
    "preview": "view {\n  position: relative;\n  box-sizing: border-box;\n}\n\n.navigation-bar {\n  position: absolute;\n  z-index: 1;\n  top: 0"
  },
  {
    "path": "examples/expanded-scroll-view/project.config.json",
    "chars": 604,
    "preview": "{\n  \"compileType\": \"miniprogram\",\n  \"setting\": {\n    \"coverView\": true,\n    \"es6\": true,\n    \"postcss\": true,\n    \"minif"
  },
  {
    "path": "examples/expanded-scroll-view/project.private.config.json",
    "chars": 316,
    "preview": "{\n  \"description\": \"项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/"
  },
  {
    "path": "examples/expanded-scroll-view/sitemap.json",
    "chars": 169,
    "preview": "{\n    \"desc\": \"关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html\",\n    \"rules\": ["
  },
  {
    "path": "examples/expanded-scroll-view/util.js",
    "chars": 1841,
    "preview": "export function getCategory() {\n\tlet categorys = [\n\t  '中小商户',\n\t  '商超零售',\n\t  '品牌服饰',\n\t  '餐饮',\n\t  '医疗',\n\t  '酒旅',\n\t  '政务',\n"
  },
  {
    "path": "examples/half-screen/.eslintrc.js",
    "chars": 587,
    "preview": "/*\n * Eslint config file\n * Documentation: https://eslint.org/docs/user-guide/configuring/\n * Install the Eslint extensi"
  },
  {
    "path": "examples/half-screen/app.js",
    "chars": 18,
    "preview": "// app.js\nApp({})\n"
  },
  {
    "path": "examples/half-screen/app.json",
    "chars": 567,
    "preview": "{\n  \"pages\": [\n    \"pages/index/index\"\n  ],\n  \"window\": {\n    \"backgroundTextStyle\": \"light\",\n    \"navigationBarBackgrou"
  },
  {
    "path": "examples/half-screen/app.wxss",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "examples/half-screen/pages/index/comment-data.js",
    "chars": 5595,
    "preview": "// 获取留言列表\nexport function getCommentList() {\n  return [\n    {\n      \"comment\": \"为了进一步优化小程序性能,提供更为接近原生的用户体验,我们在 WebView 渲"
  },
  {
    "path": "examples/half-screen/pages/index/index.js",
    "chars": 2845,
    "preview": "import { getCommentList } from \"./comment-data\"\n\nconst { shared, timing } = wx.worklet\n\nconst GestureState = {\n  POSSIBL"
  },
  {
    "path": "examples/half-screen/pages/index/index.json",
    "chars": 83,
    "preview": "{\n  \"usingComponents\": {},\n  \"disableScroll\": true,\n  \"navigationStyle\": \"custom\"\n}"
  },
  {
    "path": "examples/half-screen/pages/index/index.wxml",
    "chars": 2216,
    "preview": "<scroll-view class=\"container\" scroll-y type=\"list\">\n  <image src=\"https://res.wx.qq.com/op_res/FAyreGAUWqLJv09oZqfNbsZz"
  },
  {
    "path": "examples/half-screen/pages/index/index.wxss",
    "chars": 1848,
    "preview": "page {\n  display: flex;\n  flex-direction: column;\n  padding-top: env(safe-area-inset-top);\n  width: 100vw;\n  height: 100"
  },
  {
    "path": "examples/half-screen/project.config.json",
    "chars": 626,
    "preview": "{\n  \"appid\": \"wxe5f52902cf4de896\",\n  \"compileType\": \"miniprogram\",\n  \"libVersion\": \"latest\",\n  \"packOptions\": {\n    \"ign"
  },
  {
    "path": "examples/half-screen/project.private.config.json",
    "chars": 307,
    "preview": "{\n  \"description\": \"项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/"
  },
  {
    "path": "examples/half-screen/sitemap.json",
    "chars": 169,
    "preview": "{\n    \"desc\": \"关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html\",\n    \"rules\": ["
  },
  {
    "path": "examples/product-list/.eslintrc.js",
    "chars": 587,
    "preview": "/*\n * Eslint config file\n * Documentation: https://eslint.org/docs/user-guide/configuring/\n * Install the Eslint extensi"
  },
  {
    "path": "examples/product-list/app.js",
    "chars": 18,
    "preview": "// app.js\nApp({})\n"
  },
  {
    "path": "examples/product-list/app.json",
    "chars": 569,
    "preview": "{\n  \"pages\": [\n      \"pages/index/index\"\n  ],\n  \"window\": {\n    \"backgroundTextStyle\": \"light\",\n    \"navigationBarBackgr"
  },
  {
    "path": "examples/product-list/app.wxss",
    "chars": 49,
    "preview": "/**app.wxss**/\nview {\n  box-sizing: border-box;\n}"
  },
  {
    "path": "examples/product-list/components/navigation-bar/index.js",
    "chars": 1854,
    "preview": "Component({\n  options: {\n    multipleSlots: true // 在组件定义时的选项中启用多slot支持\n  },\n  /**\n   * 组件的属性列表\n   */\n  properties: {\n  "
  },
  {
    "path": "examples/product-list/components/navigation-bar/index.json",
    "chars": 113,
    "preview": "{\n  \"component\": true,\n  \"usingComponents\": {},\n  \"componentFramework\": \"glass-easel\",\n  \"addGlobalClass\": true\n}"
  },
  {
    "path": "examples/product-list/components/navigation-bar/index.wxml",
    "chars": 1337,
    "preview": "<view class=\"weui-navigation-bar {{extClass}}\">\n  <view class=\"weui-navigation-bar__inner\" style=\"padding-top: {{statusB"
  },
  {
    "path": "examples/product-list/components/navigation-bar/index.wxss",
    "chars": 1618,
    "preview": ".weui-navigation-bar {\n  overflow: hidden;\n  color: rgba(0, 0, 0, .9);\n  width: 100vw;\n}\n\n.weui-navigation-bar__placehol"
  },
  {
    "path": "examples/product-list/pages/index/index.js",
    "chars": 2212,
    "preview": "import { getCategory, getGoods, getVIPCategory } from '../../util'\n\nconst systemInfo = wx.getSystemInfoSync()\n\nconst { s"
  },
  {
    "path": "examples/product-list/pages/index/index.json",
    "chars": 143,
    "preview": "{\n  \"usingComponents\": {\n    \"navigation-bar\": \"../../components/navigation-bar\"\n  },\n  \"disableScroll\": true,\n  \"naviga"
  },
  {
    "path": "examples/product-list/pages/index/index.wxml",
    "chars": 2977,
    "preview": "<navigation-bar class=\"nav-bar\" title=\"\" back=\"{{false}}\">\n  <view class=\"nav-left\" slot=\"left\">\n    <image class=\"nav-l"
  },
  {
    "path": "examples/product-list/pages/index/index.wxss",
    "chars": 2653,
    "preview": ".fake-nav-bar {\n  height: 60px;\n}\n\n.search-container {\n  padding: 0 16px 10px 16px;\n  /* margin-top: 44px; */\n  /* backg"
  },
  {
    "path": "examples/product-list/project.config.json",
    "chars": 626,
    "preview": "{\n  \"appid\": \"wxe5f52902cf4de896\",\n  \"compileType\": \"miniprogram\",\n  \"libVersion\": \"latest\",\n  \"packOptions\": {\n    \"ign"
  },
  {
    "path": "examples/product-list/project.private.config.json",
    "chars": 275,
    "preview": "{\n  \"description\": \"项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/"
  },
  {
    "path": "examples/product-list/sitemap.json",
    "chars": 169,
    "preview": "{\n    \"desc\": \"关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html\",\n    \"rules\": ["
  },
  {
    "path": "examples/product-list/util.js",
    "chars": 3626,
    "preview": "export function getCategory() {\n  let categorys = [\n    '中小商户',\n    '商超零售',\n    '品牌服饰',\n    '餐饮',\n    '医疗',\n    '酒旅',\n  "
  },
  {
    "path": "examples/refresher-two-level/app.js",
    "chars": 18,
    "preview": "// app.js\nApp({})\n"
  },
  {
    "path": "examples/refresher-two-level/app.json",
    "chars": 528,
    "preview": "{\n\t\"pages\": [\n\t\t\"index/index\"\n\t],\n\t\"window\": {\n\t  \"backgroundTextStyle\": \"light\",\n\t  \"navigationBarBackgroundColor\": \"#f"
  },
  {
    "path": "examples/refresher-two-level/app.wxss",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "examples/refresher-two-level/components/navigation-bar/index.js",
    "chars": 1854,
    "preview": "Component({\n  options: {\n    multipleSlots: true // 在组件定义时的选项中启用多slot支持\n  },\n  /**\n   * 组件的属性列表\n   */\n  properties: {\n  "
  },
  {
    "path": "examples/refresher-two-level/components/navigation-bar/index.json",
    "chars": 113,
    "preview": "{\n  \"component\": true,\n  \"usingComponents\": {},\n  \"componentFramework\": \"glass-easel\",\n  \"addGlobalClass\": true\n}"
  },
  {
    "path": "examples/refresher-two-level/components/navigation-bar/index.wxml",
    "chars": 1337,
    "preview": "<view class=\"weui-navigation-bar {{extClass}}\">\n  <view class=\"weui-navigation-bar__inner\" style=\"padding-top: {{statusB"
  },
  {
    "path": "examples/refresher-two-level/components/navigation-bar/index.wxss",
    "chars": 1618,
    "preview": ".weui-navigation-bar {\n  overflow: hidden;\n  color: rgba(0, 0, 0, .9);\n  width: 100vw;\n}\n\n.weui-navigation-bar__placehol"
  },
  {
    "path": "examples/refresher-two-level/goods/index.json",
    "chars": 147,
    "preview": "{\n  \"usingComponents\": {\n    \"navigation-bar\": \"../components/navigation-bar\"\n  },\n  \"renderer\": \"skyline\",\n  \"component"
  },
  {
    "path": "examples/refresher-two-level/goods/index.less",
    "chars": 24,
    "preview": "@import '../goods.less';"
  },
  {
    "path": "examples/refresher-two-level/goods/index.ts",
    "chars": 1084,
    "preview": "import { getCategory, getGoods, getVIPCategory, getExpCategory, getVideoList } from '../util'\n\n// pages/goods/index.ts\nP"
  },
  {
    "path": "examples/refresher-two-level/goods/index.wxml",
    "chars": 79,
    "preview": "<import src=\"../goods.wxml\" />\n\n<template is=\"goods\" data=\"{{...goodsData}}\" />"
  },
  {
    "path": "examples/refresher-two-level/goods.less",
    "chars": 1359,
    "preview": ".exp-room {\n\t.nav-bar {\n\t  background-color: #fff;\n\t  position: absolute;\n\t}\n\t\n\t.nav-left {\n\t  display: flex;\n\t  flex-di"
  },
  {
    "path": "examples/refresher-two-level/goods.wxml",
    "chars": 1167,
    "preview": "<template name=\"goods\">\n\t<view class=\"exp-room\">\n\t\t<view class=\"expand\">\n\t\t\t<navigation-bar class=\"nav-bar\" title=\"\" bac"
  },
  {
    "path": "examples/refresher-two-level/index/index.json",
    "chars": 204,
    "preview": "{\n  \"usingComponents\": {\n    \"navigation-bar\": \"../components/navigation-bar\"\n  },\n  \"disableScroll\": true,\n  \"renderer\""
  },
  {
    "path": "examples/refresher-two-level/index/index.less",
    "chars": 2473,
    "preview": "@import '../goods.less';\n\n.fake-nav-bar {\n  height: 60px;\n}\n\n.search-container {\n  padding: 0 16px 10px 16px;\n  /* margi"
  },
  {
    "path": "examples/refresher-two-level/index/index.ts",
    "chars": 5035,
    "preview": "import { getCategory, getGoods, getVIPCategory, getExpCategory, getVideoList } from '../util'\n\nexport enum RefreshStatus"
  },
  {
    "path": "examples/refresher-two-level/index/index.wxml",
    "chars": 3484,
    "preview": "<import src=\"../goods.wxml\" />\n<navigation-bar class=\"nav-bar\" title=\"\" back=\"{{false}}\">\n\t<view class=\"nav-left\" slot=\""
  },
  {
    "path": "examples/refresher-two-level/project.config.json",
    "chars": 752,
    "preview": "{\n    \"appid\": \"wxe5f52902cf4de896\",\n    \"compileType\": \"miniprogram\",\n    \"libVersion\": \"3.1.5\",\n    \"packOptions\": {\n "
  },
  {
    "path": "examples/refresher-two-level/util.js",
    "chars": 4784,
    "preview": "export function getCategory() {\n\tlet categorys = [\n\t  '中小商户',\n\t  '商超零售',\n\t  '品牌服饰',\n\t  '餐饮',\n\t  '医疗',\n\t  '酒旅',\n\t  '政务',\n"
  },
  {
    "path": "examples/segmented-half-screen/.eslintrc.js",
    "chars": 587,
    "preview": "/*\n * Eslint config file\n * Documentation: https://eslint.org/docs/user-guide/configuring/\n * Install the Eslint extensi"
  },
  {
    "path": "examples/segmented-half-screen/app.js",
    "chars": 18,
    "preview": "// app.js\nApp({})\n"
  },
  {
    "path": "examples/segmented-half-screen/app.json",
    "chars": 567,
    "preview": "{\n  \"pages\": [\n    \"pages/index/index\"\n  ],\n  \"window\": {\n    \"backgroundTextStyle\": \"light\",\n    \"navigationBarBackgrou"
  },
  {
    "path": "examples/segmented-half-screen/app.wxss",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "examples/segmented-half-screen/pages/index/comment-data.js",
    "chars": 5595,
    "preview": "// 获取留言列表\nexport function getCommentList() {\n  return [\n    {\n      \"comment\": \"为了进一步优化小程序性能,提供更为接近原生的用户体验,我们在 WebView 渲"
  },
  {
    "path": "examples/segmented-half-screen/pages/index/index.js",
    "chars": 4526,
    "preview": "import { getCommentList } from \"./comment-data\"\n\nfunction clamp(val, min, max) {\n  'worklet'\n  return Math.min(Math.max("
  },
  {
    "path": "examples/segmented-half-screen/pages/index/index.json",
    "chars": 83,
    "preview": "{\n  \"usingComponents\": {},\n  \"disableScroll\": true,\n  \"navigationStyle\": \"custom\"\n}"
  },
  {
    "path": "examples/segmented-half-screen/pages/index/index.wxml",
    "chars": 1948,
    "preview": "<map id=\"myMap\" scale=\"{{scale}}\" latitude=\"23.099994\" longitude=\"113.324520\"></map>\n\n<view class=\"comment-container\" st"
  },
  {
    "path": "examples/segmented-half-screen/pages/index/index.wxss",
    "chars": 1708,
    "preview": "page {\n  display: flex;\n  flex-direction: column;\n  width: 100vw;\n  height: 100vh;\n  color: #1A191E;\n}\npage, view {\n  bo"
  }
]

// ... and 18 more files (download for full content)

About this extraction

This page contains the full source code of the wechat-miniprogram/awesome-skyline GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 218 files (335.4 KB), approximately 124.7k tokens, and a symbol index with 252 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!