ASP.NET Core 中 HttpContext 详解与使用 | Microsoft.AspNetCore.Http 详解 - 痴者工良 - 博客园

mikel阅读(160)

来源: ASP.NET Core 中 HttpContext 详解与使用 | Microsoft.AspNetCore.Http 详解 – 痴者工良 – 博客园

笔者没有学 ASP.NET,直接学 ASP.NET Core ,学完 ASP.NET Core MVC 基础后,开始学习 ASP.NET Core 的运行原理。发现应用程序有一个非常主要的 “传导体” HttpContext 。

赶忙写一下笔记先。

目录

“传导体” HttpContext

操作 HttpContext 前期准备

HttpContext 类型的属性和方法

HttpContext 对象实践与测试


“传导体” HttpContext

要理解 HttpContext 是干嘛的,首先,看图

  图一 内网访问程序

图二 反向代理访问程序

 

ASP.NET Core 程序中,Kestrel 是一个基于 libuv 的跨平台 ASP.NET Core web 服务器。不清楚 Kerstrel 没关系,以后慢慢了解。

我们可以理解成,外部访问我们的程序,通过 Http 或者 Https 访问,例如 https://localhost:44337/Home/Index,需要通过一个网址,来寻向访问特定的页面。

访问页面时,会产生 Cookie、Seesion、提交表单、上传数据、身份认证等,外部与应用程序之间传导的导体就是 HttpContext

总之,客户端跟 Web应用程序交互 是通过 HttpContext 传导的。

 

原理

ASP.NET Core 本质是一个控制台程序!ASP.NET Core 程序并不直接监听请求,而是通过依赖 HTTP Server ,来实现把各自请求转发到应用程序中。这个被转发的请求相当于我们日常浏览网页、上传文件、提交表单等的网络请求,这些请求会被包装,然后组合到 HttpContext 中。

就好像顾客到餐厅吃饭

  1. 需要先点菜、提出服务要求
  2. 服务员把你的菜单、需求送到厨房
  3. 厨师在加工好食品
  4. 服务员再把食品递给你

HttpContext 相当于这个服务员,她在前、后传递信息。


操作 HttpContext 前期准备

一般来说,我们主要写好Web程序,而无需理会 数据是怎么传导的。就好像两台电脑能够发送资料,我们用不着知道他们是通过无线Wifi、光纤还是铜线电缆传输的。

当有需要时,自然需要用~ 废话少说,先简单操作 HttpContext 了解下。后面接着解析这个对象。

如果你不需要练习,请直接跳过这一节内容。

  • 打开 VS(2017)
  • 新建项目
  • ASP.NET Core Web 应用程序
  • Web应用程序(模型视图控制器)
  • 打开 Startup.cs ,在 ConfigureServices 中,加上
1
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); //先不用管这个是干嘛的

  •  打开 HomeController.cs ,在顶部 using Microsoft.AspNetCore.Http; 把 HomeController 类替换成以下代码
    复制代码
      public class HomeController : Controller
        {
            private IHttpContextAccessor _accessor;
            public HomeController(IHttpContextAccessor accessor)
            {
                _accessor = accessor;
            }
            [HttpGet]
            public IActionResult Index(int? id)
            {
                var httpcontext = _accessor.HttpContext;
    
                return View(httpcontext);
            }
    
        }
    复制代码

     

  • 打开 Views/Home 目录,删除除 Index.cshtml 外的其它视图
  • 把 Index.cshtml 的代码改成
@model Microsoft.AspNetCore.Http.HttpContext
@{
    Layout = null;
}

到这里,准备已经完成。

以上代码的作用是把 HttpContext 对象 传递到 视图 中,直接在视图中使用。这样我们在理解时,只需在视图测试即可。


 HttpContext 类型的属性和方法

在 ASP.NET Core 中,系统为每一个请求分配一个线程,HttpContext 针对的,就是一个线程。所以它的类、方法、属性等,都是针对当前请求起作用。

 

Properties(特性)

Authentication                这个已经用不到了,这里只是列一下表。

用于身份认证(ASP.NET中用到),官方不建议在ASP.NT Core中使用。替代方案 Microsoft.AspNetCore.Authentication.AuthenticationHttpContextExtensions

Connection 获取有关此请求的基础连接的信息
Features 获取此请求上可用的服务器和中间件提供的HTTP特性的集合
Items 获取或设置可用于在该请求范围内共享数据的键/值集合
Request 请求
RequestAborted 通知此请求基础的连接何时中止,因此请求操作应取消
RequestServices 获取或设置 IServiceProvider 集合,提供访问的请求的服务容器
Response 响应
Session 获取或设置用于管理此请求的用户会话数据的对象
TraceIdentifier 获取或设置用于在跟踪日志中表示此请求的唯一标识符
User 获取或设置此请求的用户
WebSockets 获取一个对象,该对象管理此请求的WebSu套连接的建立

Item、Session、Response 等对象都是需要经常使用到的,下面笔者会详细实践。

 


HttpContext 对象实践与测试

Request

用于获取用户请求的对象,浏览器向Web程序提交表单、访问的URL、URL中包含的查询字符串、报文请求头等等。

Body 获取或设置 RequestBody 流
ContentLength 获取或设置 Content-Length 头
ContentType 获取或设置Content-Type 头
Cookies 获取或设置 Cookies
Form 获取或设置 表单内容
HasFormContentType      Checks the Content-Type header for form types.
Headers Gets the request headers.
Host 获取或设置主机头。可以包括端口
HttpContext 获取或设置请求上下文
IsHttps 检测当前是否HTTPS连接
Method 获取或设置HTTP方法
Path 获取或设置当前请求的路径,即URL
PathBase 获取或设置 RequestPathBase,就是URL前面那一段,如https://docs.microsoft.com
Protocol Gets or sets the RequestProtocol.
Query 查询字符串的集合
QueryString 获取或设置用于在Request.Query中创建查询集合的原始查询字符串
Scheme 获取或设置HTTP请求方案

试一试

打开 Index.Cshtml ,把以下代码加上去

(为了看得清楚一点,我加了表格)

复制代码
<table>
    <tr>
        <td>RequestBody流</td>
        <td> @Model.Request.Body</td>
    </tr>
    <tr>
        <td>Content-Length头</td>
        <td>@Model.Request.ContentLength</td>
    </tr>
    <tr>
        <td>Content-Type头</td>
        <td> @Model.Request.ContentType</td>
    <tr>
        <td>Cookies </td>
        <td>@Model.Request.Cookies</td>
        </tr>
    <tr>
        <td>IsHttps</td>
        <td>@Model.Request.IsHttps</td>
        </tr>
    <tr>
        <td>Host </td>
        <td>@Model.Request.Host</td>
    </tr>

