h5调用摄像头拍照可以自定义拍照页面吗_拍照墙的伪装

本文是《React 思维模式》的预览连载之一,这是我最近在写的一本小说体裁的 React 书。想知道我创作背后的心酸故事吗?点这里从头看

拍照墙有什么好玩的?用得着这么奋不顾身么?我从来都讨厌拍照,便由艾伦自拍去了。

又忙了大概半小时,小路全都加宽,这下安全了,我想。咦?艾伦怎么还没回来?自拍能玩到这么投入?我决定去看看他在拍什么写真。来到拍照墙跟前,我才发现艾伦早已不见踪影,只剩他的三脚架孤零零地立在那里,上面的照相机还在不停地工作,相片散落了一地。

又跟我玩消失?我大喊艾伦,周围却是一片寂静,除了咔嚓咔嚓的拍照声。我开始在满地的相片中翻找线索,在艾伦的各种卖萌耍酷表情中,一张相片吸引了我的注意。相片中,一只灰白色的动物回过头来面对着镜头,口中含着什么东西,挂在嘴边的仿佛是……两条人腿!那脚上穿着的分明是艾伦的阿迪达斯运动鞋!我不禁全身寒毛倒竖,抬头望见那堵灰白色的拍照墙,那是和相片中的动物一样的灰白色。我跌跌撞撞倒退几步,哆嗦着又捡起了几张相片,终于看到那惊悚的真相。原来,拍照墙是那怪物用来吸引猎物的伪装,那镂空洞口正是它的血盆大口,将可怜的艾伦囫囵吞下。

990dcaf7d5bfeae9c918a7ee77955445.png

我脑中一片空白,完了完了!怎么救艾伦?还有救吗?正在心神不定中,眼前视野中忽然出现了一行发着蓝光的字:

React 思维模型:JSX 是伪装成 HTML 的 JavaScript 代码。

哦,脑机又要给我灌知识了,但是我得去救人啊!不过,这个思维模型也许跟救人有关?我坐下来开始冥想。

JSX

吞掉艾伦的那个墙怪就住在下面这个组件里:

function App() {
  return <div>   </div>
}

其实,这个组件是一个 JavaScript 函数,并返回了一个值(return 后面的部分)。那么,这个函数到底返回了什么?

……

一个 HTML 标签?

一个字符串(string)?

一个特殊的 html-tag 值?跟 JavaScript 里的数字(number) 或者布尔值(boolean)差不多?

……

对不起,猜错了!

原来,那拍照墙并不是真正的拍照墙,混写在 React 代码里的标签也不是真正的 HTML,而是一种特殊的标签,大名叫做 JSX。这里的“JS”指的是 JavaScript,“X”有扩展(extension)的意思,也表示它跟另外一种标记语言 XML 其实更接近,不过如果你没听说过 XML 也不妨碍理解和使用 JSX。

JSX 只是伪装成 HTML 标签,其实质是 JavaScript 代码。在发送到浏览器执行之前, React 开发工具将 JSX 标签自动转换为相应的 JavaScript 代码。比如:

<div>   </div>

跟下面的代码是等效的:

_jsx("div", { children: "   " })

这里的 _jsx 是开发工具自动导入的一个函数:

import {jsx as _jsx} from 'react/jsx-runtime'

