小程序和Vue+uniapp+unicloud培训课件

news2024/9/25 11:15:59

文章目录

  • **一、什么是小程序**
    • **1.1** **小程序简介**
    • **1.2** **小程序的特点**
    • **1.3** **小程序的开发流程**
      • 个人小程序和企业小程序的区别
    • 1.4 小程序代码构成
      • 1.4.1 JSON 配置
      • 1.4.2 WXML 模板
        • **数据绑定**
        • 逻辑语法
        • 条件逻辑
        • 列表渲染
        • 模板
        • 引用
        • 共同属性
      • 1.4.3 WXSS 样式
      • 1.4.4 JS 逻辑交互
        • 模块化
    • 1.5 小程序宿主环境
      • 1.5.1 渲染层和逻辑层
      • 1.5.2 程序与页面
      • 1.5.3 组件
      • 1.5.4 API
  • 二、Vue简介
    • **2.1 Vue**的定义
    • 2.2 Vue的特点
    • **2.3 Vue**的使用
    • 2.4 MVVM软件架构模式
  • 三、uniapp
    • 3.1 什么是uni-app?
    • 3.2 快速上手
      • 3.2.1 创建uni-app
      • 3.2.2 uni-app工程目录结构
      • 3.2.3 页面简介
        • 新建页面
        • 删除页面
        • 应用首页
        • 页面生命周期
        • 组件生命周期
        • 路由
        • 路由跳转
        • 页面栈
        • 相互引用
      • 3.2.4 运行uni-app
      • 3.2.5 发布uni-app
        • 打包为原生App
        • 发布为Web网站
        • 发布为微信小程序
  • 四、 unicloud
    • 4.1uniCloud是什么和不是什么
    • 4.2 什么是serverless?
    • 4.3 基本概念
      • 4.3.1服务空间
      • 4.3.2云数据库
      • 4.3.3云函数/云对象
    • 4.4 快速上手
      • 4.4.1 创建uniCloud项目
      • 4.4.2 关联服务空间
      • 4.4.3 创建云函数/云对象
  • 五、 项目案例
    • 4.4 快速上手
      • 4.4.1 创建uniCloud项目
      • 4.4.2 关联服务空间
      • 4.4.3 创建云函数/云对象
  • 五、 项目案例

一、什么是小程序

1.1 小程序简介

小程序是一种新型的应用程序,它是运行在移动设备上的应用程序,用户可以在不下载和安装应用的情况下直接使用。

1.2 小程序的特点

  • 快速启动:小程序无需下载和安装,用户可以直接通过扫码或搜索进入小程序。
  • 轻量级:小程序的体积相对较小,不会占用太多存储空间,可以随时随地使用。
  • 原生体验:小程序采用原生技术开发,可以提供更加流畅的用户体验。
  • 易于分享:小程序可以通过二维码、微信分享等方式进行传播,可以快速扩大影响力。

1.3 小程序的开发流程

小程序的开发流程主要包括以下几个步骤:

  • 注册小程序账号:注册小程序账号,获取小程序开发资格。 开发小程序的第一步,需要拥有一个小程序 AppID,后续的所有开发流程会基于这个 AppID 来完成。小程序的注册非常简单,只需几个操作。

    使用浏览器打开 https://mp.weixin.qq.com/ 点击立即注册

个人小程序和企业小程序的区别

一,注册时的区别:
个人版的注册需要的“资质”极少,几乎只要个人的身份信息就可以。注册流程简化许多。

企业版的注册则繁琐许多,需要提供管理者的身份信息的同时,企业的各项资质、对公账号、企业验证等等,要提供一系列的证明和验证。

个人版的注册时不需要收取300元的 认证费用的(因为个人版暂时不支持 认证)

企业版的 认证就需要收取300元

二,开发的小程序性质不同:
接口限制

个人主体的小程序肯定是无法完整地使用小程序的接口和能力的,具体哪些接口用不了呢?

  1. 微信支付

如需使用微信支付,就必须先开通微信支付商户账号,而开通商户号必须是具备企业资格,个人资质无法开通商户账号。

如小程序需要接入微信支付,小程序本身必须要经过微信认证才行,而个人主体注册的小程序是不支持认证的。

所以,这是一个限制:个人主体注册的小程序不能使用微信支付!

  1. 卡券

在微信里,卡券的分类众多,其中就包含了具有储值功能会员卡,像这种会员卡涉及到用户财产安全的接口肯定会受到严格的监管,而个人主体注册的小程序风险大,微信自然不能让你使用。

  1. 获取微信用户绑定的手机号码

微信在近期更新中,开放了快速填写手机号,直接获取用户微信绑定的手机号码功能。

但目前这个接口仅开放给已通过微信认证的小程序使用;尚未认证的组织类小程序和个人主体小程序,都无法使用这个功能。

4.个人版附近小程序是没办法显示

附近小程序是根据营业执照注册地址定位的。

三,企业高级接口
接口一:OAuth2.0网页授权、获取用户基本信息

这两个接口是此次开放对于微网站类应用最重要的技术保证,在OAuth2.0接口的支援下,可做到真正的微信用户状态保持、信息拉取(昵称、性别、 地区 等),可真正实现微网站用户免注册。该接口目前唯一的不爽是只 能在微信环境内使用,但是相信随着微信开放程度加强、同类竞争对手的进入,该接口应该会更加开放。不过,仅仅目前的开放程度,已经足够我们把微网站做得更 好。

接口二:客服接口

该接口是简化版的“消息下发接口”,曾今也是第三方开发公司梦寐以求的接口之一,其基本应用原理是当用户主动发送一条信息给公众平台后,公众平台可 在24小时内,无限的向该用户推送消息。此接口最重要的产品应用就是可以开发类似QQ或旺旺一样的微信客服系统。另外,也为自动回复机器人的应用,也带来 了更多的想象空间。

接口三:生成带参数二维码

该接口可以实现大家一直期盼的扫码场景:

场景一:以微信生意宝的客户“Logitech/罗技”为例,罗技公司在全国有N多家代理门店,利用该接口,罗技公司可以对不同的门店设置不同的微信二维码,这样就可以判断出粉丝是在哪家门店扫码关注的了,这也是运营人员的福音。

场景二:例如公司官网上有多个活动,都在通过二维码推广公众平台,如何统计出哪个活动带来的新粉丝最多?利用这个接口,这个问题也就不是问题咯~~

所以,此接口必将成为一个微信推广利器,不过,腾讯目前对这个接口稍作了限制,目前微信最多只支持生成1000个永久参数的二维码,但是可以无限制生成带临时参数的二维码(临时参数有效期30分钟)。

接口四:获取用户地理位置

O2O服务最具有科技感的服务形式,就是基于位置提供不同的服务、给用户提供不同的信息,该接口区别于目前微信聊天窗口中发送地理位置的功能,最大 的区别的是,该接口是以事件的形式自动上报给公众平台的,用户无法作假,也无须操作(当然,一开始需要用户授权同意)。该接口开放后可以给其他接口服务提 供前 置参数,由此可实现很多基于地理位置的组合应用,例如:实现景点微信导游,当用户走到不同的地方,发送个“导游”两个字给公众平台,系统将自动推送给用户 当前的景点信息,如果这个功能和客服系统对接,就可自动实现按照客户目前所在的区域自动分流。

接口五:获取关注者列表、用户分组接口

这两个接口可以配合获取用户基本信息接口,让微信用户可以脱离微信后台,直接在微网站后台进行客户的维护与管理,使得微网站后台更加实用高效。

接口六:语音识别

应该说这个接口是腾讯为我们提供的下酒小菜,如果合理应用,可做出更多有意思的应用和游戏。他的基本流程是这样的:用户向聊天窗口发送语音信息,微 信会把识别的文字结果也反馈给微信生意宝系统,这样就等同于发送了文字消息。比如,以后用户想要回复微网站的首页,除了可以输入文字“首页”或图标外,用 户也可以对着手机大喊一声“芝麻开门”,也能出现微网站首页。

以上是微信新开放的接口简单说明,除了这些高级接口,其实还有一些我们现在已经在使用的操作微信的客户端的脚本接口,正式开放,例如:隐藏微信中网页右 上角按钮,隐藏微信中网页底部导航栏等,另外网页获取用户网络状态的接口,对于微网站应用还是比较重要的,我们可以识别用户当前使用的是wifi还是3g 网络,以便决定信息怎么展示,帮助用户省流量、省钱。另外,对于HTML5应用,该状态的获取,可充分发掘HTML5本地应用程序的威力。

  • 开发小程序:使用小程序开发工具进行开发,包括界面设计、数据管理、业务逻辑等方面。安装开发者工具

    在小程序开发文档中找到小程序开发工具的下载页面,或者直接输入 https://mp.weixin.qq.com/debug/wxadoc/dev/devtools/download.html 根据自己的操作系统下载对应的安装包进行安装。需要注意的是,小程序开发工具在 Windows上仅支持 Windows 7 及以上版

  • 提交审核:将开发完成的小程序提交到微信小程序平台进行审核。

  • 发布上线:审核通过后,可以将小程序发布上线,供用户使用。