</table>
复制代码

运行Web程序,结果如下

在浏览器 F12 后,可以看到控制台的内容。请查看 下图的 1、3部分

 

 

Request 的其它使用方法,就不再赘述,你可以在视图中 @Model.Request. 加上需要测试的属性即可。

推荐别人关于 Request 的文章 https://www.cnblogs.com/Sea1ee/p/7240943.html


Response

Request 是 客户端向 Web 发送请求,而 Response 则是 Web 响应 客户端 的请求。这里笔者就不全部翻译了

使用Response可以直接影响服务器响应,设置响应内容、响应类型(发送网页、文件、图片等)、视图响应前重定向。

Response 应该在控制器中使用。具体使用方法笔者这里就不赘述。

Body 获取或设置响应体流
ContentLength      Gets or sets the value for the Content-Type response header.
ContentType 获取或设置内容类型响应标头的值
Cookies 获取一个对象,该对象可用于管理此响应的Cookie
HasStarted Gets a value indicating whether response headers have been sent to the client.
Headers Gets the response headers.
HttpContext Gets the HttpContext for this response.
StatusCode Gets or sets the HTTP response code.

Response 的方法

     OnCompleted(Func<Task>)
在响应已发送到客户端之后添加要调用的委托
     OnCompleted(Func<Object,Task>, Object)           响应已发送到客户端之后添加要调用的委托
     OnStarting(Func<Task>) 在响应头将被发送到客户端之前添加要调用的委托
     OnStarting(Func<Object,Task>, Object) 在响应头将被发送到客户端之前添加要调用的委托
     Redirect(String) 向客户端返回一个临时重定向响应(HTTP 302)
     Redirect(String, Boolean) 向客户端返回重定向响应(HTTP 301或HTTP 302)
     RegisterForDispose(IDisposable) 处置(不可分)在请求完成处理后,注册主机处理的对象

Response 拓展方法

GetTypedHeaders(HttpResponse)
WriteAsync(HttpResponse, String, Encoding, CancellationToken) 取消令牌使用给定的编码将给定文本写入响应体
WriteAsync(HttpResponse, String, CancellationToken) 将给定文本写入响应体。UTF-8编码将被使用
Clear(HttpResponse)
SendFileAsync(HttpResponse, IFileInfo, Int64, Nullable<Int64>, CancellationToken)      使用Sendfile 扩展发送给定的文件
SendFileAsync(HttpResponse, IFileInfo, CancellationToken) Sends the given file using the SendFile extension.
SendFileAsync(HttpResponse, String, Int64, Nullable<Int64>, CancellationToken) Sends the given file using the SendFile extension.
SendFileAsync(HttpResponse, String, CancellationToken) Sends the given file using the SendFile extension.

请参考下图的第 2 部分

 


Item

如果你使用过 ViewData,就不难理解 HttpContext.Item

HttpContext.Item 是一个字典集合类型,具体类型为 IDictionary<TModel,TModel>。它的使用方法像 ViewData。(不要跟我说说你不知道 ViewBag、ViewData 是什么~)

打开 Index.Cshtml ,用下面代码复制替换

复制代码
@model Microsoft.AspNetCore.Http.HttpContext
@{
    Layout = null;
}
@{
    List<string> i = new List<string>();
    i.Add("a");
    i.Add("b");
    i.Add("c");
    i.Add("d");
    i.Add("e");
    i.Add("f");
    i.Add("g");
    i.Add("h");
    i.Add("i");

    Model.Items["Test"] = i;       
    /*
        Model.Items 是字典类型
        这里设置 键 Test
                 值 i ,它的值是 List<string> 类型
    */

foreach(var item in Model.Items["Test"] as List<string>) //字典类型,必须先用 as 转为对应类型
{
    <br> @item
    
}
}
复制代码

结果

可以用 HttpContext.Item  来存储当前请求的意向有用的数据。


HttpContext 的其它方法使用这里不再赘述,需要注意的是,HttpContext 是针对一个请求的而产生的。

uni-app发布 h5 与ASP .NET MVC 后台 发布 到 IIS的同一端口 并配置跨域_uniapp发布h5部署iis-CSDN博客

mikel阅读(166)

来源: uni-app发布 h5 与ASP .NET MVC 后台 发布 到 IIS的同一端口 并配置跨域_uniapp发布h5部署iis-CSDN博客

iis 安装URL重写

在这里插入图片描述

选择对应的后台项目,进行url重写

编辑【模式】部分的内容的重写规则,我这里是h5中请求的前缀是api,大家可以根据自己的前缀进行修改。
编写【操作类型】为重写,并写重写url,按照图中设置即可。
在这里插入图片描述

uni-app web发布配置

在这里插入图片描述

在这里插入图片描述

uni-app项目打包成H5部署到服务器(超详细步骤)_uni-app unpackage-CSDN博客

mikel阅读(182)

来源: uni-app项目打包成H5部署到服务器(超详细步骤)_uni-app unpackage-CSDN博客

咳咳, 第一次写博客, 有点激动, 昨天get了一个新技能, 也是我之前一直最不懂的一块, 就是项目做完后如何部署到服务器,昨天尝试了部署uni-app项目到测试服务器, 成功之后很开心, 后面又自己上网学了下怎么部署vue项目, 所以这篇会讲怎么部署uni-app项目, 下一篇讲怎么部署vue项目, 好, 上操作

一 ,打包项目
HBuilderX下载地址: https://www.dcloud.io/hbuilderx.html

1 , HBuilderX打开你的uni-app项目 — > 点发行 – > 网站 – PC Web或手机H5

 

2 , 点完之后会弹出一个框, 填写网站标题和和域名之后点发行

 

3 , 点完之后控制台会显示正在编译中… , 稍等一会

 

4, 打包成功 , 生成了unpackage文件夹, 打包好的文件存放在里面

 

二 , 用一个工具, 把打包好的文件上传到你的服务器 , 我用的是Xftp , 用别的工具也可以
Xftp下载链接:https://pan.baidu.com/s/1z7-AYhinrWR3qIuZTkk0XQ
提取码:cn6m

 

1, 打开Xftp , 点小窗口的新建

 

2 , 点完之后弹出这个框, 填写完信息之后点连接 , 服务器的相关信息问公司的人要

 

3 , 点完连接之后 , 弹出这个框 , 点接受并保存

 

4 , 然后会看到右侧出现了新建会话的窗口 , 表示连接到服务器了,