注:在 React 17 发布之前,该 JSX 标签与这个函数调用等效:React.createElement('div', {}, " &quot;)。不过,因为 React 核心团队计划将 jsx-runtime 移植到 React 17 之前的版本,所以在此我们仅讨论 _jsx 这种形式。

所以,本节开头的组件可以重写为:

import {jsx as _jsx} from 'react/jsx-runtime'
function App() {
  return _jsx("div", { children: "   " })
}

这样的代码看起来更合理,对吧?在 App 函数里,我们调用了_jsx 函数并且返回其结果,这个函数接收了两个参数:"div"{ children: " &quot; }。

JSX 属性

既然 JSX 标签实际上是一个函数调用,猜猜看下面这个标签转换成 JavaScript 是什么样子的?

<div className="mr-wall" />

答案:

_jsx("div", { className: "mr-wall" })

这个函数调用仍然有两个参数,第一个参数是元素的类型,第二个参数则是包含了所有属性的一个对象。

嵌套标签

那么,这个标签呢?

<div>
  <button />
</div>

答案:

_jsx('div', { children: _jsx('button') })

这个跟前面的类似,children 是一个特殊的属性,包含了嵌套在 div 里的标签,或者说是 div 的“孩子”。而 button 同时也是一个 jsx 标签,所以 children 的值是再一次调用 _jsx 的结果,而不是一个简单的字符串。

再来看一个:

<div> {alan} </div>

答案:

_jsx("div", { children: [" ", alan, " "] })

当有花括号时,标签内容将被拆分为多个“孩子”,并包括在一个数组内。

最后一个例子:

<div className="container">
  <div className="mr-wall"> {alan} </div>
  <button />
</div>

转换成 JavaScript:

_jsx('div', { className: "container", children: [
  	_jsx("div", { className: "mr-wall", children: [" ", alan, " "] }), 
	  _jsx('button')
]})

有了 JSX,我们可以轻松把 HTML 代码移植到 JavaScript 里,并且保持其简练易读的特性。

_jsx 的返回值

那么,_jsx 到底返回了一个什么结果呢?是不是 DOM 元素?我们不妨把函数的返回值打印出来瞧瞧:

function App() {
  const result = _jsx("input")
  console.log(result) // 打印到控制台
  return result
}

控制台的结果如下:

Object {type: "input", key: null, ref: null, props: Object, _owner: null}

看到了吧?_jsx 函数所创建并返回了一个简单的 JavaScript 对象,跟 DOM 元素没啥关系。这个对象的正式名称是 React 元素(React element),其作用只是描述我们所期望在浏览器中看到的结果。

原来就是一个表达式!

你知道吗?我们可以把 JSX 标签赋值给一个变量:

let content = <div>咔嚓</div>

或者作为参数在调用函数时传过去:

showAlert(<input />)

或者打印在控制台上:

console.log(<div>   </div>)

为什么可以做到这些呢?

这并不是魔法。这仅仅是因为 JSX 标签是函数调用(_jsx(...))。既然是函数调用,JSX 标签就是一个 JavaScript 表达式,可以写在任何能容纳表达式的地方。

另外,你知道为什么下面这段代码不能工作吗?

const div = <div />
div.appendChild("input")

_jsx 所创建的只是一个简单的对象,并不是 DOM 节点。所以它没有 appendChild 方法供我们调用!

你看,这就是了解 JSX 的实质好处。在 React 星上,这是生死攸关的大事。而作为造物主,只有对底层的知识有足够的了解,你才能更加自如地呼风唤雨:真正理解自己写的代码,自由表达你的想法,充分利用各种语言和框架的不同特性。

理解 JSX 和 HTML 的区别

不管 JSX 标签怎么伪装,它毕竟不是 HTML。实际上,JSX 跟 HTML 之间有很多不同的地方,比如我们在前面看到的使用 CSS 样式上的区别:

// JSX
<input style={{ minWidth: 200 }} />
  
// HTML
<input style="min-width: 200px" />

为什么这里有两层大括号?为什么不是单层大括号?为什么不是引号?

这第一层括号实际上就是墙上的那个“洞”(怪物的嘴),而第二层括号是 JavaScript 对象的界定符。所以,这里的 style 属性的值是一个对象,这也解释了为什么括号内是{ minWidth: 200 },而不是{ minWidth: 200px },或者{ min-width: 200px },因为后面两个都不是对象的正确写法。基于同样的原因,当 CSS 属性值不是数字的时候,我们需要使用引号,比如,设置背景颜色是用 <div style={{ background: "red" }}>,而不是 <div style={{ background: red }}>

当然,上述是标准 React 所支持的方法,有一些第三方库(如 styled-components、emotion)可以让我们在 JavaScript 代码里加入真正的 CSS 代码,其格式完全原汁原味,我们甚至可以直接从网上拷贝一段 CSS 代码放到程序里,不过这些库的实现仍然是基于上述的标准方法。

再举一个例子,HTML 的按钮是这样写的:

<button onclick="alert('OK')">OK</button>

而 JSX 版本则是这样的:

<button onClick={() => alert("OK")}>OK</button>

至少有两个地方不一样:第一,HTML 版本的属性名是全小写的,而在 JSX 里的属性是驼峰式命名(camel case);第二,两者的onclick属性值很不一样。

为什么会有这些区别?原因只有一个,JSX 标签根本就是 JavaScript 代码。如果把按钮的 JSX 改写成 JavaScript,就真相大白了:

_jsx('button', { onClick: () => alert('OK')}, "OK")

这里,onClick的取值是一个匿名的箭头函数(arrow function),所以才会有那些括号和箭头。

为什么不把两种标记语言做得一模一样呢?记住,其根源还是因为 JSX 就是 JavaScript 代码,就要遵照 JavaScript 代码规则。当然,我们还可以把 JSX 看成增强型的 HTML,因为它可以支持自定义标签等高级功能,这个是后话。

最后,我把 JSX 和 HTML 两者之间一些常见的区别列出来供你参考,见表 TODO 。

表 TODO:JSX 和 HTML 的区别

f2b554e362901803cd610a01228051d6.png

小结

怪物伪装的拍照墙,JavaScript 伪装的 HTML,这就是 JSX 的真实面目。它是:

  • 一个函数调用;
  • 一个表达式;
  • 其值是一个简单的对象。

艾伦,要挺住啊,我这就来救你!


看完以后觉得有用吗?后面还希望我怎么写?请拍砖!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值