1.4 小程序代码构成

  • .json 后缀的 JSON 配置文件

  • .wxml 后缀的 WXML 模板文件

  • .wxss 后缀的 WXSS 样式文件

  • .js 后缀的 JS 脚本逻辑文件

1.4.1 JSON 配置

JSON 是一种数据格式,并不是编程语言,在小程序中,JSON扮演的静态配置的角色。

相比于XML ,JSON格式最大的优点是易于人的阅读和编写,通常不需要特殊的工具,就能读懂和修改,是一种轻量级的数据交换格式。

JSON文件都是被包裹在一个大括号中 {},通过key-value的方式来表达数据。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FJb8ieRb-1677491373212)(C:\Users\Administrator\AppData\Local\Temp\1677412175702.png)]

JSON的Key必须包裹在一个双引号中,在实践中,编写 JSON 的时候,忘了给 Key 值加双引号或者是把双引号写成单引号是常见错误。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-l63RH5IN-1677491373220)(C:\Users\Administrator\AppData\Local\Temp\1677412214164.png)]

JSON的值只能是以下几种数据格式:

  1. 数字,包含浮点数和整数
  2. 字符串,需要包裹在双引号中
  3. Bool值,true 或者 false
  4. 数组,需要包裹在方括号中 []
  5. 对象,需要包裹在大括号中 {}
  6. Null

其他任何格式都会触发报错,例如 JavaScript 中的 undefined 。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UtsiaAEK-1677491373223)(C:\Users\Administrator\AppData\Local\Temp\1677412273203.png)]

还需要注意的是 JSON 文件中无法使用注释,试图添加注释将会引发报错。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EtXIQAoO-1677491373225)(C:\Users\Administrator\AppData\Local\Temp\1677412317671.png)]

1.4.2 WXML 模板

WXML 全称是 WeiXin Markup Language,是小程序框架设计的一套标签语言,结合小程序的基础组件、事件系统,可以构建出页面的结构。

从事过网页编程的人知道,网页编程采用的是 HTML + CSS + JS 这样的组合,其中 HTML 是用来描述当前这个页面的结构,CSS 用来描述页面的样子,JS 通常是用来处理这个页面和用户的交互。

同样道理,在小程序中也有同样的角色,其中 WXML 充当的就是类似 HTML 的角色。

一个完整的 WXML语句由一段开始标签和一段结束标签组成,在标签中可以是内容,也可以是其他的 WXML 语句,这一点上同 HTML 是一致的。有所不同的是,WXML 要求标签必须是严格闭合的,没有闭合将会导致编译错误。

标签可以拥有属性,属性提供了有关的 WXML元素更多信息。属性总是定义在开始标签中,除了一些特殊的属性外,其余属性的格式都是key=“value” 的方式成对出现。需要注意的是,WXML中的属性是大小写敏感的,也就是说 class 和 Class 在WXML中是不同的属性,代码2-3是一个文本标签的示例。

数据绑定

用户界面呈现会因为当前时刻数据不同而有所不同,或者是因为用户的操作发生动态改变,这就要求程序的运行过程中,要有动态的去改变渲染界面的能力。在 Web 开发中,开发者使用 JavaScript 通过Dom 接口来完成界面的实时更新。在小程序中,使用 WXML 语言所提供的数据绑定功能,来完成此项功能。

先看一个简单的例子。

数据绑定示例

<!--pages/wxml/index.wxml-->
<text>当前时间:{{time}}</text>

保存后工具刷新,模拟器并没有显示出当前的时间,这是因为我们并没有给 time 设置任何初始值,请打开 index.js 文件,在 data 的大括号中加入:time: (new Date()).toString()

数据绑定示例

// pages/wxml/index.js
Page({
  /**
   * 页面的初始数据
   */
  data: {
    time: (new Date()).toString()
  },
})

保存,模拟器刷新后正确的展示了当前时间,并且每次编译时间都会被更新。

WXML 通过 {{变量名}} 来绑定 WXML 文件和对应的 JavaScript 文件中的 data 对象属性。

后文中为了保持简单,通过以下格式来展示上述的代码逻辑,使用第一段注释来表明 WXML 对应的脚本文件中的 data 结构。

<!--
{
  time: (new Date()).toString()
}
-->
<text>当前时间:{{time}}</text>

属性值也可以动态的去改变,有所不同的是,属性值必须被包裹在双引号中,如下:

属性值的绑定

<!-- 正确的写法 -->
<text data-test="{{test}}"> hello world</text>


<!-- 错误的写法  -->
<text data-test={{test}}> hello world </text >

需要注意的是变量名是大小写敏感的,也就是说 {{name}} 和 {{Name}} 是两个不同的变量。

代码清单2-9 绑定的变量大小写敏感

<!--
{
  w: 'w',
  W: 'W'
}
-->


<view>{{w}}</view>
<view>{{W}}</view>


<!-- 输出
w
W
-->

还需要注意,没有被定义的变量的或者是被设置为 undefined 的变量不会被同步到 wxml 中,如代码2-10所示。

代码清单2-10 undefined值不会被输出到 wxml 中

<!--
{
  var2: undefined,
  var3: null,
  var4: "var4"
}
-->


<view>{{var1}}</view>
<view>{{var2}}</view>
<view>{{var3}}</view>
<view>{{var4}}</view>


<!--
输出:
null
var4
-->

逻辑语法

通过 {{ 变量名 }} 语法可以使得 WXML 拥有动态渲染的能力,除此外还可以在 {{ }} 内进行简单的逻辑运算。

三元运算:

<!-- 根据 a 的值是否等于 10 在页面输出不同的内容 -->
<text>{{ a === 10? "变量 a 等于10": "变量 a 不等于10"}}</text>

算数运算:

<!--
{ a: 1,  b: 2, c: 3 }
-->


<view> {{a + b}} + {{c}} + d </view>


<!-- 输出 3 + 3 + d -->

类似于算数运算,还支持字符串的拼接,如代码2-11所示。

字符串的拼接

<!--
{ name: 'world' }
-->


<view>{{"hello " + name}}</view>


<!-- 输出 hello world -->

{{ }}中还可以直接放置数字、字符串或者是数组

常量

<text>{{[1,2,3]}}</text>

<!-- 输出 1,2,3 -->



<text>{{"hello world"}}</text>

<!-- 输出 hello world -->

条件逻辑

WXML 中,使用 wx:if=“{{condition}}” 来判断是否需要渲染该代码块:

<view wx:if="{{condition}}"> True </view>

使用 wx:elif 和 wx:else 来添加一个 else 块:

<view wx:if="{{length > 5}}"> 1 </view>
<view wx:elif="{{length > 2}}"> 2 </view>
<view wx:else> 3 </view>

因为 wx:if 是一个控制属性,需要将它添加到一个标签上。如果要一次性判断多个组件标签,可以使用一个 <block/> 标签将多个组件包装起来,并在上边使用 wx:if 控制属性。

<block wx:if="{{true}}">
  <view> view1 </view>
  <view> view2 </view>
</block>

列表渲染

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

列表渲染示例

<!-- array 是一个数组 -->
<view wx:for="{{array}}">
  {{index}}: {{item.message}}
</view>

<!-- 对应的脚本文件
Page({
  data: {
    array: [{
      message: 'foo',
    }, {
      message: 'bar'
    }]
  }
})
-->

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

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

类似 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 的值以两种形式提供:

  1. 字符串,代表在 for 循环的 array 中 item 的某个 property,该 property 的值需要是列表中唯一的字符串或数字,且不能动态改变。
  2. 保留关键字 this 代表在 for 循环中的 item 本身,这种表示需要 item 本身是一个唯一的字符串或者数字,如:

当数据改变触发渲染层重新渲染的时候,会校正带有 key 的组件,框架会确保他们被重新排序,而不是重新创建,以确保使组件保持自身的状态,并且提高列表渲染时的效率。

使用 wx:key 示例(WXML)

<switch wx:for="{{objectArray}}" wx:key="unique" > {{item.id}} </switch>
<button bindtap="switch"> Switch </button>
<button bindtap="addToFront"> Add to the front </button>


<switch wx:for="{{numberArray}}" wx:key="*this" > {{item}} </switch>
<button bindtap="addNumberToFront"> Add Number to the front </button>

使用 wx:key 示例(JavaScript)

Page({
  data: {
    objectArray: [
      {id: 5, unique: 'unique_5'},
      {id: 4, unique: 'unique_4'},
      {id: 3, unique: 'unique_3'},
      {id: 2, unique: 'unique_2'},
      {id: 1, unique: 'unique_1'},
      {id: 0, unique: 'unique_0'},
    ],
    numberArray: [1, 2, 3, 4]
  },
  switch: function(e) {
    const length = this.data.objectArray.length
    for (let i = 0; i < length; ++i) {
      const x = Math.floor(Math.random() * length)
      const y = Math.floor(Math.random() * length)
      const temp = this.data.objectArray[x]
      this.data.objectArray[x] = this.data.objectArray[y]
      this.data.objectArray[y] = temp
    }
    this.setData({
      objectArray: this.data.objectArray
    })
  },
  addToFront: function(e) {
    const length = this.data.objectArray.length
    this.data.objectArray = [{id: length, unique: 'unique_' + length}].concat(this.data.objectArray)
    this.setData({
      objectArray: this.data.objectArray
    })
  },
  addNumberToFront: function(e){
    this.data.numberArray = [ this.data.numberArray.length + 1 ].concat(this.data.numberArray)
    this.setData({
      numberArray: this.data.numberArray
    })
  }
})