左侧是你自己的电脑本地 , 右侧是服务器电脑

左侧进到刚刚打包好的文件存放路径 , unpackage/dist/build/h5 , 把static文件夹和index.html 复制到右侧服务器中部署的文件夹里 , 看你们是部署到哪个文件夹就拖到哪里

 

5 , 部署成功 !! 打开浏览器,输入服务器ip地址,访问一首页的内容吧 ^_^

地址就是 服务器ip/部署的文件夹/ , 比如 服务器ip是123.60.120.40:3006 ,部署的文件夹名字是project , 地址就是如下

http://123.60.120.40:3006/project/
————————————————

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/weixin_49577940/article/details/118058899

uView 2.0版本 http请求封装_uni.$u.route-CSDN博客

mikel阅读(119)

来源: uView 2.0版本 http请求封装_uni.$u.route-CSDN博客

config/config.js写入

// 此vm参数为页面的实例,可以通过它引用vuex中的变量
module.exports = (vm) => {
	// 初始化请求配置
	uni.$u.http.setConfig((config) => {
		/* config 为默认全局配置*/
		config.baseURL = ''; /* 根域名 */
		return config
	})

	// 请求拦截
	uni.$u.http.interceptors.request.use((config) => { // 可使用async await 做异步操作
		// 初始化请求拦截器时,会执行此方法,此时data为undefined,赋予默认{}
		config.data = config.data || {}
		config.header['Content-Type'] = 'application/x-www-form-urlencoded'
		// console.log(uni.getStorageSync('storage_key'))
		// 根据custom参数中配置的是否需要token,添加对应的请求头
		if (uni.getStorageSync('storage_key')) {
			// 可以在此通过vm引用vuex中的变量,具体值在vm.$store.state中
			config.header.token = uni.getStorageSync('storage_key').token.token
		}
		return config
	}, config => { // 可使用async await 做异步操作
		return Promise.reject(config)
	})

	// 响应拦截
	uni.$u.http.interceptors.response.use((response) => {
		/* 对响应成功做点什么 可使用async await 做异步操作*/
		const data = response.data
		console.log(response.statusCode)
		// 自定义参数
		// const custom = response.config?.custom
		if (data.code != 1) {
			// 如果没有显式定义custom的toast参数为false的话,默认对报错进行toast弹出提示
			if (data.msg) {
				uni.$u.toast(data.msg)
			}
			// // 如果需要catch返回,则进行reject
			// if (custom?.catch) {
			// 	return Promise.reject(data)
			// } else {
			// 	// 否则返回一个pending中的promise,请求不会进入catch中
			// 	return new Promise(() => {})
			// }
			
		}
		return data === undefined ? {} : data
	}, (response) => {
		// 对响应错误做点什么 (statusCode !== 200)
		if(response.statusCode==401){
			uni.$u.route('/pages/jy_Sign/jy_Sign')
		}
		return Promise.reject(response)
	})
}

config/api.js封装

const http = uni.$u.http
import qs from 'qs'
export const restlist = (params, config = {}) => http.post('/api/ebook/restlist', qs.stringify(params), config)

引入配置

main.js引入

// 引入请求封装,将app参数传递到配置中
require('./config/request.js')(app)
app.$mount()
使用
import {
		restlist
	} from '../../config/api.js'
	
	getdata() {
				var that = this;
				that.page = 1;
				this.status='loading'
				var data = {
					page: this.page,
					keywords: this.selected,
				};
				restlist(data).then(res => {
					this.status='loadmore'
					if (res.code == 1) {
						that.list = res.data
					} else {
						uni.showToast({
							title: res.msg,
							icon: 'none',
							duration: 2000
						});
					}
				}).catch(err => {

				})
			},
			getmore() {
				var that = this;
				that.page = that.page + 1;
				that.status = 'loading';
				let data = {
					page: this.page,
					keywords: this.selected,
				};
				restlist(data).then(res => {
					var data = res.data;
					if (!data || data.length == 0) {
						that.status = 'nomore';
					}
					for (var i = 0; i < data.length; i++) {
						that.list.push(data[i]);
					}
				}).catch(err => {

				})
			},

request

// 此vm参数为页面的实例,可以通过它引用vuex中的变量
import configs from './config.js'
import {
	fungoPreviousPage
} from "@/utils/util.js"
module.exports = (vm) => {
	// 初始化请求配置
	uni.$u.http.setConfig((config) => {
		/* config 为默认全局配置*/
		config.baseURL = configs.baseUrl; /* 根域名 */
		return config
	})

	// 请求拦截
	uni.$u.http.interceptors.request.use((config) => { // 可使用async await 做异步操作
		config.header['Content-Type'] = 'application/json'
		config.data = config.data || {}

		// 根据custom参数中配置的是否需要token,添加对应的请求头
		config.header['cookie'] = uni.getStorageSync('cookie')
		// if (config?.custom?.auth) {
		// 	if (uni.getStorageSync('cookie')) {
		// 		// 可以在此通过vm引用vuex中的变量,具体值在vm.$store.state中
		// 	} else {
		// 		uni.redirectTo({
		// 			url: '/pages/login/wxlogin'
		// 		})
		// 	}
		// }
		return config
	}, config => { // 可使用async await 做异步操作
		return Promise.reject(config)
	})

	// 响应拦截
	uni.$u.http.interceptors.response.use((response) => {
		/* 对响应成功做点什么 可使用async await 做异步操作*/
		const data = response.data
		if (response.header['Set-Cookie']) {
			// Set-Cookie字符串获取
			var cookies = response.header['Set-Cookie']
			// 字符串分割成数组
			var cookieArray = cookies.split(/,(?=[^,]*=)/)
			// 分号拼接数组
			var newCookie = cookieArray.join(';')
			uni.setStorageSync('cookie', newCookie)
		}
		// 自定义参数
		// const custom = response.config?.custom
		if (data.code != 200) {
			// 如果没有显式定义custom的toast参数为false的话,默认对报错进行toast弹出提示
			if (data.message) {
				uni.$u.toast(data.message)
			}

			if (data.code == 401) {
				// uni.clearStorageSync()
				fungoPreviousPage()
				uni.$u.route('/pages/login/wxlogin')
			}
			if (data.code == 602) {
				// uni.clearStorageSync()
				fungoPreviousPage()
				uni.$u.route('/pages/login/wxlogin')
			}
		}
		return data === undefined ? {} : data
	}, (response) => {
		// 对响应错误做点什么 (statusCode !== 200)
		if (response.statusCode == 401) {
			fungoPreviousPage()
			uni.$u.route('/pages/login/wxlogin')
		}
		return Promise.reject(response)
	})
}

