程序开发_开发板程序 - CSDN
  • 【会员免费】链接 http://edu.csdn.net/lecturer/585 ...办会员卡可咨询 QQ 1405491181 。 会员可免费学习已发布的全部课程,和在会员有效期内讲师新发布的全部课程 ,承诺平均每个月至少增加价值300元+ 的新课程。
  • 由浅入深,零基础快速入门小程序开发。通过10小时的学习,你也可以上线一款属于自己的微信小程序。 本课是《手把手带你零基础入门小程序》系列课程的一节,如果你想快速入门小程序开发,想学习小程序云开发,...
  • 程序开发入门

    2018-11-27 16:02:26
    小程序实战入门,10天带领大家上线一款属于自己的微信小程序。微信小程序开发入门视频教程,该课程从微信小程序注册到官方开发工具、官方Demo、再到开发个人专属小程序所有知识点,包括小程序获取用户信息等功能。
  • 微信小程序开发

    2019-05-10 15:24:25
    本课程主要介绍如何开发微信小程序,是一门比较基础入门的微信小程序开发课程,本套课程涵盖了大部分的基础内容,使学员们可以尽快的掌握小程序的开发技巧 本套课程大部分可分为如下几个层面 一:小程序的开发...
  • 课程目标:让学员从零基础入门全面认识微信小程序开发  课程特色:不采用第三方API作为后端接口,接口我已写好,永久有效,含有登录,收藏,留言等功能 【课程收益】 1.学员学完...
  • 作者:谭东 备注:小程序只是突发灵感兴趣弄的,...然后有目标的进行实践,也就是要实现个你想要的小程序,这样边实践边学习才能够有疑问,才能够更快的理解和学习小程序开发。所以后续几天就开始小程序实践和学习...

    作者:谭东

    备注:小程序只是突发灵感兴趣弄的,并非专业研究小程序,其实小程序API并不多,不复杂,扩展无非就是JS了。

    最近用了大概两天左右的时间看了小程序的官方文档:https://mp.weixin.qq.com/cgi-bin/wx

    然后有目标的进行实践,也就是要实现个你想要的小程序,这样边实践边学习才能够有疑问,才能够更快的理解和学习小程序开发。所以后续几天就开始小程序实践和学习之旅了,期间也遇到了一些问题并且学到了很多基础知识和解决方案。接下来给大家讲解下小程序的开发基本知识和扩展知识。

    官方文档其实写的基本很详细了,我们先从工具开始说起。

    1、小程序开发者工具。

    这个工具集成了公众号网页调试和小程序调试两种开发模式。我这里使用了Beta版本,没有用正式版。因为我想体验使用其中的Git版本管理功能。下载地址:https://developers.weixin.qq.com/miniprogram/dev/devtools/beta.html

    下载安装好后,先要微信扫描登录。然后选择小程序项目。

    新建小程序项目。

    选择新建小程序的项目目录,AppID没有注册的话,可以先点击下面的使用测试号即可,不影响开发。

    大致的工具界面如下图,新版有版本管理。红色圈起来的为小程序项目的一个页面包含的元素:

    工具用起来很方便、简单、直接。详细用法就不说了,主要的功能大概说下。左侧是模拟器,可以模拟安卓手机和苹果手机的效果,因为有些小程序组件在安卓和苹果上显示是有区别的,大家可以注意下。圈红的为小程序一个页面的基本组成文件元素:xx.js、xx.wxml、xx.wxss、xx.json。其实就是有JS文件、HTML文件(xx.wxml)、CSS样式文件(xx.wxss)和配置文件(xx.json)组成,非常的容易理解。我们就是在使用小程序的组件、控件来绘制UI布局,主要是xx.wxml和xx.wxss文件。xx.js负责生命周期函数和事件处理,例如:点击事件、数据请求、数据绑定等等逻辑操作。

    我们在编写完后,可以点击工具栏上的预览按钮,扫描二维码在真机上体验,也可以直接用左侧的模拟器时时预览即可。

    看完了工具,我们看下基本开发的要素和需要注意的问题吧,以免新手再次重蹈覆辙。

    看下默认的新建后的结构:

    app.json是小程序全局配置文件,包括了小程序的所有页面路径、界面表现、网络超时时间、底部 tab 等。

    大致代码结构如下:

    {
      "pages":[
        "pages/index/index",
        "pages/logs/logs"
      ],
      "window":{
        "backgroundTextStyle":"light",
        "navigationBarBackgroundColor": "#fff",
        "navigationBarTitleText": "WeChat",
        "navigationBarTextStyle":"black"
      }
    }

    pages是配置小程序所有页面,类似于注册清单。window是全局的窗口配置,如颜色、标题等等。当然每个页面也可以自己单独配置,就是页面名称.json文件。例如:page.json。不过需要注意的是,单独页面配置的json无需写window这个关键字,直接如下代码所示:

    {
      "backgroundTextStyle": "light",
      "navigationBarBackgroundColor": "#34495e",
      "navigationBarTitleText": "日记",
      "navigationBarTextStyle": "white",
      "enablePullDownRefresh": true,
      "backgroundColor": "#34495e"
    }

    那么再看工具配置文件project.config.json。

    通常大家在使用一个工具的时候,都会针对各自喜好做一些个性化配置,例如界面颜色、编译配置等等,当你换了另外一台电脑重新安装工具的时候,你还要重新配置。考虑到这点,小程序开发者工具在每个项目的根目录都会生成一个 project.config.json,你在工具上做的任何配置都会写入到这个文件,当你重新安装工具或者换电脑工作时,你只要载入同一个项目的代码包,开发者工具就自动会帮你恢复到当时你开发项目时的个性化配置,其中会包括编辑器的颜色、代码上传时自动压缩等等一系列选项。具体详细配置大家可以看小程序官方文档有详细介绍。

    还有一个app.wxss和app.js。这个app.wxss就是全局的样式文件,也就是css文件,当然和页面配置文件一样,每个页面可以单独写页面名称.wxss。

    WXSS 具有 CSS 大部分的特性,小程序在 WXSS 也做了一些扩充和修改。

    新增了尺寸单位。在写 CSS 样式时,开发者需要考虑到手机设备的屏幕会有不同的宽度和设备像素比,采用一些技巧来换算一些像素单位。WXSS 在底层支持新的尺寸单位 rpx ,开发者可以免去换算的烦恼,只要交给小程序底层来换算即可,由于换算采用的浮点数运算,所以运算结果会和预期结果有一点点偏差。

    提供了全局的样式和局部样式。和前边 app.json, page.json 的概念相同,你可以写一个 app.wxss 作为全局样式,会作用于当前小程序的所有页面,局部页面样式 page.wxss 仅对当前页面生效。

    此外 WXSS 仅支持部分 CSS 选择器

    再来看app.js,很明显是一个js文件。负责UI交互、数据绑定更新、网络请求、页面生命周期等等操作相关的都在这里。当然每个页面都有自己单独的.js文件,这个app.js可以做一些需要全局共享和操作的逻辑在里面。在这里可以调用微信小程序的很多API,也可以自己写js方法使用。

    那么我们看下一个页面的组成,基本上就是下图这些结构元素。有界面、有样式、有js交互、有配置。

    每新增一个页面都要在app.json里添加注册进去。

    一个.js文件里有生命周期的管理函数,可以在这里面做相应的操作。

    Page({
    
      /**
       * 页面的初始数据
       */
      data: {
        
      },
    
      /**
       * 生命周期函数--监听页面加载
       */
      onLoad: function (options) {
        
      },
    
      /**
       * 生命周期函数--监听页面初次渲染完成
       */
      onReady: function () {
        
      },
    
      /**
       * 生命周期函数--监听页面显示
       */
      onShow: function () {
        
      },
    
      /**
       * 生命周期函数--监听页面隐藏
       */
      onHide: function () {
        
      },
    
      /**
       * 生命周期函数--监听页面卸载
       */
      onUnload: function () {
        
      },
    
      /**
       * 页面相关事件处理函数--监听用户下拉动作
       */
      onPullDownRefresh: function () {
        
      },
    
      /**
       * 页面上拉触底事件的处理函数
       */
      onReachBottom: function () {
        
      },
    
      /**
       * 用户点击右上角分享
       */
      onShareAppMessage: function () {
        
      }
    })

    我们看下最简单的一个index.wxml页面,可以当做是Html页面,只有一个text控件,里面的bindtap就是点击事件的绑定。

    <!--index.wxml-->
    <view class="container">
      <view class="usermotto">
        <text class="user-motto" bindtap='click'>{{motto}}</text>
      </view>
    </view>

    那么这个class就是index.wxss里的样式文件。里面的{{motto}}就是指向index.js里的data里定义的一个变量。小程序都是通过{{..}}两个大括号包括一个英文名字来进行变量绑定的。这样我们就可以动态更换里面的显示内容了。那么怎么更新内容呢?

    在js里使用下面的this.setData方式动态更新刷新数据:

    this.setData({ motto: "名字" })
    /**index.wxss**/
    .userinfo {
      display: flex;
      flex-direction: column;
      align-items: center;
    }
    
    .userinfo-avatar {
      width: 128rpx;
      height: 128rpx;
      margin: 20rpx;
      border-radius: 50%;
    }
    
    .userinfo-nickname {
      color: #aaa;
    }
    
    .usermotto {
      margin-top: 200px;
    }

    再看下index.

    js文件。

    //index.js
    //获取应用实例
    const app = getApp()
    
    Page({
      data: {
        motto: 'Hello World',
      },
      
      //事件处理函数
      click: function() {
        wx.navigateTo({
          url: '../logs/logs'
        })
      },
        
    })

    Page函数是必须要有的,里面包含data:{  ... },用于放置数据、常量、变量等等。这里的click:function就是我们定义的点击事件。wx.navigateTo...方法就是小程序的官方API,具体其他API的用法和返回参数是什么可以看官方API文档,很详细。

    观察下,上面有个声明了app这个常量。这个就是app.js里拿到的全局管理调用app.js里的方法和常量用的。很多需要存储和全局读写、处理的都可以进行操作以及放置在app.js里。在 JavaScript 文件中声明的变量和函数只在该文件中有效;不同的文件中可以声明相同名字的变量和函数,不会互相影响。通过全局函数 getApp() 可以获取全局的应用实例,如果需要全局的数据可以在 App() 中设置。

    Page({
      data: { // 参与页面渲染的数据
        logs: []
      },
      onLoad: function () {
        // 页面渲染后执行
      }
    })

    小程序的组件和控件有很多,可以看做是Html的标签,对称方式使用。具体组件特性看官方文档:

    https://developers.weixin.qq.com/miniprogram/dev/component/

    为了让开发者可以很方便的调起微信提供的能力,例如获取用户信息、微信支付等等,小程序提供了很多 API 给开发者,例如:

    要获取用户的地理位置时,只需要:

    wx.getLocation({
      type: 'wgs84',
      success: (res) => {
        var latitude = res.latitude // 经度
        var longitude = res.longitude // 纬度
      }
    })

    调用微信扫一扫能力,只需要:

    wx.scanCode({
      success: (res) => {
        console.log(res)
      }
    })

    需要注意的是:多数 API 的回调都是异步,你需要处理好代码逻辑的异步问题。更多API说明和用法,看官方文档。

    https://developers.weixin.qq.com/miniprogram/dev/api/

    页面的生命周期,我之前说过了,比较重要,大家可以看下理解下。

    看下逻辑层需要注意的。除了页面的生命周期,还有页面的监听事件。onPullDownRefresh():监听用户下拉刷新事件。

    需要在app.json的window选项中或页面配置中开启enablePullDownRefresh。
    可以通过wx.startPullDownRefresh触发下拉刷新,调用后触发下拉刷新动画,效果与用户手动下拉刷新一致。
    当处理完数据刷新后,wx.stopPullDownRefresh可以停止当前页面的下拉刷新。

    onReachBottom():监听用户上拉触底事件。

    可以在app.json的window选项中或页面配置中设置触发距离onReachBottomDistance,默认为50px。
    在触发距离内滑动期间,本事件只会被触发一次。

    onPageScroll(Object):监听用户滑动页面事件。

    onShareAppMessage(Object):

    监听用户点击页面内转发按钮(<button> 组件 open-type="share")或右上角菜单“转发”按钮的行为,并自定义转发内容。

    注意:只有定义了此事件处理函数,右上角菜单才会显示“转发”按钮。

    onTabItemTap(Object):点击 tab 时触发。

    Page.prototype.setData(Object data, Function callback):setData 函数用于将数据从逻辑层发送到视图层(异步),同时改变对应的 this.data 的值(同步)。

    Object 以 key: value 的形式表示,将 this.data 中的 key 对应的值改变成 value。

    其中 key 可以以数据路径的形式给出,支持改变数组中的某一项或对象的某个属性,如 array[2].message,a.b.c.d,并且不需要在 this.data 中预先定义。

    注意:

    直接修改 this.data 而不调用 this.setData 是无法改变页面的状态的,还会造成数据不一致。
    仅支持设置可 JSON 化的数据。
    单次设置的数据不能超过1024kB,请尽量避免一次设置过多的数据。
    请不要把 data 中任何一项的 value 设为 undefined ,否则这一项将不被设置并可能遗留一些潜在问题。

    接下来看下小程序里的路由、跳转。

    主要有这几种方式:

    这几种方式url都可以传递参数。

    wx.navigateTo:保留当前页面,跳转到应用内的某个页面,使用wx.navigateBack可以返回到原页面。注意:目前页面路径最多只能十层。

    wx.redirectTo(OBJECT):关闭当前页面,跳转到应用内的某个页面。如果你想让页面没有返回按钮,不能返回的话,就用这个跳转方式吧。

    wx.reLaunch(OBJECT):关闭所有页面,打开到应用内的某个页面。

    wx.switchTab(OBJECT):跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面。

    wx.navigateBack(OBJECT):关闭当前页面,返回上一页面或多级页面。可通过 getCurrentPages() 获取当前的页面栈,决定需要返回几层。

    注意:

    1、navigateTo, redirectTo 只能打开非 tabBar 页面。
    2、switchTab 只能打开 tabBar 页面。
    3、reLaunch 可以打开任意页面。
    4、页面底部的 tabBar 由页面决定,即只要是定义为 tabBar 的页面,底部都有 tabBar。
    5、调用页面路由带的参数可以在目标页面的onLoad中获取。

    再看下模块化。

    可以将一些公共的代码抽离成为一个单独的 js 文件,作为一个模块。模块只有通过 module.exports 或者 exports 才能对外暴露接口。

    需要注意的是:

    exports 是 module.exports 的一个引用,因此在模块里边随意更改 exports 的指向会造成未知的错误。所以更推荐开发者采用 module.exports 来暴露模块接口,除非你已经清晰知道这两者的关系。小程序目前不支持直接引入 node_modules , 开发者需要使用到 node_modules 时候建议拷贝出相关的代码到小程序的目录中。

    // common.js
    function sayHello(name) {
      console.log(`Hello ${name} !`)
    }
    function sayGoodbye(name) {
      console.log(`Goodbye ${name} !`)
    }
    
    module.exports.sayHello = sayHello
    exports.sayGoodbye = sayGoodbye

    ​在需要使用这些模块的文件中,使用 require(path) 将公共代码引入:

    var common = require('common.js')
    Page({
      helloMINA: function() {
        common.sayHello('MINA')
      },
      goodbyeMINA: function() {
        common.sayGoodbye('MINA')
      }
    })

    注意:require 暂时不支持绝对路径。

    接下来看下小程序的视图层,也就是wxml和wxss。

    框架的视图层由 WXML 与 WXSS 编写,由组件来进行展示。将逻辑层的数据反应成视图,同时将视图层的事件发送给逻辑层。

    WXML(WeiXin Markup language) 用于描述页面的结构。

    WXS(WeiXin Script) 是小程序的一套脚本语言,结合 WXML,可以构建出页面的结构。

    WXSS(WeiXin Style Sheet) 用于描述页面的样式。

    组件(Component)是视图的基本组成单元。

    这里挑几个比较重要的来说。首先是列表渲染,就是我们想实现一个List列表展示的时候,要进行List数据绑定,item数据绑定、可能还会涉及到模板和数据传递等等。

    列表渲染:

    <!--wxml-->
    <view wx:for="{{array}}"> {{item}} </view>
    // page.js
    Page({
      data: {
        array: [1, 2, 3, 4, 5]
      }
    })

    在组件上使用 wx:for 控制属性绑定一个数组,即可使用数组中各项的数据重复渲染该组件。默认数组的当前项的下标变量名默认为 index,数组当前项的变量名默认为 item。

    <view wx:for="{{array}}">
      {{index}}: {{item.message}}
    </view>

    使用 wx:for-item 可以指定数组当前元素的变量名,

    使用 wx:for-index 可以指定数组当前下标的变量名:

    <view wx:for="{{array}}" wx:for-index="idx" wx:for-item="itemName">
      {{idx}}: {{itemName.message}}
    </view>

    wx:for 也可以嵌套。类似 block wx:if,也可以将 wx:for 用在<block/>标签上,以渲染一个包含多节点的结构块。例如:

    <block wx:for="{{[1, 2, 3]}}">
      <view> {{index}}: </view>
      <view> {{item}} </view>
    </block>

    如果列表中项目的位置会动态改变或者有新的项目添加到列表中,并且希望列表中的项目保持自己的特征和状态(如 <input/> 中的输入内容,<switch/> 的选中状态),需要使用 wx:key 来指定列表中项目的唯一的标识符。

    wx:key 的值以两种形式提供:

    字符串,代表在 for 循环的 array 中 item 的某个 property,该 property 的值需要是列表中唯一的字符串或数字,且不能动态改变。
    保留关键字 *this 代表在 for 循环中的 item 本身,这种表示需要 item 本身是一个唯一的字符串或者数字,如:
    当数据改变触发渲染层重新渲染的时候,会校正带有 key 的组件,框架会确保他们被重新排序,而不是重新创建,以确保使组件保持自身的状态,并且提高列表渲染时的效率。

    如不提供 wx:key,会报一个 warning, 如果明确知道该列表是静态,或者不必关注其顺序,可以选择忽略。

    条件渲染:

    <!--wxml-->
    <view wx:if="{{view == 'WEBVIEW'}}"> WEBVIEW </view>
    <view wx:elif="{{view == 'APP'}}"> APP </view>
    <view wx:else="{{view == 'MINA'}}"> MINA </view>
    // page.js
    Page({
      data: {
        view: 'MINA'
      }
    })

    在框架中,使用 wx:if="{{condition}}" 来判断是否需要渲染该代码块。

    因为 wx:if 之中的模板也可能包含数据绑定,所以当 wx:if 的条件值切换时,框架有一个局部渲染的过程,因为它会确保条件块在切换时销毁或重新渲染。同时 wx:if 也是惰性的,如果在初始渲染条件为 false,框架什么也不做,在条件第一次变成真的时候才开始局部渲染。

    相比之下,hidden 就简单的多,组件始终会被渲染,只是简单的控制显示与隐藏。

    一般来说,wx:if 有更高的切换消耗而 hidden 有更高的初始渲染消耗。因此,如果需要频繁切换的情景下,用 hidden 更好,如果在运行时条件不大可能改变则 wx:if 较好。

    还可能会涉及到模板template,可以在模板中定义代码片段,然后在不同的地方调用。

    使用 name 属性,作为模板的名字。然后在<template/>内定义代码片段,如:

    <!--
      index: int
      msg: string
      time: string
    -->
    <template name="msgItem">
      <view>
        <text> {{index}}: {{msg}} </text>
        <text> Time: {{time}} </text>
      </view>
    </template>

    使用 is 属性,声明需要的使用的模板,然后将模板所需要的 data 传入,如:

    <template is="msgItem" data="{{...item}}"/>
    Page({
      data: {
        item: {
          index: 0,
          msg: 'this is a template',
          time: '2016-09-15'
        }
      }
    })

    is 属性可以使用 Mustache 语法,来动态决定具体需要渲染哪个模板:

    <template name="odd">
      <view> odd </view>
    </template>
    <template name="even">
      <view> even </view>
    </template>
    
    <block wx:for="{{[1, 2, 3, 4, 5]}}">
    	<template is="{{item % 2 == 0 ? 'even' : 'odd'}}"/>
    </block>

    模板拥有自己的作用域,只能使用 data 传入的数据以及模版定义文件中定义的 <wxs /> 模块。

    另外,target(触发事件的源组件)和currentTarget(事件绑定的当前组件)也比较重要,大家可以自行看例子和文档学习。

    dataset:在组件中可以定义数据,这些数据将会通过事件传递给 SERVICE。 书写方式: 以data-开头,多个单词由连字符-链接,不能有大写(大写会自动转成小写)如data-element-type,最终在 event.currentTarget.dataset 中会将连字符转成驼峰elementType。

    <view data-alpha-beta="1" data-alphaBeta="2" bindtap="bindViewTap"> DataSet Test </view>
    Page({
      bindViewTap:function(event){
        event.currentTarget.dataset.alphaBeta === 1 // - 会转为驼峰写法
        event.currentTarget.dataset.alphabeta === 2 // 大写会转为小写
      }
    })

    小程序的引用,如引用外部css文件、引入js文件、引入wxml模板文件等等。

    WXML 提供两种文件引用方式import和include。

    import可以在该文件中使用目标文件定义的template,如:在 item.wxml 中定义了一个叫item的template:

    <!-- item.wxml -->
    <template name="item">
      <text>{{text}}</text>
    </template>

    在 index.wxml 中引用了 item.wxml,就可以使用item模板:

    <import src="item.wxml"/>
    <template is="item" data="{{text: 'forbar'}}"/>

    import 有作用域的概念,即只会 import 目标文件中定义的 template,而不会 import 目标文件 import 的 template。

    include 可以将目标文件除了 <template/> <wxs/> 外的整个代码引入,相当于是拷贝到 include 位置,如:

    <!-- index.wxml -->
    <include src="header.wxml"/>
    <view> body </view>
    <include src="footer.wxml"/>
    <!-- header.wxml -->
    <view> header </view>
    <!-- footer.wxml -->
    <view> footer </view>

    再讲一个wxs文件,不太常用。WXS(WeiXin Script)是小程序的一套脚本语言,结合 WXML,可以构建出页面的结构。

    注意:
    1、wxs 不依赖于运行时的基础库版本,可以在所有版本的小程序中运行。
    2、wxs 与 javascript 是不同的语言,有自己的语法,并不和 javascript 一致。
    3、wxs 的运行环境和其他 javascript 代码是隔离的,wxs 中不能调用其他 javascript 文件中定义的函数,也不能调用小程序提供的API。
    4、wxs 函数不能作为组件的事件回调。
    5、由于运行环境的差异,在 iOS 设备上小程序内的 wxs 会比 javascript 代码快 2 ~ 20 倍。在 android 设备上二者运行效率无差异。
    以下是一些使用 WXS 的简单示例。

    页面渲染:

    <!--wxml-->
    <wxs module="m1">
    var msg = "hello world";
    
    module.exports.message = msg;
    </wxs>
    
    <view> {{m1.message}} </view>

    页面输出:

    hello world

    数据处理:

    // page.js
    Page({
      data: {
        array: [1, 2, 3, 4, 5, 1, 2, 3, 4]
      }
    })
    <!--wxml-->
    <!-- 下面的 getMax 函数,接受一个数组,且返回数组中最大的元素的值 -->
    <wxs module="m1">
    var getMax = function(array) {
      var max = undefined;
      for (var i = 0; i < array.length; ++i) {
        max = max === undefined ? 
          array[i] : 
          (max >= array[i] ? max : array[i]);
      }
      return max;
    }
    
    module.exports.getMax = getMax;
    </wxs>
    
    <!-- 调用 wxs 里面的 getMax 函数,参数为 page.js 里面的 array -->
    <view> {{m1.getMax(array)}} </view>

    页面会输出5。

    WXS 代码可以编写在 wxml 文件中的 <wxs> 标签内,或以 .wxs 为后缀名的文件内。

    每一个 .wxs 文件和 <wxs> 标签都是一个单独的模块。每个模块都有自己独立的作用域。即在一个模块里面定义的变量与函数,默认为私有的,对其他模块不可见。一个模块要想对外暴露其内部的私有变量与函数,只能通过 module.exports 实现。

    可以直接创建 .wxs 文件,在其中直接编写 WXS 脚本。

    var foo = "'hello world' from comm.wxs";
    var bar = function(d) {
      return d;
    }
    module.exports = {
      foo: foo,
      bar: bar
    };

    在.wxs文件里面编写了 WXS 代码。该 .wxs 文件可以被其他的 .wxs 文件 或 WXML 中的 <wxs> 标签引用。

    每个 wxs 模块均有一个内置的 module 对象。exports:通过该属性,可以对外共享本模块的私有变量与函数。

    // /pages/tools.wxs
    
    var foo = "'hello world' from tools.wxs";
    var bar = function (d) {
      return d;
    }
    module.exports = {
      FOO: foo,
      bar: bar,
    };
    module.exports.msg = "some msg";
    <!-- page/index/index.wxml -->
    
    <wxs src="./../tools.wxs" module="tools" />
    <view> {{tools.msg}} </view>
    <view> {{tools.bar(tools.FOO)}} </view>

    页面输出:

    some msg
    'hello world' from tools.wxs

    在.wxs模块中引用其他 wxs 文件模块,可以使用 require 函数。

    引用的时候,要注意如下几点:

    1、只能引用 .wxs 文件模块,且必须使用相对路径。
    2、wxs 模块均为单例,wxs 模块在第一次被引用时,会自动初始化为单例对象。多个页面,多个地方,多次引用,使用的都是同一个 wxs 模块对象。
    3、如果一个 wxs 模块在定义之后,一直没有被引用,则该模块不会被解析与运行。

    module 属性是当前 <wxs> 标签的模块名。在单个 wxml 文件内,建议其值唯一。有重复模块名则按照先后顺序覆盖(后者覆盖前者)。不同文件之间的 wxs 模块名不会相互覆盖。module 属性值的命名必须符合下面两个规则:

    1、首字符必须是:字母(a-zA-Z),下划线(_)。
    2、剩余字符可以是:字母(a-zA-Z),下划线(_), 数字(0-9)。

    src 属性可以用来引用其他的 wxs 文件模块。引用的时候,要注意如下几点:

    1、只能引用 .wxs 文件模块,且必须使用相对路径。
    2、wxs 模块均为单例,wxs 模块在第一次被引用时,会自动初始化为单例对象。多个页面,多个地方,多次引用,使用的都是同一个 wxs 模块对象。
    3、如果一个 wxs 模块在定义之后,一直没有被引用,则该模块不会被解析与运行。

    注意:
    1、<wxs> 模块只能在定义模块的 WXML 文件中被访问到。使用 <include> 或 <import> 时,<wxs> 模块不会被引入到对应的 WXML 文件中。
    2、<template> 标签中,只能使用定义该 <template> 的 WXML 文件中定义的 <wxs> 模块。

    再看下官方给出的小程序性能优化建议。

    setData 是小程序开发中使用最频繁的接口,也是最容易引发性能问题的接口。在介绍常见的错误用法前,先简单介绍一下 setData 背后的工作原理。

    小程序的视图层目前使用 WebView 作为渲染载体,而逻辑层是由独立的 JavascriptCore 作为运行环境。在架构上,WebView 和 JavascriptCore 都是独立的模块,并不具备数据直接共享的通道。当前,视图层和逻辑层的数据传输,实际上通过两边提供的 evaluateJavascript 所实现。即用户传输的数据,需要将其转换为字符串形式传递,同时把转换后的数据内容拼接成一份 JS 脚本,再通过执行 JS 脚本的形式传递到两边独立环境。而 evaluateJavascript 的执行会受很多方面的影响,数据到达视图层并不是实时的。

    常见的 setData 操作错误:
    1. 频繁的去 setData。

    在我们分析过的一些案例里,部分小程序会非常频繁(毫秒级)的去setData,其导致了两个后果:Android 下用户在滑动时会感觉到卡顿,操作反馈延迟严重,因为 JS 线程一直在编译执行渲染,未能及时将用户操作事件传递到逻辑层,逻辑层亦无法及时将操作处理结果及时传递到视图层;
    渲染有出现延时,由于 WebView 的 JS 线程一直处于忙碌状态,逻辑层到页面层的通信耗时上升,视图层收到的数据消息时距离发出时间已经过去了几百毫秒,渲染的结果并不实时;
    2. 每次 setData 都传递大量新数据。

    由setData的底层实现可知,我们的数据传输实际是一次 evaluateJavascript 脚本过程,当数据量过大时会增加脚本的编译执行时间,占用 WebView JS 线程,

    3. 后台态页面进行 setData。

    当页面进入后台态(用户不可见),不应该继续去进行setData,后台态页面的渲染用户是无法感受的,另外后台态页面去setData也会抢占前台页面的执行。

    图片资源:
    目前图片资源的主要性能问题在于大图片和长列表图片上,这两种情况都有可能导致 iOS 客户端内存占用上升,从而触发系统回收小程序页面。

    图片对内存的影响:
    在 iOS 上,小程序的页面是由多个 WKWebView 组成的,在系统内存紧张时,会回收掉一部分 WKWebView。从过去我们分析的案例来看,大图片和长列表图片的使用会引起 WKWebView 的回收。

    图片对页面切换的影响:
    除了内存问题外,大图片也会造成页面切换的卡顿。我们分析过的案例中,有一部分小程序会在页面中引用大图片,在页面后退切换中会出现掉帧卡顿的情况。当前我们建议开发者尽量减少使用大图片资源。

    代码包大小的优化:
    小程序一开始时代码包限制为 1MB,但我们收到了很多反馈说代码包大小不够用,经过评估后我们放开了这个限制,增加到 2MB 。代码包上限的增加对于开发者来说,能够实现更丰富的功能,但对于用户来说,也增加了下载流量和本地空间的占用。开发者在实现业务逻辑同时也有必要尽量减少代码包的大小,因为代码包大小直接影响到下载速度,从而影响用户的首次打开体验。除了代码自身的重构优化外,还可以从这两方面着手优化代码大小:

    控制代码包内图片资源:
    小程序代码包经过编译后,会放在微信的 CDN 上供用户下载,CDN 开启了 GZIP 压缩,所以用户下载的是压缩后的 GZIP 包,其大小比代码包原体积会更小。 但我们分析数据发现,不同小程序之间的代码包压缩比差异也挺大的,部分可以达到 30%,而部分只有 80%,而造成这部分差异的一个原因,就是图片资源的使用。GZIP 对基于文本资源的压缩效果最好,在压缩较大文件时往往可高达 70%-80% 的压缩率,而如果对已经压缩的资源(例如大多数的图片格式)则效果甚微。

    及时清理没有使用到的代码和资源:
    在日常开发的时候,我们可能引入了一些新的库文件,而过了一段时间后,由于各种原因又不再使用这个库了,我们常常会只是去掉了代码里的引用,而忘记删掉这类库文件了。目前小程序打包是会将工程下所有文件都打入代码包内,也就是说,这些没有被实际使用到的库文件和资源也会被打入到代码包里,从而影响到整体代码包的大小。

    下面将会讲解一些开发中遇到的问题:

    列表绑定渲染数据、跳转传值、小程序的工具调试使用、小程序授权弹窗、小程序客服反馈、小程序支付、小程序获取unionId和openId、小程序第三方框架、UI库等。

     

     

    这个是开源share的,github地址:https://github.com/jaychou2012/wx_note

     

     

    持续更新中,敬请关注... ...

    展开全文
  • 程序面试题 1.bindtap和catchtap的区别是什么? bind事件绑定不会阻止冒泡事件向上冒泡,catch事件绑定可以阻止冒泡事件向上冒泡 2.Js数组转成换字符串,强制转换成整数及转换成浮点数的函数分别是什么? js...

     

    小程序面试题

    1. bindtap和catchtap的区别是什么?

    bind事件绑定不会阻止冒泡事件向上冒泡,catch事件绑定可以阻止冒泡事件向上冒泡

    2. Js数组转成换字符串,强制转换成整数及转换成浮点数的函数分别是什么?

    js提供了parseInt()和parseFloat()两个转换函数。前者把值转换成整数,后者把值转换成浮点数。只有对String类型调用这些方法,这两个函数才能正确运行;对其他类型返回的都是NaN(Not a Number)。

    1. 转换函数:

    在 判断字符串是否是数字值前,parseInt()和parseFloat()都会仔细分析该字符串。parseInt()方法首先查看位置0处的 字符,判断它是否是个有效数字;如果不是,该方法将返回NaN,不再继续执行其他操作。但如果该字符是有效数字,该方法将查看位置1处的字符,进行同样的 测试。这一过程将持续到发现非有效数字的字符为止,此时parseInt()将把该字符之前的字符串转换成数字。

    parseInt("1234blue"); //returns 1234 
    parseInt("0xA"); //returns 10 
    parseInt("22.5"); //returns 22 
    parseInt("blue"); //returns NaN

    2. 强制类型转换

    还可使用强制类型转换(type casting)处理转换值的类型。使用强制类型转换可以访问特定的值,即使它是另一种类型的。
    ECMAScript中可用的3种强制类型转换如下: 
    Boolean(value)——把给定的值转换成Boolean型; 
    Number(value)——把给定的值转换成数字(可以是整数或浮点数); 
    String(value)——把给定的值转换成字符串。

    3. 利用js变量弱类型转换

    举个小例子,一看,就会明白了。
    <script> 
    var str= '012.345 '; 
    var x = str-0; 
    x = x*1;
    </script>

    上例利用了js的弱类型的特点,只进行了算术运算,实现了字符串到数字的类型转换,不过这个方法还是不推荐的。

     

    3. 简单描述下微信小程序的相关文件类型

    小程序:pages ——index:index.js(页面逻辑) /index.wxml (页面结构)/index.wxss (页面样式表) / index.json (页面配置)

    App.js   小程序逻辑

    App.json  小程序公共设置

    App.wxss   小程序公共样式表

    4. 小程序有哪些参数传值的方法?

    1、设置id的方法标识跳转后传递的参数值;

    2、通过使用data - xxxx 的方法来标识要传递的值

    微信小程序设置id的方法标识来传值

    在要跳转的item处,设置一个id并给当前的id赋值上对应的key值,比如一部电影的id(后面带着id去下一个页面查询,详细信息)如:

    后我们在js的bindtap的响应事件中获取,并传递到下一个界面中;

    获取到id传的值

    通过e.currentTarget.id;获取设置的id值,并通过设置全局对象的方式来传递数值,

    获取全局对象 var app=getApp(); //设置全局的请求访问传递的参数 app.requestDetailid=id;

    提示:其实我们也可以在,wxml中查看到我们设置的每一个item的id值

    通过使用data - xxxx 的方法标识来传值

    通过使用data - xxxx 的方法标识来传值,xxxx可以自定义取名 比如data-key等等都可以。

    如何获取data-xxxx传递的值?

    在js的bindtap的响应事件中:

    通过数据解析一层层找到数据,var id=e.target.dataset.id(根据你的data-id的取名)

    微信小程序如何跨页面获取值?

    依据上面的方式设置要传递的值,页面跳转后,我们就需要在下一个页面拿到传递的数据(这个数据在传递前,就已经被设置成全局变量

    在跳转后的js页面,接收传递过来的数据detail.js

    同样通过全局额方式取值出来,(即和app.js中取某个变量的值是一样的)

    var movieid=getApp().MovieDetailid;
    console.log(movieid);

    5. 简述下wx.navigateTo(), wx.redirectTo(), wx.switchTab(), wx.navigateBack(), wx.reLaunch()的区别?

    微信小程序 跳转页面

    小程序页面有2种跳转,可以在wxml页面或者js中:

    1,在wxml页面中:

    <navigator url="../index/index">跳转到新页面</navigator>

    <navigator url="../index/index" open-type="redirect">在当前页打开</navigator>

    <navigator url="../index/index" open-type="switchTab">切换到首页Tab</navigator>

     

    2,在js页面中:

    【注意】此处注意两个关键词 “应用内的页面” 和 “tabBar页面”。  app.json文件中tabBar中注册过的tab页,即为“tabBar页面”,非tabBar中注册占用的页面即为“应用内的页面” 。 如下图:home页面为“应用内的页面”,index和logs页面则为 “tabBar页面”。

     

    3,如果上述跳转遇到跳转失败或无效的问题,请访问下面链接:

    wx.navigateTo/wx.redirectTo 无效

    6. 如果需要用户授权,用户选择拒绝授权,此时应该如何处理?

    在微信小程序开发时,当我们调用API  wx.getUserInfo(OBJECT) 时,需要用户授权。但如果用户拒绝授权,我们如何兼容用户拒绝授权状态,拥有更好的用户体验呢?

    先看看这个接口的官方文档:

    wx.getUserInfo(OBJECT)

    获取用户信息,需要先调用 wx.login 接口。

    OBJECT参数说明:

    参数名

    类型

    必填

    说明

    withCredentials

    Boolean

    是否带上登录态信息

    success

    Function

    接口调用成功的回调函数

    fail

    Function

    接口调用失败的回调函数

    complete

    Function

    接口调用结束的回调函数(调用成功、失败都会执行)

    1. tipwx.getUserInfo 接口需要用户授权,请兼容用户拒绝授权的场景。

    我们就是要在用户点击拒绝的时候,弹出提示框,提示用户以提升用户体验。像下面这样的。

    用具体代码实现就是,将弹窗写在 wx.getUserInfo 的fail回调函数中,像下面这样:

    wx.getUserInfo({

    success: function (resuser) {

    console.log(success)

    },

    fail: function () {// 调用微信弹窗接口

    wx.showModal({

    title: '警告',

    content: '您点击了拒绝授权,将无法正常使用******的功能体验。请10分钟后再次点击授权,或者删除小程序重新进入。',

    success: function (res) {

    if (res.confirm) {

    console.log('用户点击确定')

    }

    }

    })

    }

    })

    这样用户就获得了提示信息,但此时,用户还是停留在页面的,如果某些展示信息,还是给要给用户展示的,只是在进行某些操作的时候要对授权进行验证的话,那就得继续修改我们的代码,保存用户的登录态,在其他地方做验证使用。

    第一种思路:

    保存登录态这里是这样的,将用户的登录信息传给后台,后台保存用户信息,同时用 open_id 在后台换取一个SessionId  用换取的这个SessionId 存在缓存,做为登录态验证。

    wx.getUserInfo({

    success: function (resuser) {

    let userInfo = resuser.userInfo

    that.healthApi.login(code, userInfo).then(logindata => {   // 这里将微信的请求封装成Promiese 风格

    if (logindata.code === 0) {

    var sessionId = logindata.data// 调用微信wechat.setStorage将换回来的 SessionId 存在本地缓存

    that.wechat.setStorage('sessionId', sessionId).then(() => {

    that.globalData.userInfo = userInfo

    typeof cb == "function" && cb(that.globalData.userInfo)

    })

    }

    })

    },

    fail: function () {

    wx.showModal({

    title: '警告',

    content: '您点击了拒绝授权,将无法正常使用*****的功能体验。请10分钟后再次点击授权,或者删除小程序重新进入。',

    success: function (res) {

    if (res.confirm) {

    console.log('用户点击确定')

    }

    }

    })

    }

    })

    这样我们将登录态保存在了 SessionId 中,在每次登录的时候我们只需要再调用一个 检查 SessionId的接口就行,检查不通过再调微信登录接口。此处不做延伸了。

    第二种思路:

    在3.29微信小程序更新的版本中,加入了这样一条属性

    withCredentials 字段基础库版本 1.1.0 开始支持,低版本需做兼容处理

    这个字段的意思就是调用 wx.getUserInfo(OBJECT) 是否带上 登录态  的信息。

    官方文档是这样解释的:

    withCredentials 字段基础库版本 1.1.0 开始支持,低版本需做兼容处理

    注:当 withCredentials 为 true 时,要求此前有调用过 wx.login 且登录态尚未过期,此时返回的数据会包含 encryptedData, iv 等敏感信息;当 withCredentials 为 false 时,不要求有登录态,返回的数据不包含 encryptedData, iv 等敏感信息。

    success返回参数说明:

    参数

    类型

    说明

    userInfo

    OBJECT

    用户信息对象,不包含 openid 等敏感信息

    rawData

    String

    不包括敏感信息的原始数据字符串,用于计算签名。

    signature

    String

    使用 sha1( rawData + sessionkey ) 得到字符串,用于校验用户信息。

    encryptedData

    String

    包括敏感数据在内的完整用户信息的加密数据,详细见加密数据解密算法

    iv

    String

    加密算法的初始向量,详细见加密数据解密算法

    注:需要兼容微信低版本,向后兼容

    那么利用这个接口,我们可以直接拿到 登录状态,在其他需要验证登录的地方进行提示,而在不需要授权的地方还可以让用户浏览小程序。

    回到前面的问题,在用户点击拒绝授权后,在某些操作时需要验证用户是否授权过,弹出交互信息,那么就利用上面的 SessionId或者 withCredentials 登录态进行下面的操作:

    applyIn: function applyIn() {

    if (wx.getStorageSync('sessionId')) {  // 根据储存的sessionId 进行验证

    wx.navigateTo({

    url: 'familyDoctorApply/familyDoctorApply?Oid=' + this.data.params.Oid + '&title=' + this.data.params.title + '&serviceCity=' + this.data.array[this.data.index].name + '&productPrice=' + this.data.product.productPrice

    });

    } else {

    wx.showModal({

    title: '警告',

    content: '您点击了拒绝授权,无法使用此功能。',

    success: function (res) {

    if (res.confirm) {

    console.log('用户点击确定')

    }

    }

    })

    }

    效果像这样:

    这样一个简单完整的登录及授权,登录态保存等前端微信小程序解决方案就完成了,还可以继续扩展到登录有效期,退出登录,用户权限等跟多扩展的地方。

    7. 你平时封装可以复用的方法吗?你会把可以复用的方法写在哪个文件里?

    其实可以模拟一些框架的,比如bootsrap,写个demo出来,抽出css和js,js最好抽象成对象(构造函数)或者是带参数的方法,然后你只要声明对像,或者参数指定某个class或id,就可以了

    写在html文件里有什么优点吗?
    独立出来会有什么问题吗?尤其是载入页面的时候,应该会多发很多http请求吧,会不会造成加载变慢?

    8. 分析下小程序的优劣势?

    小程序是在微信生态发展过程中新出现的一种应用形态,小程序的小,从某种程度上已经说明了它的体量不会很大,但是可以实现一些功能相对简单、交互相对简单的服务需求,同时解决了App长期以来多平台适配、多应用市场分发、开发成本居高不下等诸多方面的问题。所以小程序【密件】依靠微信平台和自身“阅后即焚”的功能,获得众多年轻人的好评

    优势:

    1)容易上手,只要之前有HTML+CSS+JS基础知识,写小程序基本上没有大问题;当然如果了解ES6+CSS3则完全可以编写出即精简又动感的小程序;

    2)基本上不需要考虑兼容性问题,只要微信可以正常运行的机器,就可以运行小程序;

    3)基本组件库已经比较齐全:Toast,Loading框,Picker,定位及地图,Image,Input,Checkbox,Text,TextArea,ScrollView等常用的组件都有,而且使用也挺简单、方便;

    4)发布、审核高效,基本上上午发布审核,下午就审核通过,升级简单,而且支持灰度发布;

    5 ) 微信官方提供使用人数、频率等数据统计,小程序js脚本执行错误日志;

    6)开发文档比较完善,开发社区比较活跃;

    7)最近刚开放的牛x功能,新增webview组件,可以展示网页啦,这个比较爽;

    8)支持插件式开发,一些基本功能可以开发成插件,供多个小程序调用;

    劣势:

    1)后台调试麻烦,因为API接口必须https请求,且公网地址,也就是说后台代码必须发布到远程服务器上;当然我们可以修改host进行dns映射把远程服务器转到本地,或者开启tomcat远程调试;不管怎么说终归调试比较麻烦。

    2)前台测试有诸多坑,最头疼莫过于模拟器与真机显示不一致(之前碰到一个案例,后续单独讲解)

    3)真机测试,个别功能安卓和苹果表现迥异,我们的小程序里有很多页面有定位功能,模拟器和iphone定位瞬间完成,然而安卓手机就蛋疼了,老显示“定位中...”要很久才能定位好。后来没办法只能优化,减少定位次数。

    4)native组件,展示很不好,比如textarea,不能在滚动页面出现,而且至于顶层,经常其它组件会被它遮挡,点击其它组件时,就进入textarea输入框;画布组件也是如此;

    5)页面跳转深度不能超过5个页面,这个比较麻烦,有些复杂的页面跳转没法实现,不过太复杂的话也有悖小程序简单易用的原则啦;

    6)小程序升级问题,官方文档说会自动更新,实际情况往往是要先把原来的小程序删除掉,重新搜索添加,才能加载最新版本;

    7)页面渲染稳定性有待提高,已经好几次出现部分用户的页面显示异常,整个页面被放大了好几倍,先删除原来小程序再添加回来,如此重复好几次,才能显示正常;

    8)js引用只能使用绝对路径,很蛋疼;基于安全性及MINA框架实现原理,小程序中对js使用做了很多限制,不能使用:new Function,eval,Generator,不能操作cookie,不能操作DOM;

    9)开发工具bug比较多且效率比较低,三天两头升级,解决老问题的同时又出现问题;文件查找、资源定位、代码编辑较eclipse有一定差距。经常出现把a.js当做b.js来修改

    9. 设置值到页面暂存区(即data)里面的方法有几种?分别是什么?有什么区别?

    1. 使用QueryString变量
        QueryString是一种非常简单的传值方式,他可以将传送的值显示在浏览器的地址栏中。如果是传递一个或多个安全性要求不高或是结构简单的数值时,可以使用这个方法。但是对于传递数组或对象的话,就不能用这个方法了。下面是一个例子:
    a.aspx的C#代码
    private void Button1_Click(object sender, System.EventArgs e)
    {
     string s_url;
     s_url = "b.aspx?name=" + Label1.Text;
     Response.Redirect(s_url);
    }

    b.aspx中C#代码
    private void Page_Load(object sender, EventArgs e)
    {
     Label2.Text = Request.QueryString["name"];
    }

      2. 使用Application 对象变量
        Application对象的作用范围是整个全局,也就是说对所有用户都有效。其常用的方法用Lock和UnLock。
    a.aspx的C#代码
    private void Button1_Click(object sender, System.EventArgs e)
    {
     Application["name"] = Label1.Text;
     Server.Transfer("b.aspx");
    }

    b.aspx中C#代码
    private void Page_Load(object sender, EventArgs e)
    {
     string name;
     Application.Lock();
     name = Application["name"].ToString();
     Application.UnLock();
    }

      3. 使用Session变量
        想必这个肯定是大家使用中最常见的用法了,其操作与Application类似,作用于用户个人,所以,过量的存储会导致服务器内存资源的耗尽。
    a.aspx的C#代码
    private void Button1_Click(object sender, System.EventArgs e)
    {
     Session["name"] = Label.Text;
    }

    b.aspx中C#代码
    private void Page_Load(object sender, EventArgs e)
    {
     string name;
     name = Session["name"].ToString();
    }

      4. 使用Cookie对象变量
        这个也是大家常使用的方法,与Session一样,其是什对每一个用户而言的,但是有个本质的区别,即Cookie是存放在客户端的,而session是存放在服务器端的。而且Cookie的使用要配合ASP.NET内置对象Request来使用。

    a.aspx的C#代码
    private void Button1_Click(object sender, System.EventArgs e)
    {
     HttpCookie cookie_name = new HttpCookie("name");
     cookie_name.Value = Label1.Text;
     Reponse.AppendCookie(cookie_name);
     Server.Transfer("b.aspx");
    }

    b.aspx中C#代码
    private void Page_Load(object sender, EventArgs e)
    {
     string name;
     name = Request.Cookie["name"].Value.ToString();
    }

      5. 使用Server.Transfer方法
        这个才可以说是面象对象开发所使用的方法,其使用Server.Transfer方法把流程从当前页面引导到另一个页面中,新的页面使用前一个页面的应答流,所以这个方法是完全面象对象的,简洁有效。
    a.aspx的C#代码
    public string Name
    {
     get{ return Label1.Text;}
    }
    private void Button1_Click(object sender, System.EventArgs e)
    {
     Server.Transfer("b.aspx");
    }

    b.aspx中C#代码
    private void Page_Load(object sender, EventArgs e)
    {
     a newWeb; //实例a窗体
     newWeb = (source)Context.Handler;
     string name;
     name = newWeb.Name;
    }

     

    微信小程序--data的赋值与取值

    通过小程序官方文档可知:

    Page() 函数用来注册一个页面。接受一个 object 参数,其指定页面的初始数据、生命周期函数、事件处理函数等。其中的参数data用来设置初始数据,WXML 中的动态数据均来自对应 Page 的 data。

    所以如果页面需要显示动态数据必须要把数据更新到data中对应的变量中。

    · 页面js文件中这么写:

    Page({

      data: {

        message: 'Hello MINA!'

      }

    })

    · wxml中这么写:

    <view> {{ message }} </view>

    · 如果该数据在操作过程中发生变化,需要将新数据重新绑定到该变量中,写法如下:

    function setData(){

        var that = this;

        that.setData({

          message: '新消息'

        })

    }

    · 如果想在js文件中使用data中的数据写法如下:

    function getData(){

        var that = this;

        console.log(that.data.message)

    }

     

    10. 如何检测用户的微信版本是否支持某项功能?

    第一期开放的接口,不是不能使用,而是无需检测,全部都是支持的。
    只有后面最新开放的一些接口,才需要检测是否支持。
    目前开放的所有接口:
    onMenuShareTimeline
    onMenuShareAppMessage
    onMenuShareQQ
    onMenuShareWeibo
    onMenuShareQZone
    startRecord
    stopRecord
    onVoiceRecordEnd
    playVoice
    pauseVoice
    stopVoice
    onVoicePlayEnd
    uploadVoice
    downloadVoice
    chooseImage
    previewImage
    uploadImage
    downloadImage
    translateVoice
    getNetworkType
    openLocation
    getLocation
    hideOptionMenu
    showOptionMenu
    hideMenuItems
    showMenuItems
    hideAllNonBaseMenuItem
    showAllNonBaseMenuItem
    closeWindow
    scanQRCode
    chooseWXPay
    openProductSpecificView
    addCard
    chooseCard
    openCard

     

    11. 如何分包加载?分包加载的优势在哪?

    分包加载的介绍
          大部分小程序都会由某几个功能组成,通常这几个功能之间是独立的,但会依赖一些公共的逻辑,并且这些功能通常会对应某几个独立的页面。那么小程序代码的打包,大可不必一定要打成一个,可以按照功能的划分,拆分成几个分包,当需要用到某个功能时,才加载这个功能对应的分包。
    对于用户来说,小程序加载流程变成了:
    1.首次启动时,先下载小程序主包,显示主包内的页面;
    2.如果用户进入了某个分包的页面,再下载这个对应分包,下载完毕后,显示分包的页面。
    采用分包加载,对开发者而言,能使小程序有更大的代码体积,承载更多的功能与服务;而对用户而言,可以更快地打开小程序,同时在不影响启动速度前提下使用更多功能。
    分包的划分
    在配置前首先需要开发者规划下各个分包需要容纳的内容,我们建议开发者按照功能划分的的原则,将同一个功能下的页面和逻辑放置于同一个目录下,对于一些跨功能之间公共逻辑,将其放置于主包下,这样可以确保在分包引用这部分功能时,这部分的逻辑一定存在。
    在分包划分时,应该注意以下事项:
    1.避免分包与分包之间引用上的耦合。因为分包的加载是由用户操作触发的,并不能确保某分包加载时,另外一个分包就一定存在,这个时候可能会导致 JS 逻辑异常的情况,例如报「"xxx.js" is not defined」这样的错误;
    2.一些公共用到的自定义组件,需要放在主包内。
    分包的配置
          当理清了分包的划分后,就可以进行分包的配置了,这一步并不复杂。

          假设支持分包的小程序目录结构如下:

     

         开发者通过在 app.json subPackages 字段声明项目分包结构:

    分包加载的低版本兼容问题
       微信 6.6.0 版本开始支持分包加载,而对于低于这个版本的客户端,我们做了兼容处理,开发者不需要对老版本微信客户端做兼容。对于老版本的客户端,编译后台会将所有的分包打包成一个整包,老版本的客户端依然按照整包的方式进行加载。
    所以在老版本的微信客户端下,是依然采取整包加载的方式加载的,建议开发者尽量控制代码包的大小。
    目前小程序分包大小的限制:
        整个小程序所有分包大小不超过 4M
        单个分包/主包大小不能超过 2M
       随着时间推移,老版本覆盖率降低,我们会考虑进一步扩大代码包的大小。

     

    12. 在你开发小程序的过程中遇到过什么坑? 你是怎么解决的?

    1.我们使用app.json文件来对微信小程序进行全局配置,决定页面文件的路径、窗口表现、设置网络超时时间、设置多 tab 的时候在pages中写注释的时候回报错。 
    例如:

    {

      "pages":[

          //这是首页面

        "pages/welcome/welcome"

      ]}

    此时就会报错 


    2.在json文件中没有写内容的时候也要加一对大括号{ },不然的话也会报错 
     
    3. ①在开发微信小程序的时候,我们使用app.json文件来对微信小程序进行全局配置,决定页面文件的路径,窗口表现,设置网络超时时间,设置多Tab等。 
    以下是一个包含了所有配置选项的简单配置,app.json :

    {

      //设置页面路径

      "pages": [

        "pages/index/index",

        "pages/logs/index"

      ],

      //设置默认页面的窗口表现

      "window": {

        "navigationBarTitleText": "Demo"

      },

      //设置底部 tab 的表现

      "tabBar": {

        "list": [{

          "pagePath": "pages/index/index",

          "text": "首页"

        }, {

          "pagePath": "pages/logs/logs",

          "text": "日志"

        }]

      },

      //设置网络超时时间

      "networkTimeout": {

        "request": 10000,

        "downloadFile": 10000

      },

      //设置是否开启 debug 模式

      "debug": true

    }

    ②但是在对页面json文件进行配置的时候只可以配置设置默认页面的窗口表现(即只能对window进行配置),但是在此时可以直接省略window,如果加window则没有效果,也不会报错。 
    以下是一个包含了window配置选项的简单配置,post.json :

    注意:这是错误的写法

    {

      "window":{

        "navigationBarBackgroundColor": "#ffffff",

        "navigationBarTextStyle": "black",

        "navigationBarTitleText": "微信接口功能演示",

        "backgroundColor": "#eeeeee",

        "backgroundTextStyle": "light"

      }}

    注意:正确的写法

    {

        "navigationBarBackgroundColor": "#ffffff",

        "navigationBarTextStyle": "black",

        "navigationBarTitleText": "微信接口功能演示",

        "backgroundColor": "#eeeeee",

        "backgroundTextStyle": "light"}

    4.此前一直没有注意vertical-align: middle和height:40rpx;line-height:40rpx进行设置垂直剧中的区别,这次主要说一下vertical-align: middle 
    代码如下:

    <view class="post-author-date">

        <image class="post-author" src="../../images/avatar/1.png">

        </image>

        <text class="post-date">Nov 15 2016</text>

    </view>

     

    .post-author{

        width: 60rpx;

        height: 60rpx;

        vertical-align: middle;

    }

    .post-date{

        margin-top: 5rpx;

        vertical-align: middle;

        /*height: 40rpx;

        line-height: 40rpx;*/

    }

    总结: 
    ①vertical-align: middle;把此元素放在父元素的中部 
    ②当一个父元素里面有多个子元素,需要把几个子元素水平对齐,并且每个子元素都垂直剧中的时候,对每一个子元素进行设置 vertical-align: middle 
    ③height: 40rpx; line-height: 40rpx;可以对文本进行垂直居中

     

    最后为了方便大家的沟通与交流请加QQ群: 625787746

    展开全文
  • easy-window 是一个旨在简化桌面开发难度的通用窗体,它可以让你使用当前主流的HTML5技术快速地创建Windows桌面应用程序。创作桌面应用,不需要掌握QT,C++,C#,Java那些繁琐的东西,只要会创建网页就可以。同...

    这段时间要写一个桌面软件,比来比去没有满意的,要么不好看,要么不好用,要么打包体积太大。所以就有了这个小项目——easy-window

    easy-window是什么?

    easy-window 是一个旨在简化桌面开发难度的通用窗体,它可以让你使用当前主流的HTML5技术快速地创建Windows桌面应用程序。创作桌面应用,不需要掌握QT,C++,C#,Java那些繁琐的东西,只要会创建网页就可以。同时相较于NW.jsElectron,使用方式更加简洁,体积更小(只有几M)。

    软件界面可以有多绚,就看想象力了。闲话不多说,先来看看本工具可以创建哪些窗体应用吧。

    应用示例

    1. 简单窗体

    image
    image

    1. 设置窗体图标和标题

    image

    1. 限制窗体宽高

    image

    1. 隐藏最大化最小化按钮

    image

    1. 无边框窗体

    image
    image
    image

    1. 不规则窗体

    image
    image


    使用方法

    如果要运行示例程序,只需下载easy-window.exe文件,samples文件夹和后缀名为.vbs的文件,运行对应的vbs文件即可。可以修改vbs文件中对应的参数调整窗体样式。
    vbs参数示例说明:

    Dim shell
    Set shell = WScript.CreateObject("WScript.Shell") 
    shell.run "easy-window.exe -url https://www.baidu.com -title 百度首页"
    

    其中easy-window.exe是渲染窗体的主程序,-url指定了要显示的页面,-title设置窗口标题为百度首页,运行效果如下图:
    image
    当然,vbs文件不是必须的,可以直接在cmd控制台中运行easy-window.exe -url https://www.baidu.com -title 百度首页,效果是一样的。
    更多启动参数用法请参考下方参数说明

    参数说明

    bool类型值只能是true或者false

    参数 类型 说明
    url string 网页地址,相对地址,绝对地址,远程网址均可
    timeout int 等待页面加载超时时间,单位:毫秒
    icon string 窗体图标路径
    title string 窗体标题
    minbox bool 最小化窗体按钮,默认值:true
    maxbox bool 最大化窗体按钮,默认值:true
    minmax bool 限定窗口缩放范围,默认值:false
    border bool 窗体是否有边框,默认值:true
    resizable bool 窗体是否可缩放,默认值:true
    shadow bool 窗体边框是否有阴影,默认值:false
    posx int 窗体初始横坐标
    posy int 窗体初始纵坐标
    width int 窗体宽度
    height int 窗体高度
    contextmenu bool 是否启用鼠标右键菜单,默认值:true
    layered bool 是否是不规则窗体,默认值:false
    toolwindow bool 是否是弹窗工具窗体,默认值:false
    topmost bool 窗体是否置顶,默认值:false

    内置扩展JS函数

    内置扩展JS函数的作用是弥补Javascript在开发桌面应用时,无法调用Windows api的不足。使用这些扩展的JS函数的时候就跟调用原生的JS函数一样方便,只需要在函数前边加上external.即可。
    使用示例:

    <!DOCTYPE html>
    <html lang="en">
    <head>
    	<meta charset="UTF-8">
    <body>
    	<button onclick="loadFile()">打开文件</button>
    	<script>
    		function loadFile(){
    			//选择文件
    			var filePath = external.openFile('所有文件|*.*|文本文件(.txt)|*.txt|');
    			//读取并显示文件
    			external.alert(external.readFile(filePath), '您选择的文件内容如下');
    		}
    	</script>
    </body>
    </html>
    

    运行效果

    image
    image
    可以看到,调用external.openFile()打开了文件选择窗口,选择文件之后,该函数返回了选择的文件路径。external.readFile()则实现了本地文件的读取。
    更多函数请参见下方函数说明。

    函数 说明
    hitCaption() 主要用于绑定鼠标拖动窗体。比如,在无边框或者不规则窗体中,对指定html元素绑定该函数即可实现鼠标拖动该元素的功能,示例:<img src="images/ecology-heart.png" onmousedown="external.hitCaption()">,详情参见不规则窗体示例
    hitMax() 最大化窗体
    hitMin() 最小化窗体
    close() 关闭窗体
    alert(text, title) 提示框,text:提示内容,title:提示窗口标题
    openFile(fileType, title) 打开文件,fileType:文件类型(所有文件|*.*|文本文件|*.txt|), title:选择文件窗口标题。参数均非必填
    openDir(dir, subTitle, title) 打开目录,dir:初始目录, subTitle:子标题, title:标题。参数均非必填
    saveFile(fileType, title) 保存文件,fileType:文件类型(所有文件|*.*|文本文件|*.txt|), title:窗口标题。参数均非必填
    readFile(path) 读取文件,path:文件路径
    writeFile(path, text) 写文件,path: 文件路径, text:文件内容
    clipRead() 读取剪贴板内容
    clipWrite(text) 将内容写入剪贴板,text:文本内容
    getMousePos() 获取鼠标位置
    getPos() 获取窗体位置
    setPos(x,y,width,height) 设置窗体位置和大小,x:横坐标,y:纵坐标,width:宽度,height:高度。宽高参数可选
    getScreen() 获取屏幕宽高
    setIcon(iconPath) 设置窗体图标
    setTitle(text) 设置窗体标题
    setTopmost(state) 窗体是否置顶,state:true/false

    备注

    本项目主要目的在于简化桌面窗体开发,本身功能有限。如果需要更多功能,有两种方案:

    1. 用户界面使用miniblink(精简浏览器内核)做渲染,浏览器支持的大部分功能基本都支持,所以可以通过Ajax或者Websocket与其它服务器语言通信,更多功能由其他语言实现,其实就是用开发网站那一套开发桌面软件。
    2. 本项目使用aardio语言开发,您可以自行修改编译源码,然后打包,替换本项目的easy-window.exe即可。

    如果你对本项目感兴趣,欢迎使用,共同探讨完善。

    项目地址: https://github.com/lixk/easy-window

    项目引用

    1. aardio 地址 http://www.aardio.com/

    2. miniblink 地址 https://weolar.github.io/miniblink/

    展开全文
  • 注册微信小程序 如果你还没有微信公众平台的账号,请先进入微信公众平台首页,点击 “立即注册” 按钮进行注册。注册的账号类型可以是订阅号、服务号、小程序以及企业微信,我们选择 “小程序” 即可。 接着填写...

    注册微信小程序

    如果你还没有微信公众平台的账号,请先进入微信公众平台首页,点击 “立即注册” 按钮进行注册。注册的账号类型可以是订阅号、服务号、小程序以及企业微信,我们选择 “小程序” 即可。

    接着填写账号信息,需要注意的是,填写的邮箱必须是未被微信公众平台注册、未被个人微信号绑定的邮箱,而且每个邮箱仅能申请一个小程序。

    激活邮箱之后,选择主体类型为 “个人类型”,并按要求登记主体信息。主体信息提交后不可修改,该主体将成为你使用微信公众平台各项服务和功能的唯一法律主体与缔约主体,在后续开通其他业务功能时不得变更或修改。

    在这里插入图片描述

    一切 OK 就可以直接进入小程序的管理平台了。如果直接跳转失败,也可以从微信公众平台上手动登录。填写小程序的基本信息,包括名称、图标、描述等。提交成功之后,再添加开发者。开发者默认为管理员,我们也可以从这里新增绑定开发者,这是管理员才有权限的操作。

    然后在左侧导航栏点击 “设置”,找到开发设置,获得小程序的 AppID。

    微信开发者工具

    下载微信web开发者工具,根据自己的操作系统下载对应的安装包进行安装即可。

    打开开发者工具,用微信扫码登录开发者工具,准备开发你的第一个小程序吧!

    第一个小程序

    新建项目

    打开开发者工具,选择 “小程序项目”,点击右下角的 “+” 新建项目。

    选择一个空的文件夹作为项目目录,填入刚刚的 AppID,再填写一个项目名称,比如我这里叫做 GoZeroWaster。点击 “确定” 进入工具主界面。

    项目目录结构

    微信小程序的基本文件构造和项目目录结构说明如下:

        .
        ├── app.js     # 小程序的逻辑文件
        ├── app.json   # 小程序的配置文件
        ├── app.wxss   # 全局公共样式文件
        ├── pages      # 存放小程序的各个页面
        │   ├── index  # index页面
        │   │   ├── index.js     # 页面逻辑
        │   │   ├── index.wxml   # 页面结构
        │   │   └── index.wxss   # 页面样式表
        │   └── logs   # logs页面
        │       ├── logs.js      # 页面逻辑
        │       ├── logs.json    # 页面配置
        │       ├── logs.wxml    # 页面结构
        │       └── logs.wxss    # 页面样式表
        ├── project.config.json
        └── utils
            └── util.js
    

    根目录下有3个文件:app.js、app.json、app.wxss,小程序必须有这3个描述 APP 的文件,并放在根目录下。这3个是应用程序级别的文件,与之平行的还有一个 pages 文件夹,用来存放小程序的各个页面。

    我们可以和 web 前端开发技术做个类比:

    • wxml 类似于 HTML 文件,用来编写页面的标签和骨架,但里面只能用小程序自己封装的组件;
    • wxss 类似于 CSS 文件,用来编写页面样式,只是把 css 文件换成了 wxss 文件;
    • js 文件类似于前端编程中的 JavaScript 文件,用来编写小程序的页面逻辑;
    • json 文件用来配置页面的样式和行为。

    目标成果

    我们先来看看最终的目标和成果,很简单,一共两页:

    在这里插入图片描述

    (为了让广大程序员也能保护环境和热爱生活,我特意选了 “零垃圾生活” 主题来做 Demo)

    步骤分解

    Demo 代码下载:https://gitee.com/luhuadong/Web_Learning/tree/master/WeChat/GoZeroWaster

    分解目标成果:

    1. 个人中心
    2. 生活指南
    3. 模拟弹窗
    4. 预览图片

    页头页尾

    在目标成果预览中我们看到,两个页面都有共同的部分 —— 页头和页尾。所以在构建页面内容之前,我们先把页头和页尾处理好。我们很容易猜到,这两部分属于小程序的全局配置,因此需要修改 app.json 文件。

    最初的内容如下:

        {
            "pages":[
                "pages/index/index",
                "pages/logs/logs"
            ],
            "window":{
                "backgroundTextStyle": "light",
                "navigationBarBackgroundColor": "#fff",
                "navigationBarTitleText": "WeChat",
                "navigationBarTextStyle": "balack"
            }
        }
    

    pages 属性用来设置页面路径,它是一个数组,每一项都是字符串来指定小程序由哪些页面组成。数组的第一项代表小程序的初始页面。小程序中新增或减少页面,都需要对 pages 数组进行修改。

    window 属性用于设置小程序的状态栏、导航条、标题、窗口背景色。

    我们把页头的标题和颜色修改一下,页尾部分我们做一个 tab 栏来切换页面,这个属性叫做 tabBar,代码如下:

    {
      "pages":[
        "pages/index/index",
        "pages/logs/logs"
      ],
      "window":{
        "backgroundTextStyle":"light",
        "navigationBarBackgroundColor": "#2f2f8f",
        "navigationBarTitleText": "GoZeroWaste",
        "navigationBarTextStyle":"white"
      },
      "tabBar":{
        "color": "#bfc1ab",
        "selectedColor": "#13b11c",
        "backgroundColor": "#1f1f4f",
        "list": [
          {
            "pagePath": "pages/index/index",
            "iconPath": "image/icon_component.png",
            "selectedIconPath": "image/icon_component_HL.png",
            "text": "个人中心"
          },
          {
            "pagePath": "pages/details/details",
            "iconPath": "image/icon_API.png",
            "selectedIconPath": "image/icon_API_HL.png",
            "text": "生活指南"
          }
        ]
      }
    }
    

    (所用到的图片放在项目的 image 目录,你也可以使用自己的图片)

    这里用到几个 tabBar 的属性是 color、selectedColor、backgroundColor 和 list,list 是一个数组,主要用于设定导航的路径。

    CTRL + S 保存之后,模拟器就会自动刷新,马上可以看到效果。

    个人中心

    在这里插入图片描述

    简单起见,我们就在 pages/index 目录下实现 “个人中心” 页面好了。双击打开 index.wxml,初始内容如下:

        <!--index.wxml-->
        <view class="container">
          <view class="userinfo">
            <button wx:if="{{!hasUserInfo && canIUse}}" open-type="getUserInfo" bindgetuserinfo="getUserInfo"> 获取头像昵称 </button>
            <block wx:else>
              <image bindtap="bindViewTap" class="userinfo-avatar" src="{{userInfo.avatarUrl}}" background-size="cover"></image>
              <text class="userinfo-nickname">{{userInfo.nickName}}</text>
            </block>
          </view>
          <view class="usermotto">
            <text class="user-motto">{{motto}}</text>
          </view>
        </view>
    

    这里已经有一些代码了,虽然现在可能还看不懂,但我们知道,这就是现在页面的源代码。我们把 “Hello World” 部分注释掉,增加我们希望显示的内容:

    <!--index.wxml-->
    <view class="container">
      <view class="userinfo">
        <button wx:if="{{!hasUserInfo && canIUse}}" open-type="getUserInfo" bindgetuserinfo="getUserInfo"> 获取头像昵称 </button>
        <block wx:else>
          <image bindtap="bindViewTap" class="userinfo-avatar" src="{{userInfo.avatarUrl}}" background-size="cover"></image>
          <text class="userinfo-nickname">{{userInfo.nickName}}</text>
        </block>
      </view>
       <!-- <view class="usermotto">
        <text class="user-motto">{{motto}}</text>
      </view>  -->
      <view class="ID_Badge">
        <view>
          <text class="ID_info">{{company}}</text>
        </view>
        <view>
          <text class='ID_info'>{{position}}</text>
        </view>
        <view>
          <text class='ID_info'>{{lesson}}</text>
        </view>
      </view>
    </view>
    

    这里分别使用 {{company}}{{position}}{{lesson}} 作为占位符,用法类似于 Django 的模板语言。当然也可以直接用相应的字符来替换它,只不过我们想沿用 {{motto}} 的做法,让你知道在哪里修改这些数据。没错,就是在 index.js 文件:

    Page({
      data: {
        motto: 'Hello World',
        company: "GoZeroWaste",
        lesson: "21天零垃圾生活指南",
        position: "垃圾魔法师",
        /* ... */
      },
    

    wxml 文件中的 <view> 组件类似于网页开发中的 <div>,而 <text> 组件是用来写文本的,需要注意的是 <text/> 组件内只支持 <text/> 嵌套。当然,可用用 <image> 插入图片,图片要保存到 image 目录,否则在测试的时候是无法上传的。

        <view class="ID_Badge">
            <!-- 省略 -->
            <view>
              <text class='ID_info'>{{lesson}}</text>
            </view>
            <view>
              <image class='pic' mode='widthFix' src='../../image/GoZeroWaste.jpg'></image>
            </view>
          </view>
    

    mode=‘widthFix’ 表示以宽度不变,高度自动变化,保持原图宽高比不变的方式进行缩放以适应屏幕大小。

    接下来还需要修改 index.wxss 文件来设置样式:

    /**index.wxss**/
    .userinfo {
      display: flex;
      flex-direction: column;
      align-items: center;
    }
    
    .userinfo-avatar {
      width: 128rpx;
      height: 128rpx;
      margin: 20rpx;
      border-radius: 50%;
    }
    
    .userinfo-nickname {
      color: #aaa;
    }
    
    .usermotto {
      margin-top: 200px;
    }
    
    .ID_Badge {
      padding-top: 20rpx;
      color: blue;
    }
    
    .ID_info {
      display: flex;
      flex-direction: column;
      align-items: center;
    }
    
    .pics {
      width: 400rpx;
    }
    

    保存刷新,“个人中心” 页面就完成了。

    生活指南

    在这里插入图片描述

    原来的项目中 pages 目录下只有 index 和 logs 两个目录,因此我们还需要为第二个页面创建一个目录。

    创建页面有两种方法:

    • 在目录结构的 pages 图表上,新建目录,然后在目录下逐一创建页面构成文件
    • 在 app.json 下,直接添加

    建议采用第二种方法,修改 app.json 文件:

        {
          "pages":[
            "pages/index/index",
            "pages/logs/logs",
            "pages/details/details"
          ],
    

    保存刷新之后就会发现,目录结构里自动创建了这一页。对应的,也要修改 app.json 中的 tabBar 的链接(实际上我们已经做了):

        	{
                "pagePath": "pages/details/details",
                "iconPath": "image/icon_API.png",
                "selectedIconPath": "image/icon_API_HL.png",
                "text": "生活指南"
            }
    

    然后修改 details.wxml 设置这一页的标题:

        <!--pages/details/details.wxml-->
        <view>
          <view class='title'>
            <text>21天零垃圾生活指南</text>
          </view>
        </view>
    

    修改 details.wxss 设置样式:

        /* pages/details/details.wxss */
        .title {
          display: flex;
          flex-direction: column;
          align-items: center;
          margin-top: 40rpx;
          margin-bottom: 40rpx;
          font-size: 40rpx;
        }
    

    这个页面是一个列表展示的页面,我们先在 details.js 文件中准备好数据:

    // pages/details/details.js
    Page({
    
      /**
       * 页面的初始数据
       */
      data: {
        showModalStatus: false,
        list: [
          {
            id: 0,
            name : "写一篇《垃圾日记》",
            introduce: "零垃圾并不是一项宏大的工程,而是由日常生活中一个个小小的习惯和选择组成的。最难的,是迈出第一步。",
            src: '../../image/day01.jpg',
            showModalStatus: false,
            catalog: [
              { section: "1. xxx" },
              { section: "2. xxx" },
              { section: "3. xxx" },
              { section: "4. xxx" },
            ]
          },
          {
            id: 1,
            name: "带上自己的购物袋",
            introduce: "在我们家,当时垃圾桶里最多的就是塑料袋,而这些袋子跟着我回家后,都几乎难逃被丢进垃圾桶的命运。",
            src: '../../image/day02.jpg',
            showModalStatus: false,
            catalog: [
              { section: "1. xxx" },
              { section: "2. xxx" },
              { section: "3. xxx" },
              { section: "4. xxx" },
            ]
          },
          /* 省略 */
        ]
      },
    

    接下来我们要使用列表渲染(wx:for)的方法将这些数据绑定一个数组,并在页面上重复渲染。修改 details.wxml 文件:

          <view>
            <view wx:for="{{list}}" wx:key="id" >
              <view class="lesson" id="{{item.id}}">
                <image class="lessonPic" mode='aspectFit' src="{{item.src}}"></image>
                <view class="lessonName">{{item.name}}</view>
                <view class="lessonIntroduce">{{item.introduce}}</view>
              </view>
            </view>
          </view>
    

    默认数组的当前项的下标变量名默认为 index,数组当前项的变量名默认为 item。

    修改 details.wxss 文件添加样式:

        .lesson {
          height: 190rpx;
          padding-left: 20rpx;
        }
        
        .lessonPic {
          position: absolute;
          height: 150rpx;
          width: 150rpx;
        }
        
        .lessonName {
          position: absolute;
          margin-left: 220rpx;
          font-size: 35rpx;
        }
        
        .lessonIntroduce {
          position: absolute;
          margin-left: 220rpx;
          margin-top: 60rpx;
          margin-right: 20rpx;
          color: rgb(185, 161, 161);
          font-size: 28rpx;
        }
    

    好啦,第二个页面也完成了。

    模拟弹窗

    在这里插入图片描述

    接下来我们要在 “生活指南” 页面模拟一个弹窗的效果,正常的时候不显示,只有在点击的时候才出现,摁下面的 “确定” 就会消失。

    完了实现这个功能,我们要在组件中绑定一个事件处理函数 bindtap,点击该组件的时候,小程序会在该页面对应的 Page 中找到相应的事件处理函数。

    我们先在 details.js 中为每一列数据里引入一个 boolean 变量 showModalStatus 来描述对应的弹窗状态,并且初始值为 false,表示不显示。同时外层也增加一个初始值为 false 的 showModalStatus 变量实现遮罩效果。如下:

           data: {
            showModalStatus: false,
            list: [
              {
                id: 0,
                name : "写一篇《垃圾日记》",
                introduce: "零垃圾并不是一项宏大的工程,而是由日常生活中一个个小小的习惯和选择组成的。最难的,是迈出第一步。",
                src: '../../image/day01.jpg',
                showModalStatus: false,
                catalog: [
                  { section: "1. xxx" },
                  { section: "2. xxx" },
                  { section: "3. xxx" },
                  { section: "4. xxx" },
                ]
              },
    

    然后在 details.wxml 中插入弹窗,并用条件渲染(wx:if)来判断是否渲染(显示)弹窗。同时为每一个 item 添加 data-statu 来表示弹窗的状态。如下:

      <view>
        <view wx:for="{{list}}" wx:key="id" >
          <view class="lesson" bindtap='powerDrawer' data-statu='open' id="{{item.id}}">
            <image class="lessonPic" mode='aspectFit' src="{{item.src}}"></image>
            <view class="lessonName">{{item.name}}</view>
            <view class="lessonIntroduce">{{item.introduce}}</view>
          </view>
            
          <!-- 弹窗 -->
          <view class='drawer_box' wx:if='{{item.showModalStatus}}' id='{{item.id}}'>
            <view class="title">{{item.name}}</view>
            <view class='drawer_content'>
              <view class='title' wx:for='{{item.catalog}}' wx:for-item='catalog' wx:key='id'>
                {{catalog.section}}
              </view>
            </view>
            <!-- 确定按钮 -->
            <view class='btn_ok' bindtap='powerDrawer' data-statu='close' id='{{item.id}}'>确定</view>
          </view>
        </view>
          
        <!-- 遮罩层 -->
        <view class='drawer_screen' data-statu='close' wx:if='{{showModalStatus}}'></view>
      </view>
    

    在 details.js 添加 powerDrawer 事件处理,包括显示和关闭事件:

          powerDrawer: function (e) {
            console.log("clicked");
        
            var currentStatu = e.currentTarget.dataset.statu;
            var index = e.currentTarget.id;
        
            // 关闭
            if (currentStatu == 'close') {
              this.data.list[index].showModalStatus = false;
              this.setData({
                showModalStatus: false,
                list: this.data.list,
              });
            }
        
            // 显示
            if (currentStatu == 'open') {
              this.data.list[index].showModalStatus = true;
              this.setData({
                showModalStatus: true,
                list: this.data.list,
              });
            }
          },
    

    最后在 details.wxss 设置一下弹窗和遮罩层的样式:

        .drawer_box {
          width: 650rpx;
          overflow: hidden;
          position: fixed;
          top: 50%;
          z-index: 1001;
          background: #FAFAFA;
          margin: -150px 50rpx 0 50rpx;
        }
        
        .drawer_content {
          border-top: 1.5px solid #E8E8EA;
          height: 210px;
          overflow-y: scroll; /* 超出父盒子高度可滚动 */
        }
        
        .btn_ok {
          padding: 10px;
          font: 20px "microsoft yahei";
          text-align: center;
          border-top: 1.5px solid #E8E8EA;
          color: #3CC51F;
        }
        
        .drawer_screen {
          width: 100%;
          height: 100%;
          position: fixed;
          top: 0;
          left: 0;
          z-index: 1000;
          background: black;
          opacity: 0.5;
          overflow: hidden;
        }
    

    OK,模拟弹窗也实现了。

    预览图片

    在这里插入图片描述

    最后一步就是在第一个页面实现图片预览和图片保存的功能,在 index.wxml 中为图片添加一个点击事件 previewImage。

        <image class='pic' mode='widthFix' src='../../image/GoZeroWaste.jpg' bindtap='previewImage'></image>
    

    在 index.js 中添加 imgalist 项(我们直接把公众号的二维码图片上传到 CSDN 的图片服务器了),并且实现 previewImage 事件处理。如下:

        Page({
          data: {
            motto: 'Hello World',
            company: "GoZeroWaste",
            lesson: "21天零垃圾生活指南",
            position: "垃圾魔法师",
            imgalist: ['https://img-blog.csdnimg.cn/20190109104518898.jpg'],
            userInfo: {},
            hasUserInfo: false,
            canIUse: wx.canIUse('button.open-type.getUserInfo')
          },
          previewImage: function (e) {
            wx.previewImage({
              current: this.data.imgalist,  // 当前显示图片的http链接
              urls: this.data.imgalist      // 需要预览的图片http链接列表
            })
          },
    

    大功告成,点击开发者工具中的 “预览”,使用微信扫描生成的二维码即可在手机端查看。

    教程就到这里囖,再见吧~

    在这里插入图片描述

    展开全文
  • 我作为一个普通的Android程序员,由于需求原因被公司安排做小程序开发了,前前后后研究小程序也有两个月左右了,也完成了公司的一个小工具,算是入门了。前面我也在公众号发布过小程序的学习文章。 接下来我将计划...
  • 在我转产品之前,虽然我混迹IT行业,做过实施和售前,也跟研发打过交道,但我一直都不知道一个软件是怎么开发出来的。直面客户,扛着压力,在对程序一无所知的情况下,很容易产生一些想法:为什么产品的结果是这样?...
  • 小程序依托微信超过 10 亿的海量用户,它无需安装即可使用的完美用户体验,已经成为商家竞相争夺的大蛋糕,同时,小程序开发快速、容易部署广受程序员的喜爱,作为程序员的我们,还有什么理由不学习小程序开发呢?...
  • 程序开发入门教程

    2018-05-30 10:06:09
    程序本质上是一套Hybrid开发框架,因此从技术上看,小程序属于旧瓶装新酒。但是依托于微信这个超级平台,在配合线下无数的轻量使用场景,小程序推出的时机恰到好处。从技术实现的角度看,小程序是融合原生和WEB...
  • 微信小程序开发实战

    2019-04-01 14:05:00
    本套课程使用了元认知教学法,直接实战式教学,摆脱学院派的理论式讲解,对于0基础的学员可以入门编写微信小程序,过程中指导如何学习使用文档查阅接口等,通过两个完整的实战小项目的实例,入手小程序开发
  • “微信小程序开发教程​”以腾讯官方资料为主,系统讲解微信小程序开发的相关的知识点。 全套课程共3篇 微信小程序实战教程(第1篇)——讲解小程序基础知识点,重点讲解小程序开发工具,视图层(View)和逻辑层(App ...
  • 微信小程序可谓是今天最火的一个名词了,一经出现真是轰炸了整个开发人员,当然很多App开发人员有了一个担心,...不排斥新技术,所以,心动不如行动,赶紧先搭建一个微信小程序开发工具。那么接下来就让我们一起来开始
  • 做任何程序开发要首先找到其官方文档,我们先来看看其有哪些官方文档。 微信小程序开发文档链接为:https://mp.weixin.qq.com/debug/wxadoc/dev/index.html,如下图: 这里就是做微信小程序开发的全部官方文档。...
  • 实际上,微信和腾讯云同是腾讯产品,已经提供了10分钟(根据准备资源情况,已完成小程序申请认证)完成小程序开发、部署、发布的方式。当然,实现的是基础功能。但是,可以给学习者很便捷的体验和很好的启发。 不过...
  • 目标是从 0 开始带领读者上手实战,课程以微信小程序的核心概念作为主线,介绍配置文件、页面样式文件、JavaScript 的基本知识并以指南针为例对基本知识进行扩展,另外加上开发工具的安装、小程序发布等内容,...
  • 大家想到使用Java这门编程语言大多是脑海中是浮现的B/S开发,高并发、云计算、大数据等等,今天给大家带来的是Java不一样的使用方式——使用Java做PC桌面程序开发。 不同的是,之前Java是使用swing或者awt开发,...
1 2 3 4 5 ... 20
收藏数 2,934,607
精华内容 1,173,842
热门标签
关键字:

程序开发