模板

WXML提供模板(template),可以在模板中定义代码片段,然后在不同的地方调用。使用 name 属性,作为模板的名字。然后在 <template/> 内定义代码片段,如:

定义模板

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

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

模板使用示例

<!--
item: {
  index: 0,
  msg: 'this is a template',
  time: '2016-06-18'
}
-->


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


<template is="msgItem" data="{{...item}}"/>

<!-- 输出
0: this is a template Time: 2016-06-18
-->

is可以动态决定具体需要渲染哪个模板。

动态使用模板

<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>



<!-- 输出
odd
even
odd
even
odd
-->

引用

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,简言之就是 import 不具有递归的特性。

例如:C 引用 B,B 引用A,在C中可以使用B定义的 template,在B中可以使用A定义的 template ,但是C不能使用A定义的template.

模板 A

<!-- A.wxml -->
<template name="A">
  <text> A template </text>
</template>

模板 B

<!-- B.wxml -->
<import src="a.wxml"/>

<template name="B">
  <text> B template </text>
</template>

模板 C

<!-- C.wxml -->
<import src="b.wxml"/>

<template is="A"/>  <!-- 这里将会触发一个警告,因为 b 中并没有定义模板 A -->

<template is="B"/>

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

index.wxml

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

<view> body </view>

<include src="footer.wxml"/>

header.wxml

<!-- header.wxml -->
<view> header </view>

footer.wxml

<!-- footer.wxml -->
<view> footer </view>

共同属性

所有wxml 标签都支持的属性称之为共同属性,如表2-1所示。

共同属性

属性名类型描述注解
idString组件的唯一标识整个页面唯一
classString组件的样式类在对应的 WXSS 中定义的样式类
styleString组件的内联样式可以动态设置的内联样式
hiddenBoolean组件是否显示所有组件默认显示
data-*Any自定义属性组件上触发的事件时,会发送给事件处理函数
bind*/catch*EventHandler组件的事件

1.4.3 WXSS 样式

WXSS(WeiXin Style Sheets)是一套用于小程序的样式语言,用于描述WXML的组件样式,也就是视觉上的效果。

WXSS与Web开发中的CSS类似。为了更适合小程序开发,WXSS对CSS做了一些补充以及修改。WXSS 具有 CSS 大部分的特性,小程序在 WXSS 也做了一些扩充和修改。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CUad84qt-1677491373233)(C:\Users\Administrator\AppData\Local\Temp\1677414122175.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Yegl56EG-1677491373236)(C:\Users\Administrator\AppData\Local\Temp\1677414145584.png)]

项目公共样式:根目录中的app.wxss为项目公共样式,它会被注入到小程序的每个页面。页面样式:与app.json注册过的页面同名且位置同级的WXSS文件。 app.json注册了pages/rpx/index页面,那pages/rpx/index.wxss为页面pages/rpx/index.wxml的样式。

其它样式:其它样式可以被项目公共样式和页面样式引用。

在小程序开发中,开发者不需要像Web开发那样去优化样式文件的请求数量,只需要考虑代码的组织即可。

  1. 新增了尺寸单位。在写 CSS 样式时,开发者需要考虑到手机设备的屏幕会有不同的宽度和设备像素比,采用一些技巧来换算一些像素单位。WXSS 在底层支持新的尺寸单位 rpx ,开发者可以免去换算的烦恼,只要交给小程序底层来换算即可,由于换算采用的浮点数运算,所以运算结果会和预期结果有一点点偏差。
  2. 提供了全局的样式和局部样式。和前边 app.json, page.json 的概念相同,你可以写一个 app.wxss 作为全局样式,会作用于当前小程序的所有页面,局部页面样式 page.wxss 仅对当前页面生效。在CSS中,开发者可以这样引用另一个样式文件:@import url('./test_0.css')
  3. 此外 WXSS 仅支持部分 CSS 选择器

WXSS内联样式与Web开发一致:

<!--index.wxml-->

<!--内联样式-->
<view style="color: red; font-size: 48rpx"></view>

小程序支持动态更新内联样式:

<!--index.wxml-->

<!--可动态变化的内联样式-->
<!--
{
  eleColor: 'red',
  eleFontsize: '48rpx'
}
-->
<view style="color: {{eleColor}}; font-size: {{eleFontsize}}"></view>

1.4.4 JS 逻辑交互

一个服务仅仅只有界面展示是不够的,还需要和用户做交互:响应用户的点击、获取用户的位置等等。在小程序里边,我们就通过编写 JS 脚本文件来处理用户的操作。

模块化

浏览器中,所有 JavaScript 是在运行在同一个作用域下的,定义的参数或者方法可以被后续加载的脚本访问或者改写。同浏览器不同,小程序中可以将任何一个JavaScript 文件作为一个模块,通过module.exports 或者 exports 对外暴露接口。

请看是一个简单模块示例,B.js 引用模块A,并使用A暴露的multiplyBy2方法完成一个变量乘以 2 的操作。

模块示例

// moduleA.js
module.exports = function( value ){
  return value * 2;
}

引用模块A

// B.js

// 在B.js中引用模块A
var multiplyBy2 = require('./moduleA')
var result = multiplyBy2(4)

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

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

1.5 小程序宿主环境

我们称微信客户端给小程序所提供的环境为宿主环境。小程序借助宿主环境提供的能力,可以完成许多普通网页无法完成的功能。

1.5.1 渲染层和逻辑层

首先,我们来简单了解下小程序的运行环境。小程序的运行环境分成渲染层和逻辑层,其中 WXML 模板和 WXSS 样式工作在渲染层,JS 脚本工作在逻辑层。

小程序的渲染层和逻辑层分别由2个线程管理:渲染层的界面使用了WebView 进行渲染;逻辑层采用 JsCore 线程运行 JS 脚本。一个小程序存在多个界面,所以渲染层存在多个 WebView 线程,这两个线程的通信会经由微信客户端(下文中也会采用 Native 来代指微信客户端)做中转,逻辑层发送网络请求也经由 Native 转发,小程序的通信模型下图所示。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uVmAbRHX-1677491373238)(C:\Users\Administrator\AppData\Local\Temp\1677409947621.png)]

1.5.2 程序与页面

微信客户端在打开小程序之前,会把整个小程序的代码包下载到本地。

紧接着通过 app.jsonpages 字段就可以知道你当前小程序的所有页面路径:

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

这个配置说明在 QuickStart 项目定义了两个页面,分别位于 pages/index/indexpages/logs/logs。而写在 pages 字段的第一个页面就是这个小程序的首页(打开小程序看到的第一个页面)。

于是微信客户端就把首页的代码装载进来,通过小程序底层的一些机制,就可以渲染出这个首页。

小程序启动之后,在 app.js 定义的 App 实例的 onLaunch 回调会被执行:

App({
  onLaunch: function () {
    // 小程序启动之后 触发
  }
})

整个小程序只有一个 App 实例,是全部页面共享的。

接下来我们简单看看小程序的一个页面是怎么写的。

你可以观察到 pages/logs/logs 下其实是包括了4种文件的,微信客户端会先根据 logs.json 配置生成一个界面,顶部的颜色和文字你都可以在这个 json 文件里边定义好。紧接着客户端就会装载这个页面的 WXML 结构和 WXSS 样式。最后客户端会装载 logs.js,你可以看到 logs.js 的大体内容就是:

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

Page 是一个页面构造器,这个构造器就生成了一个页面。在生成页面的时候,小程序框架会把 data 数据和 index.wxml 一起渲染出最终的结构,于是就得到了你看到的小程序的样子。

在渲染完界面之后,页面实例就会收到一个 onLoad 的回调,你可以在这个回调处理你的逻辑。

1.5.3 组件

小程序提供了丰富的基础组件给开发者,开发者可以像搭积木一样,组合各种组件拼合成自己的小程序。

就像 HTMLdiv, p 等标签一样,在小程序里边,你只需要在 WXML 写上对应的组件标签名字就可以把该组件显示在界面上,例如,你需要在界面上显示地图,你只需要这样写即可:

<map></map>

使用组件的时候,还可以通过属性传递值给组件,让组件可以以不同的状态去展现,例如,我们希望地图一开始的中心的经纬度是广州,那么你需要声明地图的 longitude(中心经度) 和 latitude(中心纬度)两个属性:

<map longitude="广州经度" latitude="广州纬度"></map>

组件的内部行为也会通过事件的形式让开发者可以感知,例如用户点击了地图上的某个标记,你可以在 js 编写 markertap 函数来处理:

<map bindmarkertap="markertap" longitude="广州经度" latitude="广州纬度"></map>

当然你也可以通过 style 或者 class 来控制组件的外层样式,以便适应你的界面宽度高度等等。