uni-app.02.提交form表单的两种方式_uniapp form表单提交-CSDN博客

mikel阅读(141)

来源: uni-app.02.提交form表单的两种方式_uniapp form表单提交-CSDN博客

uni-app提交form表单的两种方式
form表单元素较少
比如用户登录,如下图
前端代码举例
此处省略了部分多余代码
<template>
<view style=”padding:50rpx;”>
<view style=”margin-top:60rpx;”>
<form @submit=”submit”>
<view class=”gui-border-b gui-form-item” style=”margin-top:80rpx;”>
<view class=”gui-form-body”>
<input type=”number” class=”gui-form-input” v-model=”driverTel” name=”driverTel” placeholder=”手机号” placeholder-style=”color:#CACED0″/>
</view>
</view>
<view class=”gui-border-b gui-form-item” style=”margin-top:30rpx;”>
<view class=”gui-form-body”>
<input type=”password” class=”gui-form-input” v-if=”isPwd”
v-model=”password” name=”password” placeholder=”密码” placeholder-style=”color:#CACED0″/>
<input type=”text” class=”gui-form-input” v-if=”!isPwd” :disabled=”true”
v-model=”password” name=”password” placeholder=”密码” placeholder-style=”color:#CACED0″/>
</view>
<text class=”gui-form-icon gui-icons gui-text-center”
@click=”changePwdType” :style=”{color:isPwd?’#999999′:’#008AFF’}”>&#xe609;</text>
</view>
<view style=”margin-top:50rpx;”>
<button type=”default” class=”gui-button gui-bg-blue msgBtn” formType=”submit” style=”border-radius:50rpx;”>
<text class=”gui-color-white gui-button-text-max”>登录</text>
</button>
</view>
</form>
</view>
</view>
</template>
<script>
uni.request({
url: _self.server_host + “/app/driver/login/password”,
method:’POST’,
header:{‘content-type’ : “application/x-www-form-urlencoded”},
data:{
// 对于上面的form表单提交,我们可以直接在uni.request的data属性中直接提交就行了
driverTel: _self.driverTel,
password: _self.password
},
success: (res) => {
// 服务器返回结果
}
})
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
后端代码举例
/**
* 这里可以以一个实体类来接收,实体类必须包含前端传参参数的对应字段
*/
@PostMapping(“/password”)
public Result loginByPassword(LoginUserVO loginUserVO) {
// 处理业务逻辑
}
/**
* 也可以按照字段名来接收
*/
@PostMapping(“/password”)
public Result loginByPassword(String username, String passsword) {
// 处理业务逻辑
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
form表单元素较多
上面的方法在form表单元素较多时处理起来就比较费事了,一般像新增用户、商品之类的form表单少则十几个,多则几十个。如下图:
如果按照上面的写法,不仅前端写起来费事不雅观,后台接受也要一个字段一个字段的接收也煞是费劲,这个时候我们可以定义一个对象formData,将数据保存到里面提交时直接提交JSON字符串到后端,后端接收到JSON字符串后转成JSON对象,然后再进行自己的业务逻辑处理
前端代码举例:
<!– 表单元素核心区域 –>
<scroll-view :scroll-y=”true” :show-scrollbar=”false” :style=”{height:mainHeight+’px’}”>
<!– 第1步 –>
<view class=”gui-padding” v-if=”step == 1″>
<view class=”gui-form-item gui-border-b”>
<text class=”gui-form-label”>所属客户</text>
<view class=”gui-form-body”>
<picker mode=”selector” :range=”tenantList” :value=”tenantIndex” @change=”tenantChange($event,tenantList)” :range-key=”‘tenantName'”>
<view class=”gui-flex gui-rows gui-nowrap gui-space-between gui-align-items-center”>
<text class=”gui-text”>{{tenantList[tenantIndex].tenantName}}</text>
<text class=”gui-form-icon gui-icons gui-text-center gui-color-gray”>&#xe603;</text>
</view>
</picker>
</view>
</view>
<view class=”gui-form-item gui-margin-top gui-border-b”>
<text class=”gui-form-label”>姓名</text>
<view class=”gui-form-body”>
<input type=”text” class=”gui-form-input” v-model=”formData.driverName” placeholder=”请输入姓名” />
</view>
</view>
<view class=”gui-form-item gui-margin-top gui-border-b”>
<text class=”gui-form-label”>手机号</text>
<view class=”gui-form-body”>
<input type=”text” class=”gui-form-input” v-model=”formData.driverTel” placeholder=”请输入手机号” />
</view>
</view>
<view class=”gui-form-item gui-margin-top gui-border-b”>
<text class=”gui-form-label”>身份证号码</text>
<view class=”gui-form-body”>
<input type=”text” class=”gui-form-input” v-model=”formData.idNumber” placeholder=”请输入身份证号码” />
</view>
</view>
<view class=”gui-margin-top”>
<text class=”gui-form-label” style=”width: 100%;”>身份证照片(个人信息面)</text>
</view>
<view class=”gui-idcard-items gui-img-in gui-flex gui-rows gui-justify-content-center”>
<view class=”gui-idcard-items-image” @tap=”selectIdPhotoPositive”>
<gui-image :src=”formData.idPhotoPositive” :width=”380″></gui-image>
</view>
</view>
<view class=”gui-margin-top”>
<text class=”gui-form-label” style=”width: 100%;”>身份证照片(国徽图案面)</text>
</view>
<view class=”gui-idcard-items gui-img-in gui-flex gui-rows gui-justify-content-center”>
<view class=”gui-idcard-items-image” @tap=”selectIdPhotoReverse”>
<gui-image :src=”formData.idPhotoReverse” :width=”380″></gui-image>
</view>
</view>
<view class=”gui-form-item gui-margin-top gui-border-b”>
<text class=”gui-form-label”>证件有效期</text>
<view class=”gui-form-body”>
<picker class=”gui-form-picker” mode=”date” @change=”idNumberValidUntilChange”>
<text class=”gui-text”>{{formData.idNumberValidUntil}}</text>
<text class=”gui-icons icon-arrow-down” style=”margin-left:5px;”></text>
</picker>
</view>
</view>
<view class=”gui-form-item gui-border-b”>
<text class=”gui-form-label”>收款人</text>
<view class=”gui-form-body”>
<picker mode=”selector” :range=”payeeList” :value=”payeeIndex” @change=”payeeChange($event,payeeList)” :range-key=”‘payeeName'”>
<view class=”gui-flex gui-rows gui-nowrap gui-space-between gui-align-items-center”>
<text class=”gui-text”>{{payeeList[payeeIndex].payeeName}}</text>
<text class=”gui-form-icon gui-icons gui-text-center gui-color-gray”>&#xe603;</text>
</view>
</picker>
</view>
</view>
</view>
<!– 第2步 –>
<view class=”gui-padding” v-if=”step == 2″>
<view class=”gui-form-item gui-margin-top gui-border-b”>
<text class=”gui-form-label”>驾驶证编号</text>
<view class=”gui-form-body”>
<input type=”text” class=”gui-form-input” v-model=”formData.drivingLicenseNumber” placeholder=”请输入驾驶证编号” />
</view>
</view>
<view class=”gui-margin-top”>
<text class=”gui-form-label” style=”width: 100%;”>驾驶证(主页)</text>
</view>
<view class=”gui-idcard-items gui-img-in gui-flex gui-rows gui-justify-content-center”>
<view class=”gui-idcard-items-image” @tap=”selectDrivingLicensePhoto”>
<gui-image :src=”formData.drivingLicensePhoto” :width=”380″></gui-image>
</view>
</view>
<view class=”gui-form-item gui-margin-top gui-border-b”>
<text class=”gui-form-label”>有效期开始</text>
<view class=”gui-form-body”>
<picker class=”gui-form-picker” mode=”date” @change=”drivingLicenseValidityStartChange”>
<text class=”gui-text”>{{formData.drivingLicenseValidityStart}}</text>
<text class=”gui-icons icon-arrow-down” style=”margin-left:5px;”></text>
</picker>
</view>
</view>
<view class=”gui-form-item gui-margin-top gui-border-b”>
<text class=”gui-form-label”>有效期结束</text>
<view class=”gui-form-body”>
<picker class=”gui-form-picker” mode=”date” @change=”drivingLicenseValidityEndChange”>
<text class=”gui-text”>{{formData.drivingLicenseValidityEnd}}</text>
<text class=”gui-icons icon-arrow-down” style=”margin-left:5px;”></text>
</picker>
</view>
</view>
<view class=”gui-form-item gui-margin-top gui-border-b”>
<text class=”gui-form-label”>发证机关</text>
<view class=”gui-form-body”>
<input type=”text” class=”gui-form-input” v-model=”formData.drivingLicenseIssuingOrg” placeholder=”请输入驾驶证发证机关” />
</view>
</view>
<view class=”gui-form-item gui-border-b”>
<text class=”gui-form-label”>准驾车型</text>
<view class=”gui-form-body”>
<picker mode=”selector” :range=”vehicleTypeList” :value=”vehicleTypeIndex” @change=”vehicleTypeChange($event,vehicleTypeList)” :range-key=”‘codeSetName'”>
<view class=”gui-flex gui-rows gui-nowrap gui-space-between gui-align-items-center”>
<text class=”gui-text”>{{vehicleTypeList[vehicleTypeIndex].codeSetName}}</text>
<text class=”gui-form-icon gui-icons gui-text-center gui-color-gray”>&#xe603;</text>
</view>
</picker>
</view>
</view>
<view class=”gui-form-item gui-border-b”>
<text class=”gui-form-label”>关联车辆</text>
<view class=”gui-form-body”>
<picker mode=”selector” :range=”vehicleList” :value=”vehicleIndex” @change=”vehicleChange($event,vehicleList)” :range-key=”‘carNumber'”>
<view class=”gui-flex gui-rows gui-nowrap gui-space-between gui-align-items-center”>
<text class=”gui-text”>{{vehicleList[vehicleIndex].carNumber}}</text>
<text class=”gui-form-icon gui-icons gui-text-center gui-color-gray”>&#xe603;</text>
</view>
</picker>
</view>
</view>
</view>
<!– 第3步 –>
<view class=”gui-padding” v-if=”step == 3″>
<view class=”gui-form-item gui-margin-top gui-border-b”>
<text class=”gui-form-label”>资格证号码</text>
<view class=”gui-form-body”>
<input type=”text” class=”gui-form-input” v-model=”formData.roadTransportQualificationCertificateNumber” placeholder=”请输入从业资格证编号” />
</view>
</view>
<view class=”gui-margin-top”>
<text class=”gui-form-label” style=”width: 100%;”>从业资格证</text>
</view>
<view class=”gui-idcard-items gui-img-in gui-flex gui-rows gui-justify-content-center”>
<view class=”gui-idcard-items-image” @tap=”selectRoadTransportQualificationCertificatePhoto”>
<gui-image :src=”formData.roadTransportQualificationCertificatePhoto” :width=”380″></gui-image>
</view>
</view>
<view class=”gui-form-item gui-margin-top gui-border-b”>
<text class=”gui-form-label”>证件有效期</text>
<view class=”gui-form-body”>
<picker class=”gui-form-picker” mode=”date” @change=”roadTransportQualificationCertificateValidUntilChange”>
<text class=”gui-text”>{{formData.roadTransportQualificationCertificateValidUntil}}</text>
<text class=”gui-icons icon-arrow-down” style=”margin-left:5px;”></text>
</picker>
</view>
</view>
</view>
</scroll-view>
<script>
export default {
data() {
return {
// 表单数据记录
formData: {
// 第一步
tenantId: ”,// 所属客户
payeeId: ”,// 收款人
driverName: ”,// 司机姓名
driverTel: ”,// 司机电话
idNumber: ”,// 身份证号码
idNumberValidUntil:’请选择证件有效期’,// 身份证有效期
idPhotoPositive: ‘https://www.zzwlnet.com/files/images/upload_identity_card_front.png’,// 身份证正面(个人信息面)
idPhotoReverse: ‘https://www.zzwlnet.com/files/images/upload_identity_card_contrary.png’,// 身份证反面(国徽面)
// 第二步
drivingLicenseNumber: ”,// 驾驶证编号
drivingLicensePhoto: ‘https://www.zzwlnet.com/files/images/upload_driving_license.png’,// 驾驶证图片
drivingLicenseValidityStart: ‘请选择证件有效期开始时间’, // 驾驶证有效期开始
drivingLicenseValidityEnd: ‘请选择证件有效期结束时间’,// 驾驶证有效期结束
drivingLicenseIssuingOrg: ”,// 驾驶证发证机关
quasiDrivingType: ”,// 准驾车型
vehicleId: ”,// 关联车辆
// 第三步
roadTransportQualificationCertificateNumber: ”,// 从业资格证号
roadTransportQualificationCertificatePhoto: ‘https://www.zzwlnet.com/files/images/upload_road_transport_qualification_certificate.png’,// 从业资格证图片
roadTransportQualificationCertificateValidUntil: ‘请选择证件有效期’,// 从业资格证有效期
},
}
},
methods: {
submit: function() {
uni.request({
url: _self.server_host + ‘/api’,
method: ‘POST’,
header: {‘content-type’ : “application/x-www-form-urlencoded”},
data: {
// 传参方式一:以JSON字符串的形式提交form表单数据
formData: JSON.stringify(_self.formData),
// 传参方式二:将form表单数据以对象形式传递
// formData: _self.formData,
},
success: res => {
// 服务器返回数据,后续业务逻辑处理
},
fail: () => {
uni.showToast({ title: “服务器响应失败,请稍后再试!”, icon : “none”});
},
complete: () => {}
});
}
}
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
后端java代码举例
// 针对传参方式一:后台以String的方式接收
public Result add(String formData){
// 将JSON字符串转换成JSONObject
JSONObject jsonObject= JSONObject.parSEObject(formData);
// 继续后续业务逻辑处理
return Results.success();
}
// 针对传参方式二:后台以Object的方式接收
public Result add(Object driverObj){
// 继续后续业务逻辑处理
return Results.success();
}
————————————————
                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/bbxylqf126com/article/details/114951576

uni-app的H5版使用注意事项 - DCloud问答

mikel阅读(172)

来源: uni-app的H5版使用注意事项 – DCloud问答

uni-app x的web版运行注意事项,另见https://doc.dcloud.net.cn/uni-app-x/web/

HBuilderX 1.2开始包含了uni-app的web平台支持。

使用方式

  1. 打开uni-app项目下的vue文件
  2. 点击菜单 运行->运行到浏览器->Chrome
  3. 在Chrome內打开调试模式(右键->检查)开启设备模拟,模拟移动设备(如果UI变形刷新即可)
  4. HBuilderX修改代码后会自动刷新chrome的页面
  5. 审查元素

    在chrome控制台安装vue devtools后可查看节点关系。
    安装方式自行搜索。
    每个页面都在page节点下,pageHead是微信和app下的原生导航栏,即pages.json里配的导航栏。
    pageBody是导航栏下的页面内容。
    所有标签为了避免和标准H5标签冲突,都加了U前缀。

  6. 断点Debug
    点chrome控制台的source,可以给js打断点调试。
    找到同名的文件,如果没有同名vue文件,一般会有一个同文件名的js文件,此时会提示检测到sourcemap,是否引入,点允许。然后就会有同名的vue文件。如果找不到,则把焦点放到source的代码区,然后敲ctrl+p打开文件查找窗口,然后敲入vue页面名字,然后打开vue页面。
    这个vue里,只有js,没有tag和css,但可以打断点调试。

发布方式

  1. 配置发行后的路径(发行在网站根目录可不配置),比如发行网站路径是www.xxx.com/html5,在manifest.json可视化界面 – H5配置 – 运行的基础路径中设置,也可以在源码视图内编辑h5节点,router下增加base属性为html5。
    可视化界面设置:

    源码视图设置:

  2. 点击菜单 发行->H5
  3. 在当下项目下的unpackage/dist/build/h5目录找到出的资源,部署服务器(或者使用本地服务器预览,不要直接在浏览器打开html文件)。如果发布使用的history模式,需要服务端配合,参考:后端配置方式

跨端注意

uni-app由uni的通用api和平台专有api组成,H5版也不例外。可以使用uni的通用api完成很多工作,也可以在条件编译里调用H5版的浏览器专有api。
虽然dom、window都可以用了,但如果要跨端,还是少写这样的代码好。
H5仍应该使用pages.json管理页面,强烈不建议使用浏览器的跳转页面的api。
H5的条件编译写法是把之前的app-plus换成H5。敲ifdef会有代码助手提示。

复制代码//#ifdef H5  
this.titleHeight = 44  
//#endif

条件编译目前有7个平台,APP-PLUS、APP-PLUS-NVUE、MP-WEIXIN、H5、MP、MP-BAIDU、MP-ALIPAY。
其中APP-PLUS-NVUE是APP-PLUS的子集,用于weex下单独写专用代码。
为了方便多平台选择,还引入了~#ifndef~,也就是ifdef的not,反向选择。以及或语法,及||。这些命名都是c语言条件编译的标准命名。

复制代码// #ifndef H5  
console.log("这段代码编译到非H5平台");  
// #endif

开发者之前为微信或app写的代码,H5的平台不支持时,需要注意把这些代码放到条件编译里。
经过这样的处理,之前做好的App或小程序才能正常运行到H5版里。

小程序版在UI上,尤其是导航栏上限制较多,H5在这里是参考了app,默认解析了pages.json下的app-plus的节点,实现了titleNView、buttons、下拉刷新(下拉刷新只有circle方式,因为只有这样的下拉刷新在H5版上可以保障流畅体验)

组件和API支持情况

目前的H5版,还没有100%实现uni的所有api,但大部分已经完成,具体参考uniapp文档。

第三方组件支持

  • 支持mpvue组件
  • 支持普通vue组件(仅H5平台)
  • 支持微信小程序组件(HBuilderX2.5.0+开始支持编译到H5)
  • 支持nvue

vue语法支持

H5版支持完整的vue语法,同时校验器也校验了更严格的vue语法,有些写法不规范会报警。比如data后面写对象会报警,必须写function。

注意事项(必看)

  • 编译为H5版后生成的是单页应用,SPA。如果想要SEO优化,首页可以在template模板中配置keyword。二级页不支持配置。但一个更酷的方式是用uni-app直接发布一版百度小程序,搜索权重更高。
  • 编译后看日志和错误,要看浏览器的控制台,而不是HBuilderX的控制台。浏览器的控制台会有错误提示。
  • 网络请求(request、uploadFile、downloadFile等)在浏览器存在跨域限制(CORS、Cross-Origin),解决方案详见:https://ask.dcloud.net.cn/article/35267
  • APP 和微信的原生导航栏和tabbar下,元素区域坐标是不包含原生导航栏和tabbar的。而 H5 里原生导航栏和tabbar是 div 模拟实现的,所以元素坐标会包含导航栏和tabbar的高度。为了优雅的解决多端高度定位问题,uni-app新增了2个css变量:–window-top和–window-bottom,这代表了页面的内容区域距离顶部和底部的距离。举个实例,如果你想在原生tabbar上方悬浮一个菜单,之前写bottom:0。这样的写法编译到h5后,这个菜单会和tabbar重叠,位于屏幕底部。而改为使用bottom:var(–window-bottom),则不管在app下还是在h5下,这个菜单都是悬浮在tabbar上浮的。这就避免了写条件编译代码。当然你也仍然可以使用 H5 的条件编译处理界面的不同。
  • CSS內使用vh单位的时候注意100vh包含导航栏,使用时需要减去导航栏和tabBar高度,部分浏览器还包含浏览器操作栏高度,使用时请注意。
  • event 对象上使用的 mpvue 独有的属性需调整(比如 event.pageY,可能需要加上44px的导航栏高度)。
  • fixed定位的组件有可能遮挡框架内置UI组件,如果不希望遮挡可以分平台判断,在H5平台避开内置UI。
  • 正常支持rpx。px是真实物理像素。暂不支持通过设manifest的”transformPx” : true,把px当动态单位使用。
  • 使用罗盘、地理位置、加速计等相关接口需要使用https协议,本地预览(localhost)可以使用 http 协议。
  • PC 端 Chrome 浏览器模拟器设备测试的时候,获取定位 API 需要连接谷歌服务器,需要翻墙。
  • 组件内(页面除外)不支持onLoad生命周期。
  • 为避免和内置组件冲突,自定义组件请加上前缀(但不能是u和uni)。比如可使用的自定义组件名称:my-view、m-input、we-icon,例如不可使用的自定义组件名称:u-view、uni-input。如果已有项目使用了可能造成冲突的名称,请修改名称。另外微信小程序下自定义组件名称不能以wx开头。
  • 在tabBar页面,如果page高度设置为100%时,页面超出滚动会导致底部被tabbar遮挡,可在tabbar页面去掉height:100%或者改用min-height:100%。
  • 编写组件时需要遵守vue的规范,之前在app端和小程序端能使用的一些不规范写法需要纠正,比如:不要修改props的值、组件最外层template节点下不允许包含多个节点。
  • 开发App时,不可在H5预览后直接云打包。需在HBuilderX里点运行-选择运行到手机,真机调试无误后再打包。
  • H5端 “网络不给力” 原因及解决办法:https://ask.dcloud.net.cn/article/37065。

相关

uni-app编译H5底层技术解析:https://juejin.im/post/5c1b0d715188256973244377

uni-app踩坑+小改造- 掘金

mikel阅读(194)

来源: uni-app踩坑+小改造最近团队内部一直在试点用uni-app去做一些小需求,但主要是先在H5上做试点,之后再按计划编 – 掘金

背景

最近团队内部一直在试点用uni-app去做一些小需求,但主要是先在H5上做试点,之后再按计划编译成小程序去发布。这回分享几个遇到的小问题和解决方案。

下面说到的问题主要在用uni-app开发H5平台时才会遇到,非H5平台可忽略。

跨域的问题

首先,在本地开发时,不同于直接用小程序IDE进行开发,在开发H5平台时,需要使用浏览器进行调试,而浏览器会有跨域的问题。比如直接通过本地IP地址去访问开发中的页面,同时这个页面会调一些现有的接口时,就面临着跨域的问题。

官方的解决方案

uni-app官方介绍了一些解决跨域问题的方法,比如服务端开启CORS,给浏览器安装跨域插件等,详见uni-app的H5版使用注意事项。但里面并没有提到(应该是很久未更新文档导致)的是,如果不想这么麻烦去解决,还有个更方便的办法,也就是用webpack-dev-server去代理即可解决。

更方便的解决方案

根据官方文档的描述,devServer配置被要求在manifest.json去配置,并且由于这个配置文件是json格式的,所以只能对简单类型进行配置。但对于proxy这项配置来说也是足够了的。直接如下方式配置即可解决:

代码解读
复制代码
// manifest.json
{
    "h5": {
        "devServer": {
            "proxy": {
                "/prefix/api/user/list": {
                    "target": "https://api-remote.xxxx.com",
                    "pathRewrite": {
                        "^/prefix": ""
                    }
                }
            }
        }
    }
}

另一种解决方案

直接创建一个vue.config.js文件,并在里面配置devServer,直接上代码

代码解读
复制代码
// vue.config.js
module.exports = {
  devServer: {
    proxy: {
      '/prefix/api/user/list': {
        target: 'https://api-remote.xxxx.com',
        pathRewrite: {
          '^/prefix': ''
        }
      }
    },
  }
}

这种办法的好处显而易见,用js而非json去配置会更加的灵活,需要注意的是以上两种方案不能同时使用,第一种会覆盖第二种方案。

Mock的问题

这可能也不是什么大问题,毕竟现在有很多像Easy Mock这样的在线Mock平台。但有时我们可能嫌麻烦,不想离开代码编辑窗口去注册,编写在线Mock数据,更想一切都用代码解决,那么同样可以用上面的第二种方案来搞定

解决方案

借助mocker-apimockjs这两个工具,直接配置devServerbefore选项即可,代码如下:

代码解读
复制代码
// vue.config.js
const webpackApiMocker = require('mocker-api')

module.exports = {
  devServer: {
    before (app) {
      webpackApiMocker(app, path.resolve('./mock/index.js'))
    }
  }
}

// mock/index.js
const Mock = require('mockjs')

const Random = Mock.Random
const mock = Mock.mock

const proxy = {
  'GET /api/user/list': mock({
    'array|3': [
      {
        id: 1,
        username: 'kenny',
        sex: 'male'
      }
    ]
  }),
  'POST /api/login/account': (req, res) => {
    return res.json({
      status: 'ok',
      data: {
        id: Random.id(),
        userName: Random.cname(),
        city: Random.city()
      }
    })
  }
}

module.exports = proxy

publicPath的问题

到了测试阶段,我们需要将代码部署到CDN上提测,不同的环境对应不同的CDN域名,官方通过manifest.json的方式配置publicPath显然非常的不灵活,我们希望publicPath是动态的,与环境,仓库,工程名甚至开发分支有关,而且不需要开发人员去关心。

解决方案

要解决这个问题就需要对脚手架做一些小改造了。

  • 首先,我们将publicPath这项配置拿出来单独放在一个配置文件中,比如project-config.js,并放在工程根目录下
代码解读
复制代码
const projectName = 'xxx' // 当前工程名,此处自由发挥即可
const isDev = isDev() // 是否为本地开发环境,此处自由发挥即可
const CDN_HOST = process.env.CDN_HOST   // build时指定的CDN域名
const APP_ENV = process.env.APP_ENV // build时指定的自定义环境

module.exports = {
  publicPath: isDev
    ? '/'
    : `//${CDN_HOST}/static/${projectName}/${APP_ENV}/`,
}
  • 其次,我们fork了一版官方的uni-app源码,并对@dcloudio/vue-cli-plugin-uni/index.js做了点改动
代码解读
复制代码
// @dcloudio/vue-cli-plugin-uni/index.js#L30
// 获取本地的project-config配置
module.exports = (api, options) => {
    const projectConfig = require(api.resolve('project-config'))

    Object.assign(options, { 
        outputDir: process.env.UNI_OUTPUT_TMP_DIR || process.env.UNI_OUTPUT_DIR,
        assetsDir
    }, vueConfig, {
        // 重新对publicPath进行覆盖
        publicPath: process.env.NODE_ENV === 'production' ? projectConfig.publicPath : '/'
    })
}

这样会使manifest.json中的配置失效,也就是如果使用HBuilder开发的话会受到点影响。

作者:前端论道
链接:https://juejin.cn/post/6844904063855755271
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

uni-app <image>和vue中img标签动态绑定src不显示本地图片 - web_pzj - 博客园

mikel阅读(169)

来源: uni-app <image>和vue中img标签动态绑定src不显示本地图片 – web_pzj – 博客园

因为需要根据后端返回的数据渲染不同的图片,所有要对imge标签的src进行动态绑定。

以下是静态绑定时的代码,静态绑定无任何问题。

 

下方是静态绑定时的正常图片:

 

 

以下是动态绑定时的代码,但是图片无法显示。

 

无法显示效果图:

 

解决办法一:用将路径放入require()中。

 

 

解决办法二:不要使用../,改为根目录/

uniapp 中出现 Undefined variable $u-type-primary-light 问题_undefined variable: "$u-type-primary-light".-CSDN博客

mikel阅读(139)

来源: uniapp 中出现 Undefined variable $u-type-primary-light 问题_undefined variable: “$u-type-primary-light”.-CSDN博客

问题描述
uniapp 引入 uview-ui 后 一顿操作,出现 Undefined variable: “$u-type-primary-light” 错误。
解决问题
第一步:确保 HBuilder X 是安装了 scss/sass 编译插件
第二步:确保在根目录下 uni.scss 文件中引入 theme.scss,
@import “uview-ui/theme.scss”; // 放在代码首行
1
第三步:确保在根目录下 App.vue 文件中添加 lang=”scss” 和 index.scss
<style lang=”scss”>
@import “uview-ui/index.scss”;
</style>
1
2
3
问题得以解决。
————————————————
                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/weixin_49175501/article/details/118157121

uni-app 分不清的全局变量this, uni, $u, vm, uni.$u, this.$u-CSDN博客

mikel阅读(145)

来源: uni-app 分不清的全局变量this, uni, $u, vm, uni.$u, this.$u-CSDN博客

项目引入了uview,并将uview所有模块指给uniapp全局变量uni

uni.$u=$u

 

在登录页面,或者APP.vue打印以下变量:

this, uni, $u, vm, uni.$u, this.$u

// this,$u,vm,uni, this.$u, uni.$u全局变量说明
console.log(“>>this”, this)
console.log(“>>uni”, uni)
console.log(“>>this===uni”, this === uni) //false
console.log(“>>this.$u “, this.$u)
console.log(“>>uni.$u “, uni.$u)
console.log(“>>this.$u===uni.&u”, this.$u === uni.$u) //ture

try {//$u is not defined
console.log(“>>$u “, $u)
} catch (e) {
console.log(e)
}
try { //vm is not defined
console.log(“>>this.vm”, this.vm)
console.log(“>>vm “, vm)
} catch (e) {
console.log(e)
}
运行结果
$u 是uview挂载到uni上的,方便使用uni来操作uview组件。

uni. 对象是uni-app框架实例。

this. 在.vue页面,对应就是当前vue的实例对象。

this.$u 与uni.$u 在vue页面是同一对象,指向 uview

 

$u来源
uniapp-master\uview-ui\index.vue,在此vue里,通过xx.prototype.$u的方法 ,通过uni.$u方法同时挂载到全局里。

// 引入全局mixin
import mixin from ‘./libs/mixin/mixin.js’

// 防抖方法
import debounce from ‘./libs/function/debounce.js’
// 节流方法
import throttle from ‘./libs/function/throttle.js’
import {fixMoney2Decimal, formatInputMoney, toFixed2Decimal} from “@/uview-ui/libs/function/numberform”;
import {positiveNumber} from “@/uview-ui/libs/function/inputRegExp”;
//…
//…

// 配置信息
import config from ‘./libs/config/config.js’
// 各个需要fixed的地方的z-index配置文件
import zIndex from ‘./libs/config/zIndex.js’
import {timeFormatCmm} from “@/uview-ui/libs/function/timeFormatStr”;

const $u = {
queryParams: queryParams,
positiveNumber: positiveNumber,
route: route,
timeFormat: timeFormat,
date: timeFormat, // 另名date
timeFormatCmm: timeFormatCmm,
timeFrom,
colorGradient: colorGradient.colorGradient,
colorToRgba: colorGradient.colorToRgba,
guid,
color,
sys,
os,
type2icon,
randomArray,
wranning,
get: http.get,
post: http.post,
put: http.put,
‘delete’: http.delete,
hexToRgb: colorGradient.hexToRgb,
rgbToHex: colorGradient.rgbToHex,
test,
random,
deepClone,
deepMerge,
getParent,
$parent,
addUnit,
trim,
type: [‘primary’, ‘success’, ‘error’, ‘warning’, ‘info’],
http,
toast,
toastErr,
toastS,
modal,
config, // uView配置信息相关,比如版本号
zIndex,
debounce,
throttle,

//–
toFixed2Decimal,
fixMoney2Decimal,
formatInputMoney
}

// $u挂载到uni对象上
uni.$u = $u

const install = Vue => {
Vue.mixin(mixin)
if (Vue.prototype.openShare) {
Vue.mixin(mpShare);
}
// Vue.mixin(vuexStore);
// 时间格式化,同时两个名称,date和timeFormat
Vue.filter(‘timeFormat’, (timestamp, format) => {
return timeFormat(timestamp, format)
})
Vue.filter(‘date’, (timestamp, format) => {
return timeFormat(timestamp, format)
})
// 将多久以前的方法,注入到全局过滤器
Vue.filter(‘timeFrom’, (timestamp, format) => {
return timeFrom(timestamp, format)
})
Vue.prototype.$u = $u
}

export default {
install
}
————————————————

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/LlanyW/article/details/132522228