1.5.4 API

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

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

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

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

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

需要注意的是:多数 API 的回调都是异步,你需要处理好代码逻辑的异步问题

二、Vue简介

2.1 Vue的定义

Vue是一种前端JavaScript框架,它是一种轻量级的MVVM框架,可以用于构建Web界面。

2.2 Vue的特点

  • 易于上手:Vue具有简单易学的特点,可以快速上手。

  • 灵活性高:Vue的组件化设计,可以方便地组合和重用组件。

  • 性能优秀:Vue采用虚拟DOM技术,可以提高渲染效率,减少页面渲染时间。

  • 支持插件化:Vue可以轻松地集成第三方插件,扩展其功能。

2.3 Vue的使用

Vue的使用主要包括以下几个方面:

  • 数据绑定:Vue通过数据绑定实现视图与数据的同步更新。
  • 组件化:Vue将应用程序划分为一个个组件,便于开发和维护。
  • 路由管理:Vue提供了Vue Router插件,可以轻松管理应用程序的路由。
  • 状态管理:Vue提供了Vuex插件,可以方便地管理应用程序的状态。

2.4 MVVM软件架构模式

MVVM是一种软件架构模式,它由三个核心部分组成:Model(模型)、View(视图)和ViewModel(视图模型)。这种模式通常用于开发用户界面,它的目的是将应用程序的逻辑和用户界面分离开来,从而提高代码的可维护性和可扩展性。

下面是MVVM架构中各个部分的详细说明:

Model

Model是应用程序中数据的存储和管理部分。它通常包括数据结构、数据库、网络通信等。在MVVM中,Model用于表示应用程序的业务逻辑和数据。

View

View是应用程序中用户界面的展示部分。它通常包括UI控件、视图元素、动画等。在MVVM中,View是与用户交互的部分,它负责将ViewModel中的数据呈现给用户,并接受用户输入的操作。

ViewModel

ViewModel是连接View和Model之间的桥梁。它主要包括数据绑定、命令绑定、事件处理等功能。在MVVM中,ViewModel用于将Model中的数据映射到View中,并且在View中的操作反映到Model中。

MVVM架构中最重要的一部分是数据绑定。数据绑定是指将View中的控件与ViewModel中的属性绑定在一起,当ViewModel中的属性值发生变化时,View中的控件会自动更新。同样地,当用户在View中进行操作时,ViewModel中的属性也会相应地进行更新。

MVVM架构的优点包括:

  • 提高代码的可维护性和可扩展性:MVVM将应用程序的逻辑和用户界面分离开来,从而使得代码更易于维护和扩展。
  • 提高开发效率:MVVM中的数据绑定和命令绑定可以自动完成,减少了重复代码的编写,提高了开发效率。
  • 提高测试效率:由于MVVM中的View和ViewModel之间的依赖关系松散,因此可以更方便地对ViewModel进行单元测试。

总的来说,MVVM是一种强大的软件架构模式,它在现代Web开发中被广泛应用,例如Vue.js和AngularJS等框架都采用了MVVM架构。

当我们使用MVVM框架时,通常会采用以下设计模式:

数据绑定

MVVM的核心概念之一是数据绑定。数据绑定是指将视图(View)和模型(Model)之间的数据同步更新的机制。通常采用单向绑定和双向绑定。

  • 单向绑定:视图只能读取模型的数据,无法更改。当模型的数据发生变化时,视图会自动更新。
  • 双向绑定:视图可以读取并更改模型的数据,当视图中的数据发生变化时,模型的数据也会随之更新。

命令绑定

命令绑定是MVVM框架中的另一个重要概念。命令绑定是指将视图中的事件和ViewModel中的命令绑定在一起,从而实现对视图事件的响应。

在传统的MVC框架中,通常会将事件的处理代码写在Controller中,而在MVVM框架中,我们将这些处理代码封装在ViewModel中,通过命令绑定来实现事件处理。

ViewModel

在MVVM框架中,ViewModel负责将Model中的数据转换为View中的数据。ViewModel通常包括以下几个部分:

  • 数据模型(Model):ViewModel通过数据模型(Model)来获取和管理数据。
  • 数据绑定(Data Binding):ViewModel通过数据绑定(Data Binding)将数据模型(Model)中的数据同步到View中。
  • 命令绑定(Command Binding):ViewModel通过命令绑定(Command Binding)将视图(View)中的事件和命令(Command)绑定在一起。

View

在MVVM框架中,View是用户界面的展示部分,通常由HTML、CSS和JavaScript等技术实现。View负责将ViewModel中的数据呈现给用户,并接受用户的输入操作。同时,View也需要将用户的操作传递给ViewModel进行处理。

总的来说,MVVM框架通过数据绑定和命令绑定实现了视图(View)和视图模型(ViewModel)之间的解耦,将应用程序的逻辑和用户界面分离开来,从而提高了代码的可维护性和可扩展性。

当我们在Vue中使用MVVM框架时,我们通常会遵循以下步骤:

  1. 在Vue中创建一个Vue实例,指定其所使用的HTML元素和初始数据。
  2. 在Vue实例中定义一个名为"methods"的对象,用于定义视图中的事件处理函数。
  3. 在Vue实例中定义一个名为"computed"的对象,用于定义视图中的计算属性。
  4. 在HTML中使用Vue指令,将视图与数据模型绑定在一起。

下面是一个使用Vue实现的简单计数器应用程序的示例:

htmlCopy code

<!DOCTYPE html>
<html> 
<head> 
<title>Vue MVVM Example</title> 
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>
<body> 
<div id="app"> <h1>{{ count }}</h1>
<button v-on:click="increment">+</button>
<button v-on:click="decrement">-</button> 
</div> 
<script>
var app = new Vue({
el: '#app',
data: { count: 0 },
methods: {
    increment: function()
    { this.count += 1; }, 
    decrement: function() 
    { this.count -= 1; } },
computed: {}
}); 
</script> 
</body> 

</html> 

在这个示例中,我们使用Vue创建了一个Vue实例,将其绑定到id为"app"的HTML元素上。在Vue实例中,我们定义了一个名为"count"的数据模型,以及两个名为"increment"和"decrement"的事件处理函数。我们还通过Vue指令将视图中的两个按钮与对应的事件处理函数绑定在一起。

当用户点击"+“按钮时,Vue实例中的increment方法将被调用,它会将count加1,并通过数据绑定机制自动将更新后的值同步到视图中。当用户点击”-"按钮时,同样会调用decrement方法,将count减1。

这个示例演示了MVVM框架中数据绑定和命令绑定的实现方式,它将数据模型和视图逻辑分离开来,提高了代码的可维护性和可扩展性。

三、uniapp

3.1 什么是uni-app?

uni-app是一个使用 Vue.js 开发所有前端应用的框架,开发者编写一套代码,可发布到iOS、Android、Web(响应式)、以及各种小程序(微信/支付宝/百度/头条/飞书/QQ/快手/钉钉/淘宝)、快应用等多个平台。

一套代码编到14个平台 :

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dvMG4iNK-1677491373241)(C:\Users\Administrator\AppData\Local\Temp\1677479569671.png)]

3.2 快速上手

开始之前,开发者需先下载安装如下工具:

  • HBuilderX:官方IDE下载地址

3.2.1 创建uni-app

在点击工具栏里的文件 -> 新建 -> 项目(快捷键Ctrl+N):

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VTyMIRCm-1677491373243)(C:\Users\Administrator\AppData\Local\Temp\1677479883538.png)]

选择uni-app类型,输入工程名,选择模板,点击创建,即可成功创建。

uni-app自带的模板有 默认的空项目模板、Hello uni-app 官方组件和API示例,还有一个重要模板是 uni ui项目模板,日常开发推荐使用该模板,已内置大量常用组件。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6HOge0Cz-1677491373252)(C:\Users\Administrator\AppData\Local\Temp\1677479914051.png)]

3.2.2 uni-app工程目录结构

一个uni-app工程,默认包含如下目录及文件

┌─uniCloud              云空间目录,阿里云为uniCloud-aliyun,腾讯云为uniCloud-tcb(详见uniCloud)
│─components            符合vue组件规范的uni-app组件目录
│  └─comp-a.vue         可复用的a组件
├─utssdk                存放uts文件
├─pages                 业务页面文件存放的目录
│  ├─index
│  │  └─index.vue       index页面
│  └─list
│     └─list.vue        list页面
├─static                存放应用引用的本地静态资源(如图片、视频等)的目录,注意:静态资源只能存放于此
├─uni_modules           存放[uni_module](/uni_modules)。
├─platforms             存放各平台专用页面的目录,详见
├─nativeplugins         App原生语言插件 详见
├─nativeResources       App端原生资源目录
│  └─android            Android原生资源目录 详见
├─hybrid                App端存放本地html文件的目录,详见
├─wxcomponents          存放小程序组件的目录,详见
├─unpackage             非工程代码,一般存放运行或发行的编译结果
├─AndroidManifest.xml   Android原生应用清单文件 详见
├─main.js               Vue初始化入口文件
├─App.vue               应用配置,用来配置App全局样式以及监听 应用生命周期
├─manifest.json         配置应用名称、appid、logo、版本等打包信息,详见
├─pages.json            配置页面路由、导航条、选项卡等页面类信息,详见
└─uni.scss              这里是uni-app内置的常用样式变量

3.2.3 页面简介

uni-app项目中,一个页面就是一个符合Vue SFC规范.vue文件或.nvue文件。

.vue页面和.nvue页面,均全平台支持,差异在于当uni-app发行到App平台时,.vue文件会使用webview进行渲染,.nvue会使用原生进行渲染。

新建页面

uni-app中的页面,通常会保存在工程根目录下的pages目录下。

每次新建页面,均需在pages.json中配置pages列表;未在pages.json -> pages 中配置的页面,uni-app会在编译阶段进行忽略。pages.json的完整配置参考:全局文件。

通过HBuilderX开发 uni-app 项目时,在 uni-app 项目上右键“新建页面”,HBuilderX会自动在pages.json中完成页面注册,开发更方便。

同时,HBuilderX 还内置了常用的页面模板(如图文列表、商品列表等),选择这些模板,可以大幅提升你的开发效率。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-blFJTk8L-1677491373255)(C:\Users\Administrator\AppData\Local\Temp\1677481498150.png)]

删除页面

删除页面时,需做两件工作:

  • 删除.vue文件或.nvue文件
  • 删除pages.json -> pages列表项中的配置

应用首页

uni-app会将pages.json -> pages配置项中的第一个页面,作为当前工程的首页(启动页)。

页面生命周期

uni-app 支持如下页面生命周期函数:

函数名说明平台差异说明最低版本
onInit监听页面初始化,其参数同 onLoad 参数,为上个页面传递的数据,参数类型为 Object(用于页面传参),触发时机早于 onLoad百度小程序3.1.0+
onLoad监听页面加载,其参数为上个页面传递的数据,参数类型为 Object(用于页面传参),参考示例
onShow监听页面显示。页面每次出现在屏幕上都触发,包括从下级页面点返回露出当前页面
onReady监听页面初次渲染完成。注意如果渲染速度快,会在页面进入动画完成前触发
onHide监听页面隐藏
onUnload监听页面卸载
onResize监听窗口尺寸变化App、微信小程序、快手小程序
onPullDownRefresh监听用户下拉动作,一般用于下拉刷新,参考示例
onReachBottom页面滚动到底部的事件(不是scroll-view滚到底),常用于下拉下一页数据。具体见下方注意事项
onTabItemTap点击 tab 时触发,参数为Object,具体见下方注意事项微信小程序、QQ小程序、支付宝小程序、百度小程序、H5、App、快手小程序、京东小程序
onShareAppMessage用户点击右上角分享微信小程序、QQ小程序、支付宝小程序、字节小程序、飞书小程序、快手小程序、京东小程序
onPageScroll监听页面滚动,参数为Objectnvue暂不支持
onNavigationBarButtonTap监听原生标题栏按钮点击事件,参数为ObjectApp、H5
onBackPress监听页面返回,返回 event = {from:backbutton、 navigateBack} ,backbutton 表示来源是左上角返回按钮或 android 返回键;navigateBack表示来源是 uni.navigateBack ;详细说明及使用:onBackPress 详解。支付宝小程序只有真机能触发,只能监听非navigateBack引起的返回,不可阻止默认行为。app、H5、支付宝小程序
onNavigationBarSearchInputChanged监听原生标题栏搜索输入框输入内容变化事件App、H51.6.0
onNavigationBarSearchInputConfirmed监听原生标题栏搜索输入框搜索事件,用户点击软键盘上的“搜索”按钮时触发。App、H51.6.0
onNavigationBarSearchInputClicked监听原生标题栏搜索输入框点击事件(pages.json 中的 searchInput 配置 disabled 为 true 时才会触发)App、H51.6.0
onShareTimeline监听用户点击右上角转发到朋友圈微信小程序2.8.1+
onAddToFavorites监听用户点击右上角收藏微信小程序、QQ小程序2.8.1+

onReachBottom使用注意 可在pages.json里定义具体页面底部的触发距离onReachBottomDistance,比如设为50,那么滚动页面到距离底部50px时,就会触发onReachBottom事件。

组件生命周期

uni-app 组件支持的生命周期,与vue标准组件的生命周期相同。这里没有页面级的onLoad等生命周期:

函数名说明平台差异说明最低版本
beforeCreate在实例初始化之前被调用。详见
created在实例创建完成后被立即调用。详见
beforeMount在挂载开始之前被调用。详见
mounted挂载到实例上去之后调用。详见 注意:此处并不能确定子组件被全部挂载,如果需要子组件完全挂载之后在执行操作可以使用$nextTickVue官方文档
beforeUpdate数据更新时调用,发生在虚拟 DOM 打补丁之前。详见仅H5平台支持
updated由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。详见仅H5平台支持
beforeDestroy实例销毁之前调用。在这一步,实例仍然完全可用。详见
destroyedVue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。详见

路由

uni-app页面路由为框架统一管理,开发者需要在pages.json里配置每个路由页面的路径及页面样式。类似小程序在 app.json 中配置页面路由一样。所以 uni-app 的路由用法与 Vue Router 不同,如仍希望采用 Vue Router 方式管理路由,可在插件市场搜索 Vue-Router。

路由跳转

uni-app 有两种页面路由跳转方式:使用navigator组件跳转、调用API跳转。

页面栈

框架以栈的形式管理当前所有页面, 当发生路由切换的时候,页面栈的表现如下:

路由方式页面栈表现触发时机
初始化新页面入栈uni-app 打开的第一个页面
打开新页面新页面入栈调用 API uni.navigateTo 、使用组件
页面重定向当前页面出栈,新页面入栈调用 API uni.redirectTo 、使用组件
页面返回页面不断出栈,直到目标返回页调用 API uni.navigateBack 、使用组件 、用户按左上角返回按钮、安卓用户点击物理back按键
Tab 切换页面全部出栈,只留下新的 Tab 页面调用 API uni.switchTab 、使用组件 、用户切换 Tab
重加载页面全部出栈,只留下新的页面调用 API uni.reLaunch 、使用组件

相互引用

引用组件:

传统vue项目开发,引用组件需要导入 - 注册 - 使用三个步骤,如下:

<template>
	<view>
		<!-- 3.使用组件 -->
		<uni-rate text="1"></uni-rate>
	</view>
</template>
<script>
	// 1. 导入组件
	import uniRate from '@/components/uni-rate/uni-rate.vue';
	export default {
		components: { uniRate } // 2. 注册组件
	}
</script>

Vue 3.x增加了script setup特性,将三步优化为两步,无需注册步骤,更为简洁:

<template>
	<view>
		<!-- 2.使用组件 -->
		<uni-rate text="1"></uni-rate>
	</view>
</template>
<script setup>
	// 1. 导入组件
	import uniRate from '@/components/uni-rate/uni-rate.vue';
</script>

uni-appeasycom机制,将组件引用进一步优化,开发者只管使用,无需考虑导入和注册,更为高效:

<template>
	<view>
		<!-- 1.使用组件 -->
		<uni-rate text="1"></uni-rate>
	</view>
</template>
<script>
</script>

在 uni-app 项目中,页面引用组件和组件引用组件的方式都是一样的(可以理解为:页面是一种特殊的组件),均支持通过 easycom 方式直接引用。

js 文件引入

js文件或script标签内(包括 renderjs 等)引入js文件时,可以使用相对路径和绝对路径,形式如下

// 绝对路径,@指向项目根目录,在cli项目中@指向src目录
import add from '@/common/add.js';
// 相对路径
import add from '../../common/add.js';

注意

  • js 文件不支持使用/开头的方式引入

NPM支持

uni-app支持使用npm安装第三方包。

此文档要求开发者们对npm有一定的了解,因此不会再去介绍npm的基本功能。如若之前未接触过npm,请翻阅NPM官方文档进行学习。

初始化npm工程

若项目之前未使用npm管理依赖(项目根目录下无package.json文件),先在项目根目录执行命令初始化npm工程:

npm init -y

cli项目默认已经有package.json了。HBuilderX创建的项目默认没有,需要通过初始化命令来创建。

安装依赖

在项目根目录执行命令安装npm包:

npm install packageName --save

使用

安装完即可使用npm包,js中引入npm包:

import package from 'packageName'
const package = require('packageName')

引入css

使用@import语句可以导入外联样式表,@import后跟需要导入的外联样式表的相对路径,用;表示语句结束。

示例代码:

<style>
    @import "../../common/uni.css";

    .uni-card {
        box-shadow: none;
    }
</style>

css 引入静态资源

css文件或style标签内引入css文件时(scss、less 文件同理),可以使用相对路径或绝对路径(HBuilderX 2.6.6

/* 绝对路径 */
@import url('/common/uni.css');
@import url('@/common/uni.css');
/* 相对路径 */
@import url('../../common/uni.css');

复制代码

注意

  • HBuilderX 2.6.6起支持绝对路径引入静态资源,旧版本不支持此方式

css文件或style标签内引用的图片路径可以使用相对路径也可以使用绝对路径,需要注意的是,有些小程序端 css 文件不允许引用本地文件(请看注意事项)。

/* 绝对路径 */
background-image: url(/static/logo.png);
background-image: url(@/static/logo.png);
/* 相对路径 */
background-image: url(../../static/logo.png);

3.2.4 运行uni-app

浏览器运行:进入hello-uniapp项目,点击工具栏的运行 -> 运行到浏览器 -> 选择浏览器,即可体验 uni-app 的 web 版。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7LHZBReq-1677491373257)(C:\Users\Administrator\AppData\Local\Temp\1677480041248.png)]

运行App到手机或模拟器:使用电压足够的usb端口连接手机,设置中开启USB调试,手机上允许电脑设备调试手机,进入hello-uniapp项目,点击工具栏的运行 -> 运行App到手机或模拟器,即可在该设备里面体验uni-app。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pUlFurDL-1677491373259)(C:\Users\Administrator\AppData\Local\Temp\1677480055229.png)]

如需运行在苹果手机真机上,注意需使用自定义基座 .

在微信开发者工具里运行:进入hello-uniapp项目,点击工具栏的运行 -> 运行到小程序模拟器 -> 微信开发者工具,即可在微信开发者工具里面体验uni-app。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SUNwvz7p-1677491373337)(C:\Users\Administrator\AppData\Local\Temp\1677480075752.png)]

注意:如果是第一次使用,需要先配置小程序ide的相关路径,才能运行成功。如下图,需在输入框输入微信开发者工具的安装路径。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ONb88xYq-1677491373340)(C:\Users\Administrator\AppData\Local\Temp\1677480089899.png)]

3.2.5 发布uni-app

打包为原生App

在HBuilderX工具栏,点击发行,选择原生app-云端打包,如下图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-56r3umCj-1677491373342)(C:\Users\Administrator\AppData\Local\Temp\1677480192068.png)]

出现如下界面,点击打包即可

云端打包支持安心打包,保护用户隐私,不会上传代码和证书,通过差量包制作方式实现安心打包。

App打包时,注意如果涉及三方sdk,需进行申请并在manifest.json里配置,否则相关功能无法使用。

iOS App打包需要向Apple申请证书。

发布为Web网站

  1. manifest.json 的可视化界面,进行如下配置(发行在网站根目录可不配置应用基本路径),此时发行网站路径是 www.xxx.com/h5

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zb9ssag7-1677491373344)(C:\Users\Administrator\AppData\Local\Temp\1677480428998.png)]

  2. 在HBuilderX工具栏,点击发行,选择网站-H5手机版,如下图,点击即可生成 H5 的相关资源文件,保存于 unpackage 目录

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GRKsksiA-1677491373347)(C:\Users\Administrator\AppData\Local\Temp\1677480576864.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bkAilRXM-1677491373349)(C:\Users\Administrator\AppData\Local\Temp\1677480599102.png)]

    • 打包后,推荐使用前端网页托管服务,一键上传,自带CDN加速,无需购买虚拟机,无需安装nginx等;

发布为微信小程序

  1. 申请微信小程序AppID,参考:微信教程。
  2. 在HBuilderX中顶部菜单依次点击 “发行” => “小程序-微信”,输入小程序名称和appid点击发行即可

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-01m8R5uW-1677491373351)(C:\Users\Administrator\AppData\Local\Temp\1677480773411.png)]

如果手动发行,则点击发行按钮后,会在项目的目录 unpackage/dist/build/mp-weixin 生成微信小程序项目代码。在微信小程序开发者工具中,导入生成的微信小程序项目,测试项目代码运行正常后,点击“上传”按钮,之后按照 “提交审核” => “发布” 小程序标准流程,逐步操作即可,详细查看:微信官方教程。

如果在发行界面勾选了自动上传微信平台,则无需再打开微信工具手动操作,将直接上传到微信服务器提交审核。

四、 unicloud

uniCloud 是 DCloud 联合阿里云、腾讯云,为开发者提供的基于 serverless 模式和 js 编程的云开发平台。

uniCloud 的 web控制台地址:https://unicloud.dcloud.net.cn

4.1uniCloud是什么和不是什么

uniCloud是DCloud在阿里云和腾讯云的serverless服务上封装而成的。

它包含IaaS层(由阿里云和腾讯云提供硬件和网络)和PaaS层(由DCloud提供开发环境)。

开发者可以自主选择uniCloud的硬件和网络资源的供应商,在阿里云版和腾讯云版之间切换。

开户和付费虽然通过DCloud渠道,但实际上开发者自动在云厂商处建立了账户和充值了余额。价格是云厂商的标准定价,DCloud只获取云服务厂商的返佣。

开发时虽使用DCloud的工具,但应用上线时,手机端是直连阿里云或腾讯云的serverless,不经由DCloud的服务器。

4.2 什么是serverless?

serverless是目前很火的概念,它是下一代云技术,是真正的“云”。

传统的云服务,让开发者免于购买实体服务器硬件,改为购买虚拟机。但开发者仍然要自己装操作系统、web服务器、数据库,自己处理热备,自己新购服务器来应对高并发,自己抗DDOS攻击…

这不是成熟的“云”!

真正的云计算,就像用水用电,没有复杂的门槛,即用即有、按需付费。

简单回顾下用电的历史。几十年前,很多单位都有专门管电的工程师,当单位的电力负荷不够时,就需要找这个管电的工程师扩容发电机。

现在这个管电工程师的岗位已经淘汰了,电已经变成随用随取、按需付费了。

传统云模式下,开发商仍然需要一个管服务器的工程师,当用户量激增或被攻击时,甚至需要半夜把工程师叫醒来扩容。这当然不合理。

serverless的云,真正的把计算、存储的能力进行了云化,开发者只需要按量租用这些计算和存储能力,再也不用关心扩容和攻击。

开发者不再有“服务器”的概念,因为没有一台具体的机器。就像现在的你再也找不到自己的发电机一样。

当用户量激增时,开发者什么都不用做,系统自动承载更高并发。开发者只需要按照对资源的消耗付费即可。

同理,如果没有用户使用,即没有资源消耗,则根本无需为云资源付费。

开发者写好云端业务代码,即js编写的云函数,通过HBuilderX部署到uniCloud上即可。

云端庞大的serverless资源池,有无数个node进程待命。当手机用户发起请求时,serverless系统会调配闲置的资源来运行开发者相应的云函数。

  • serverless,让一个不懂服务器运维的开发者,可以只处理自己的业务,再不用关心热备、负载、增容、DDOS等事情。
  • serverless,让一个学生,也可以享受世界最顶级的IT基础设置。

serverless在国外兴起,但国内的发展速度已经超过了国外。微信、支付宝、百度、字节跳动、快应用联盟都上线了自己的serverless云开发。

目前国内已经有超过60万开发者在使用serverless云开发,包括腾讯、阿里、DCloud的很多自有业务都在使用。

就像uni-app可跨端一样,uniCloud可跨云。基于uniCloud,无需担心使用云开发被绑定到专用的小程序平台。uni-app + uniCloud 是跨端跨云的开发方案

4.3 基本概念

4.3.1服务空间

一个服务空间对应一整套独立的云开发资源,包括数据库、存储空间、云函数等资源。服务空间之间彼此隔离。

每个服务空间都有一个全局唯一的space ID。

  • 通过 HBuilderX 中管理服务空间,包括新建服务空间和关联服务空间

uniCloud 目录右键菜单中创建服务空间

img

创建服务空间后,在同样的 uniCloud 目录右键菜单中关联该服务空间。只有项目关联好服务空间后,才能上传云函数、操作服务空间下的数据库、存储等资源。

  • 通过uniCloud的web控制台https://unicloud.dcloud.net.cn 管理服务空间。

web控制台可以新建、删除服务空间,管理线上的服务空间资源。

新建服务空间注意

  • 第一次创建腾讯云服务空间时会为用户创建腾讯云账号并跳转到腾讯云实名界面,等待实名认证审核之后可以开通服务空间。若腾讯云实名认证提示身份证下已创建过多账户,则需要在腾讯云官网注销不用的账户。详见
  • 创建服务空间可能需要几十秒的时间,可以在web控制台查看是否创建完成。

多人协作

2022年7月18日前,服务空间的多人协作是在 dev.dcloud.net.cn 的 app 协作中设置。在2022年7月18日后,改为在 unicloud.dcloud.net.cn 设置。

一个服务空间只有一个创建者,但可以设置协作成员。

项目涉及多人开发时,在uniCloud WEB控制台设置协作者(选择服务空间->成员管理),实现多人共同使用一个云服务空间。

协作者可以在HBuilderX和web控制台中操作被授权的服务空间,除了删除服务空间,其他功能均可正常操作。

授权步骤:

  1. 登录uniCloud WEB控制台中选择要添加协作者的服务空间
  2. 在服务空间详情页面左侧菜单点击成员管理
  3. 输入协作者邮箱并点击搜索,下方会出现搜索到的结果,确认无误后点击添加成员进行添加

成员管理

  1. 下方成员列表中可以查看以及移除已添加的协作者

成员列表

注意

  • 服务空间协作者和App的协作者是2套体系,需要分别设置,无关联关系。App协作者在 dev.dcloud.net.cn 设置。
  • 只有服务空间的创建者才可以添加成员,协作者无此权限
  • 根据法律要求,协作者账号需完成实名认证才可以正常添加

应用和服务空间的关系

每个uni-app应用都有一个appid,每个服务空间都有一个spaceid。

服务空间和手机端项目是多对多绑定关系。同DCloud账号下,一个应用可以关联到多个服务空间。一个服务空间也可以被多个项目访问。

多应用共用服务空间

随着用户使用uniCloud开发的项目越来越多, 部分用户遇到了新的问题。

两个、多个项目想共用一个云服务空间,比如一个系统,有用户端项目、管理admin项目,两个项目需要公共服务空间。还有司机端、乘客端、用户端、骑手端…很多类似的问题。

如果每个项目目录下都存在多个重复的云函数文件。 每个项目都要做 同步云函数列表, 下载云函数等操作。 繁琐,而且很容易冲突。

针对上面出现的问题, 提供了一云多项目的解决方案。

一云多端

绑定其它项目的服务空间

选中项目下的uniCloud-aliyun|tcb目录, 右键菜单,点击 【关联云服务空间或项目… 】 ,可以关联云服务空间绑定其它项目的服务空间

以阿里云举例, 绑定其它项目的服务空间 指的是关联其他项目的当前使用的阿里云服务空间。

  1. 阿里云无法关联到腾讯云, 腾讯云也无法关联到阿里云, 但是项目可以关联,使用时会报错。
  2. 如果项目已关联其他项目, 选择云服务空间, 此时关联关系会断开。

4.3.2云数据库

uniCloud 提供了 2 个 nosql 数据库。

  • JSON文档型云数据库

    uniCloud阿里云版的云数据库就是 MongoDB 的 serverless版;uniCloud腾讯云版的云数据库是兼容 MongoDB 的自研数据库。

    数据库中的每条记录都是一个 JSON 格式的对象。

    一个数据库可以有多个集合(相当于关系型数据中的表),集合可看做一个 JSON 数组,数组中的每个对象就是一条记录,记录的格式是 JSON 对象。

    这对于js工程师而言,非常容易理解掌握。

    MongoDB的传统操作方法还是比较复杂,uniCloud提供了更多简单操作数据库的方案,包括类似 SQL 的 JQL 语法、clientDB等技术。

  • redis 数据库

    redis 是一种可以运行在内存中的键值对数据库,它的能力没有MongoDB强大,但由于可运行在内存中,它的性能远超常规数据库。

    redis 也使用 json 方式 key/value 键值对存储数据。更多文档参考

如果开发者需要其他数据库,比如 mysql、ElasticSearch、数据湖,这些数据库没有在uniCloud的服务空间内置,云函数中通过 nodejs 的 api 可以访问这些远程数据库。

4.3.3云函数/云对象

云函数即在云端(服务器端)运行的函数。

从 HBuilderX 3.4起,新增了云函数的扩展版,云对象。

开发者无需购买、搭建服务器,只需编写代码并部署到云端即可在客户端(App/Web/小程序等)调用,同时云函数之间也可互相调用。

一个云函数的写法与一个在本地定义的 JavaScript 方法无异,代码运行在云端 Node.js 中。当云函数被客户端调用时,定义的代码会被放在 Node.js 运行环境中执行。

开发者可以如在 Node.js 环境中使用 JavaScript 一样在云函数中进行网络请求等操作,也可以使用 node_modules。

但 DCloud提供了 uniCloud对象 内置在云函数/云对象中,开发者使用更多的是 uniCloud 的 api,不了解 node 不影响开发。

HBuilderX 3.0起版本,在uniCloud/cloudfunctions目录右键创建云函数,如下:

img

在HBuilderX 3.4起,上述界面更新为 新建云函数/云对象。

云对象本质是对云函数的一种封装,可以对象化的方式使用云服务。

HBuilderX 3.0之前版本,项目下没有uniCloud目录,直接在cloudfunctions目录上右键、新建云函数

云函数修改后,可以本地运行。只有上传到云端,方可在云端生效。

4.4 快速上手

4.4.1 创建uniCloud项目

HBuilderX中新建项目,选择uni-app项目,并勾选启用uniCloud,在右侧选择服务供应商(腾讯云或阿里云)

项目名称随意,比如 firstunicloud

4.4.2 关联服务空间

一个开发者可以拥有多个服务空间,每个服务空间都是一个独立的serverless云环境,不同服务空间之间的云函数、数据库、存储都是隔离的。

对项目根目录uniCloud点右键选择关联云服务空间,绑定之前创建的服务空间,或者新建一个服务空间。

4.4.3 创建云函数/云对象

uniCloud项目创建并绑定服务空间后,开发者可以创建云函数(云对象是云函数的一种,云函数可泛指普通云函数和云对象)。

uniCloud/cloudfunctions目录右键创建云函数/云对象

img

  • 创建云函数后,生成一个目录,该目录下自动生成index.js,是该云函数的入口文件,不可改名。
  • 创建云对象后,生成一个目录,该目录下自动生成index.obj.js,是该云对象的入口文件,不可改名。

如果该云函数/云对象还需要引入其他js,可在index.js入口文件中引用。

初学者,建议从云对象学起,比云函数更加简单直观。

在本教程中,我们创建一个云对象名为 helloco。

  1. 给云对象编写方法

打开index.obj.js,我们为它添加一个 sum 方法,逻辑就是接收传入a和b2个参数,返回求和结果。

module.exports = {
	sum(a, b) {
		// 此处省略a和b的有效性校验
		return a + b
	}
}
  1. 在前端调用云对象

在项目首页,pages/index/index.vue 里,添加一个按钮,点击后执行异步方法sum。

js 中 import 这个 helloco 对象,调用它的 sum 方法

<template>
	<view class="content">
		<button @click="testco()">请求云对象的方法</button>
	</view>
</template>

<script>
	export default {
		data() {
			return {
			}
		},
		methods: {
			async testco() { // 注意异步
				const helloco = uniCloud.importObject('helloco') // 导入云对象
				try {
					const res = await helloco.sum(1,2) //导入云对象后就可以直接调用该对象的sum方法了,注意使用异步await
					console.log(res) // 结果是3
				} catch (e) {
					console.log(e)
				}
			}
		}
	}
</script>
  1. 运行

将项目运行到浏览器或其他平台,点页面上的按钮,控制台会打印结果:3

HBuilderX自带一个云函数本地运行环境,运行项目时也默认选择 连接本地云函数。可以在底部控制台中的前端控制台右上角进行切换。

可以对helloco云对象点右键上传到uniCloud服务空间,然后在前端控制台右上角切换为 连接云端云函数,那么此时客户端连接的就是真正的现网uniCloud服务器了。

五、 项目案例

、新建云函数

云函数修改后,可以本地运行。只有上传到云端,方可在云端生效。

4.4 快速上手

4.4.1 创建uniCloud项目

HBuilderX中新建项目,选择uni-app项目,并勾选启用uniCloud,在右侧选择服务供应商(腾讯云或阿里云)

项目名称随意,比如 firstunicloud

4.4.2 关联服务空间

一个开发者可以拥有多个服务空间,每个服务空间都是一个独立的serverless云环境,不同服务空间之间的云函数、数据库、存储都是隔离的。

对项目根目录uniCloud点右键选择关联云服务空间,绑定之前创建的服务空间,或者新建一个服务空间。

4.4.3 创建云函数/云对象

uniCloud项目创建并绑定服务空间后,开发者可以创建云函数(云对象是云函数的一种,云函数可泛指普通云函数和云对象)。

uniCloud/cloudfunctions目录右键创建云函数/云对象

[外链图片转存中…(img-X1PYnlC3-1677491373368)]

  • 创建云函数后,生成一个目录,该目录下自动生成index.js,是该云函数的入口文件,不可改名。
  • 创建云对象后,生成一个目录,该目录下自动生成index.obj.js,是该云对象的入口文件,不可改名。

如果该云函数/云对象还需要引入其他js,可在index.js入口文件中引用。

初学者,建议从云对象学起,比云函数更加简单直观。

在本教程中,我们创建一个云对象名为 helloco。

  1. 给云对象编写方法

打开index.obj.js,我们为它添加一个 sum 方法,逻辑就是接收传入a和b2个参数,返回求和结果。

module.exports = {
	sum(a, b) {
		// 此处省略a和b的有效性校验
		return a + b
	}
}
  1. 在前端调用云对象

在项目首页,pages/index/index.vue 里,添加一个按钮,点击后执行异步方法sum。

js 中 import 这个 helloco 对象,调用它的 sum 方法

<template>
	<view class="content">
		<button @click="testco()">请求云对象的方法</button>
	</view>
</template>

<script>
	export default {
		data() {
			return {
			}
		},
		methods: {
			async testco() { // 注意异步
				const helloco = uniCloud.importObject('helloco') // 导入云对象
				try {
					const res = await helloco.sum(1,2) //导入云对象后就可以直接调用该对象的sum方法了,注意使用异步await
					console.log(res) // 结果是3
				} catch (e) {
					console.log(e)
				}
			}
		}
	}
</script>
  1. 运行

将项目运行到浏览器或其他平台,点页面上的按钮,控制台会打印结果:3

HBuilderX自带一个云函数本地运行环境,运行项目时也默认选择 连接本地云函数。可以在底部控制台中的前端控制台右上角进行切换。

可以对helloco云对象点右键上传到uniCloud服务空间,然后在前端控制台右上角切换为 连接云端云函数,那么此时客户端连接的就是真正的现网uniCloud服务器了。

五、 项目案例

https://blog.csdn.net/weixin_43025151/article/details/129019497?spm=1001.2014.3001.5501

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/376475.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

9. IP组播(理论)

作为IP传输三种方式之一&#xff0c;IP组播通信指的是IP报文从一个源发出&#xff0c;被转发到一组特定的接收者。相较于传统的单播和广播&#xff0c;IP组播可以有效地节约网络带宽、降低网络负载&#xff0c;所以被广泛应用于IPTV、实时数据传送和多媒体会议等网络业务中。 …

5 逻辑回归及Python实现

1 主要思想 分类就是分割数据&#xff1a; 两个条件属性&#xff1a;直线&#xff1b;三个条件属性&#xff1a;平面&#xff1b;更多条件属性&#xff1a;超平面。 使用数据&#xff1a; 5.1,3.5,0 4.9,3,0 4.7,3.2,0 4.6,3.1,0 5,3.6,0 5.4,3.9,0 . . . 6.2,2.9,1 5.1,2.5…

一个容易被忽视的标签 —— iframe

前言 甲问&#xff1a;说说你知道的HTML标签。 乙于是说了一大堆标签&#xff0c;比如div&#xff0c;span等等。 甲说&#xff1a;那你知道 iframe 标签吗&#xff1f; 乙这时候迟疑了片刻&#xff0c;缓缓说出&#xff1a;知道它&#xff0c;但是不太了解这个标签。 HTM…

学到了,原来华为是这样判断MES系统的好坏的

可以想象华为公司对供应商的要求是多么严格&#xff0c;那么我们今天来谈一下华为对供应商工厂MES系统这块的要求&#xff0c;这要从生产防错系统、品质管控系统、品质追溯系统、出货防错系统四个方面来说。一、生产物料和生产治具防错系统建立完整的物料和治具标签方案&#x…

常用的数据脱敏(手机、邮箱、身份证号)

一、什么是数据脱敏 先来看看什么是数据脱敏&#xff1f;数据脱敏也叫数据的去隐私化&#xff0c;在我们给定脱敏规则和策略的情况下&#xff0c;对敏感数据比如 手机号、银行卡号 等信息&#xff0c;进行转换或者修改的一种技术手段&#xff0c;防止敏感数据直接在不可靠的环境…

AcWing3485. 最大异或和

先看题目&#xff1a; 说实话&#xff0c;我看到这道题就想用滑动窗口&#xff0c;但是滑了一下发现不太对啊&#xff0c;如果我用滑动窗口的话&#xff0c;那么最后肯定是一个固定长度为m的窗口在持续计算&#xff0c;区间长度小于m的区间的异或和肯定会被遗漏。然后我就想怎么…

vue前端架构说明书模板示例

目录 1. 技术说明... 2 1.1 版本明细... 2 1.2 核心技术介绍... 2 2. 项目结构说明... 3 3. 自动化部署设置说明... 5 4. 打包及运行说明... 5 5. 导包说明... 6 5.1 方案一... 6 5.2 方案二... 7 5.3 补充说明... 7 6. 修改本地运行时链接的服务器说明... 7 7. 常…

从 B 站出发,用 Chrome devTools performance 分析页面如何渲染

页面是如何渲染的&#xff1f;通常会得到“解析 HTML、css 合成 Render Tree&#xff0c;就可以渲染了”的回答。但是具体都做了些什么&#xff0c;却很少有人细说&#xff0c;我们今天就从 Chrome 的性能工具开始&#xff0c;具体看看一个页面是如何进行渲染的&#xff0c;以及…

视频传输协议详解(RTMP、RTSP、HLS)

RTMP——Real Time Messaging Protocol&#xff08;实时消息传输协议&#xff09;RTMP是由Adobe公司提出的&#xff0c;在互联网TCP/IP五层体系结构中应用层&#xff0c;RTMP协议是基于TCP协议的&#xff0c;也就是说RTMP实际上是使用TCP作为传输协议。TCP协议在处在传输层&…

sql学习一

文章目录一、if 语句二、去重问题三、concat,upper,lower四、group_concat五、like 模糊匹配六、union和union all七、流程控制语句case八、limit一、if 语句 if(expr1, expr2, expr3)当expr1的值为真时函数的返回值为expr2&#xff0c;当expr1的值为假时&#xff0c;函数的返…

安装redis并设置开机自启动允许远程链接

一、进入/usr/local目录下面&#xff1b;下载redis包wget https://download.redis.io/releases/redis-5.0.14.tar.gz二、安装gccyum install gcc-c三、解压、进入目录、编译tar -xvf redis-5.0.14.tar.gzcd redis-5.0.14make ##如果报错zmalloc.h:50:31: 致命错误&#xff1a;j…

打破单片机开发模式--胶水语言(JavaScript)

概述 传统的嵌入式单片机开发基本上形式如下图&#xff1a; 该流程对于功能单一或者功能变更极少的场景是比较友好的&#xff0c;但是对于设备应用层变更比较多或者公板方案开发应用的场景&#xff0c;上述场景显的有些累赘。那么有什么方式可以解决呢&#xff1f;&#xff1f…

U-Boot 之七 详解 Driver Model 架构、配置、命令、初始化流程

U-Boot 在 2014 年 4 月参考 Linux Kernel 的驱动模型设计并引入了自己的 Driver Model&#xff08;官方简称 DM&#xff09; 驱动架构。这个驱动模型&#xff08;DM&#xff09;为驱动的定义和访问接口提供了统一的方法&#xff0c;提高了驱动之间的兼容性以及访问的标准性。 …

和月薪3W的聊过后,才知道自己一直在打杂...

前几天和一个朋友聊面试&#xff0c;他说上个月同时拿到了腾讯和阿里的offer&#xff0c;最后选择了阿里。 我了解了下他的面试过程&#xff0c;就一点&#xff0c;不管是阿里还是腾讯的面试&#xff0c;这个级别的程序员&#xff0c;都会考察项目管理能力&#xff0c;并且权重…

[牛客网] HJ35 蛇形矩阵(写了好久才写出来)

链接https://www.nowcoder.com/practice/649b210ef44446e3b1cd1be6fa4cab5e?tpId37&tqId21258&rp1&ru/exam/oj/ta&qru/exam/oj/ta&sourceUrl%2Fexam%2Foj%2Fta%3Fdifficulty%3D2%26page%3D1%26pageSize%3D50%26search%3D%26tpId%3D37%26type%3D37&dif…

区块链行业遭供应链攻击,上万加密钱包被“抄底”损失上亿美元

当地时间8月2日晚间&#xff0c; 区块链行业遭遇了一次行业重创 。据科技媒体TechCrunch报道&#xff0c; 若干名攻击者“抄底”了上万个加密钱包&#xff0c;钱包内有价值上亿美元的代币。 据了解遭受攻击的加密钱包包括Phantom、Slope和TrustWallet等。涉及到的币种除了SOL、…

Vue2的tsx开发入门完全指南

本篇文章尽量不遗漏重要环节&#xff0c;本着真正分享的心态&#xff0c;不做标题党 下面进入正题&#xff1a; 由于现在vue的官方脚手架已经非常完善我们就不单独配置webpack了&#xff0c;节省大量的时间成本。 首先使用vue/cli创建一个vue模版项目&#xff08;记得是vue/…

Dockerfile详解

一、能干嘛&#xff1f; 我们总会遇到下面这种情况&#xff1a;使用docker pull 拉取下来的镜像发现其提供的功能并不完善&#xff0c;比如拉下来个centos的镜像&#xff0c;运行该镜像生成容器发现连vim&#xff0c;ifconfig命令都没有&#xff01;想要在该镜像的基础上扩充其…

[SQL]增删查改语法概览

数据定义 基本概念 基本表 本身独立存在的表SQL中一个关系就对应一个基本表一个(或多个)基本表对应一个存储文件一个表可以带若干索引 存储文件 物理结构对用户透明索引存放在存储文件中 视图 从一个或几个基本表导出的表数据库中至存放数据的定义而不存放视图对应的数据视…

Moonlight iPad全屏无边框串流方法

环境&#xff1a;iPad MoonLight 串流PC 问题&#xff1a;iPad无法全屏&#xff0c;有边框 解决办法&#xff1a;将电脑分辨率和MoonLight自定义分辨率调整为iPad原始分辨率 背景&#xff1a;在使用iPad进行MoonLight串流PC游戏时&#xff0c;发现客户端不论如何设定iPad都有边…