Ramakrishna Pattnaik 发布的文章

不要做重复的工作;基于浏览器开发 Web App 时,需要制作一些可重用的模块。

 title=

Web 组件是一系列开源技术(例如 JavaScript 和 HTML)的集合,你可以用它们创建一些 Web App 中可重用的自定义元素。你创建的组件是独立于其他代码的,所以这些组件可以方便地在多个项目中重用。

首先,它是一个平台标准,所有主流的浏览器都支持它。

Web 组件中包含什么?

  • 定制元素:JavaScript API 支持定义 HTML 元素的新类别。
  • 影子 DOM:JavaScript API 提供了一种将一个隐藏的、独立的 文档对象模型(DOM)附加到一个元素的方法。它通过保留从页面的其他代码分离出来的样式、标记结构和行为特征对 Web 组件进行了封装。它会确保 Web 组件内样式不会被外部样式覆盖,反之亦然,Web 组件内样式也不会“泄露”到页面的其他部分。
  • HTML 模板:该元素支持定义可重用的 DOM 元素。可重用 DOM 元素和它的内容不会呈现在 DOM 内,但仍然可以通过 JavaScript 被引用。

开发你的第一个 Web 组件

你可以借助你最喜欢的文本编辑器和 JavaScript 写一个简单的 Web 组件。本指南使用 Bootstrap 生成简单的样式,并创建一个简易的卡片式的 Web 组件,给定了位置信息,该组件就能显示该位置的温度。该组件使用了 Open Weather API,你需要先注册,然后创建 APPID/APIKey,才能正常使用。

调用该组件,需要给出位置的经度和纬度:

<weather-card longitude='85.8245' latitude='20.296' />

创建一个名为 weather-card.js 的文件,这个文件包含 Web 组件的所有代码。首先,需要定义你的组件,创建一个模板元素,并在其中加入一些简单的 HTML 标签:

const template = document.createElement('template');

template.innerHTML = `
  <div class="card">
    <div class="card-body"></div>
  </div>
`

定义 Web 组件的类及其构造函数:

class WeatherCard extends HTMLElement {
  constructor() {
    super();
    this._shadowRoot = this.attachShadow({ 'mode': 'open' });
    this._shadowRoot.appendChild(template.content.cloneNode(true));
  }
  ......
}

构造函数中,附加了 shadowRoot 属性,并将它设置为开启模式。然后这个模板就包含了 shadowRoot 属性。

接着,编写获取属性的函数。对于经度和纬度,你需要向 Open Weather API 发送 GET 请求。这些功能需要在 connectedCallback 函数中完成。你可以使用 getAttribute 方法访问相应的属性,或定义读取属性的方法,把它们绑定到本对象中。

get longitude() {
  return this.getAttribute('longitude');
}

get latitude() {
  return this.getAttribute('latitude');
}

现在定义 connectedCallBack 方法,它的功能是在需要时获取天气数据:

connectedCallback() {
  var xmlHttp = new XMLHttpRequest();
  const url = `http://api.openweathermap.org/data/2.5/weather?lat=${this.latitude}&lon=${this.longitude}&appid=API_KEY`
  xmlHttp.open("GET", url, false);
  xmlHttp.send(null);
  this.$card = this._shadowRoot.querySelector('.card-body');
  let responseObj = JSON.parse(xmlHttp.responseText);
  let $townName = document.createElement('p');
  $townName.innerHTML = `Town: ${responseObj.name}`;
  this._shadowRoot.appendChild($townName);
  let $temperature = document.createElement('p');
  $temperature.innerHTML = `${parseInt(responseObj.main.temp - 273)} &deg;C`
  this._shadowRoot.appendChild($temperature);
}

一旦获取到天气数据,附加的 HTML 元素就添加进了模板。至此,完成了类的定义。

最后,使用 window.customElements.define 方法定义并注册一个新的自定义元素:

window.customElements.define('weather-card', WeatherCard);

其中,第一个参数是自定义元素的名称,第二个参数是所定义的类。这里是 整个组件代码的链接

你的第一个 Web 组件的代码已完成!现在应该把它放入 DOM。为了把它放入 DOM,你需要在 HTML 文件(index.html)中载入指向 Web 组件的 JavaScript 脚本。

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
</head>

<body>
  <weather-card longitude='85.8245' latitude='20.296'/>
  <script src='./weather-card.js'></script>
</body>

</html>

这就是显示在浏览器中的 Web 组件:

 title=

由于 Web 组件中只包含 HTML、CSS 和 JavaScript,它们本来就是浏览器所支持的,并且可以无瑕疵地跟前端框架(例如 React 和 Vue)一同使用。下面这段简单的代码展现的是它跟一个由 Create React App 引导的一个简单的 React App 的整合方法。如果你需要,可以引入前面定义的 weather-card.js,把它作为一个组件使用:

import './App.css';
import './weather-card';

function App() {
  return (
  <weather-card longitude='85.8245' latitude='20.296'></weather-card>
  );
}

export default App;

Web 组件的生命周期

一切组件都遵循从初始化到移除的生命周期法则。每个生命周期事件都有相应的方法,你可以借助这些方法令组件更好地工作。Web 组件的生命周期事件包括:

  • Constructor:Web 组件的构造函数在它被挂载前调用,意味着在元素附加到文档对象前被创建。它用于初始化本地状态、绑定事件处理器以及创建影子 DOM。在构造函数中,必须调用 super(),执行父类的构造函数。
  • ConnectedCallBack:当一个元素被挂载(即,插入 DOM 树)时调用。该函数处理创建 DOM 节点的初始化过程中的相关事宜,大多数情况下用于类似于网络请求的操作。React 开发者可以将它与 componentDidMount 相关联。
  • attributeChangedCallback:这个方法接收三个参数:name, oldValuenewValue。组件的任一属性发生变化,就会执行这个方法。属性由静态 observedAttributes 方法声明:
static get observedAttributes() {
  return ['name', '_id'];
} 

一旦属性名或 _id 改变,就会调用 attributeChangedCallback 方法。

  • DisconnectedCallBack:当一个元素从 DOM 树移除,会执行这个方法。它相当于 React 中的 componentWillUnmount。它可以用于释放不能由垃圾回收机制自动清除的资源,比如 DOM 事件的取消订阅、停用计时器或取消所有已注册的回调方法。
  • AdoptedCallback:每次自定义元素移动到一个新文档时调用。只有在处理 IFrame 时会发生这种情况。

模块化开源

Web 组件对于开发 Web App 很有用。无论你是熟练使用 JavaScript 的老手,还是初学者,无论你的目标客户使用哪种浏览器,借助这种开源标准创建可重用的代码都是一件可以轻松完成的事。

插图:Ramakrishna Pattnaik, CC BY-SA 4.0


via: https://opensource.com/article/21/7/web-components

作者:Ramakrishna Pattnaik 选题:lujun9972 译者:cool-summer-021 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

学习如何使用 git stash 命令,以及何时应该使用它。

 title=

版本控制是软件开发人员日常生活中不可分割的一部分。很难想象有哪个团队在开发软件时不使用版本控制工具。同样也很难想象有哪个开发者没有使用过(或没有听说过)Git。在 2018 年 Stackoverflow 开发者调查中,74298 名参与者中有 87.2% 的人 使用 Git 进行版本控制。

Linus Torvalds 在 2005 年创建了 Git 用于开发 Linux 内核。本文将介绍 git stash 命令,并探讨一些有用的暂存变更的选项。本文假定你对 Git 概念 有基本的了解,并对工作树、暂存区和相关命令有良好的理解。

为什么 git stash 很重要?

首先要明白为什么在 Git 中暂存变更很重要。假设 Git 没有暂存变更的命令。当你正在一个有两个分支(A 和 B)的仓库上工作时,这两个分支已经分叉了一段时间,并且有不同的头。当你正在处理 A 分支的一些文件时,你的团队要求你修复 B 分支的一个错误。你迅速将你的修改保存到 A 分支(但没有提交),并尝试用 git checkout B 来签出 B 分支。Git 会立即中止了这个操作,并抛出错误:“你对以下文件的本地修改会被该签出覆盖……请在切换分支之前提交你的修改或将它们暂存起来。”

在这种情况下,有几种方法可以启用分支切换:

  • 在分支 A 中创建一个提交,提交并推送你的修改,以修复 B 中的错误,然后再次签出 A,并运行 git reset HEAD^ 来恢复你的修改。
  • 手动保留不被 Git 跟踪的文件中的改动。

第二种方法是个馊主意。第一种方法虽然看起来很传统,但却不太灵活,因为保存未完成工作的修改会被当作一个检查点,而不是一个仍在进行中的补丁。这正是设计 git stash 的场景。

git stash 将未提交的改动保存在本地,让你可以进行修改、切换分支以及其他 Git 操作。然后,当你需要的时候,你可以重新应用这些存储的改动。暂存是本地范围的,不会被 git push 推送到远程。

如何使用 git stash

下面是使用 git stash 时要遵循的顺序:

  1. 将修改保存到分支 A。
  2. 运行 git stash
  3. 签出分支 B。
  4. 修正 B 分支的错误。
  5. 提交并(可选)推送到远程。
  6. 查看分支 A
  7. 运行 git stash pop 来取回你的暂存的改动。

git stash 将你对工作目录的修改存储在本地(在你的项目的 .git 目录内,准确的说是 /.git/refs/stash),并允许你在需要时检索这些修改。当你需要在不同的上下文之间切换时,它很方便。它允许你保存以后可能需要的更改,是让你的工作目录干净同时保持更改完整的最快方法。

如何创建一个暂存

暂存你的变化的最简单的命令是 git stash

$ git stash
Saved working directory and index state WIP on master; d7435644 Feat: configure graphql endpoint

默认情况下,git stash 存储(或称之为“暂存”)未提交的更改(已暂存和未暂存的文件),并忽略未跟踪和忽略的文件。通常情况下,你不需要暂存未跟踪和忽略的文件,但有时它们可能会干扰你在代码库中要做的其他事情。

你可以使用附加选项让 git stash 来处理未跟踪和忽略的文件:

  • git stash -ugit stash --includ-untracked 储存未追踪的文件。
  • git stash -agit stash --all 储存未跟踪的文件和忽略的文件。

要存储特定的文件,你可以使用 git stash -pgit stash -patch 命令:

$ git stash --patch
diff --git a/.gitignore b/.gitignore
index 32174593..8d81be6e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,7 @@
 # dependencies
 node_modules/
 /.pnp
+f,fmfm
 .pnp.js

 # testing
(1/1) Stash this hunk [y,n,q,a,d,e,?]?

列出你的暂存

你可以用 git stash list 命令查看你的暂存。暂存是后进先出(LIFO)方式保存的:

$ git stash list
stash@{0}: WIP on master: d7435644 Feat: configure graphql endpoint

默认情况下,暂存会显示在你创建它的分支和提交的顶部,被标记为 WIP。然而,当你有多个暂存时,这种有限的信息量并没有帮助,因为很难记住或单独检查它们的内容。要为暂存添加描述,可以使用命令 git stash save <description>

$ git stash save "remove semi-colon from schema"
Saved working directory and index state On master: remove semi-colon from schema

$ git stash list
stash@{0}: On master: remove semi-colon from schema
stash@{1}: WIP on master: d7435644 Feat: configure graphql endpoint

检索暂存起来的变化

你可以用 git stash applygit stash pop 这两个命令来重新应用暂存的变更。这两个命令都会重新应用最新的暂存(即 stash@{0})中的改动。apply 会重新应用变更;而 pop 则会将暂存的变更重新应用到工作副本中,并从暂存中删除。如果你不需要再次重新应用被暂存的更改,则首选 pop

你可以通过传递标识符作为最后一个参数来选择你想要弹出或应用的储藏:

$ git stash pop stash@{1}

$ git stash apply stash@{1}

清理暂存

删除不再需要的暂存是好的习惯。你必须用以下命令手动完成:

  • git stash clear 通过删除所有的暂存库来清空该列表。
  • git stash drop <stash_id> 从暂存列表中删除一个特定的暂存。

检查暂存的差异

命令 git stash show <stash_id> 允许你查看一个暂存的差异:

$ git stash show stash@{1}
console/console-init/ui/.graphqlrc.yml        |   4 +-
console/console-init/ui/generated-frontend.ts | 742 +++++++++---------
console/console-init/ui/package.json          |   2 +-

要获得更详细的差异,需要传递 --patch-p 标志:

$ git stash show stash@{0} --patch
diff --git a/console/console-init/ui/package.json b/console/console-init/ui/package.json
index 755912b97..5b5af1bd6 100644
--- a/console/console-init/ui/package.json
+++ b/console/console-init/ui/package.json
@@ -1,5 +1,5 @@
 {
- "name": "my-usepatternfly",
+ "name": "my-usepatternfly-2",
  "version": "0.1.0",
  "private": true,
  "proxy": "http://localhost:4000"
diff --git a/console/console-init/ui/src/AppNavHeader.tsx b/console/console-init/ui/src/AppNavHeader.tsx
index a4764d2f3..da72b7e2b 100644
--- a/console/console-init/ui/src/AppNavHeader.tsx
+++ b/console/console-init/ui/src/AppNavHeader.tsx
@@ -9,8 +9,8 @@ import { css } from "@patternfly/react-styles";

interface IAppNavHeaderProps extends PageHeaderProps {
- toolbar?: React.ReactNode;
- avatar?: React.ReactNode;
+ toolbar?: React.ReactNode;
+ avatar?: React.ReactNode;
}

export class AppNavHeader extends React.Component&lt;IAppNavHeaderProps&gt;{
  render()

签出到新的分支

你可能会遇到这样的情况:一个分支和你的暂存中的变更有分歧,当你试图重新应用暂存时,会造成冲突。一个简单的解决方法是使用 git stash branch <new_branch_name stash_id> 命令,它将根据创建暂存时的提交创建一个新分支,并将暂存中的修改弹出:

$ git stash branch test_2 stash@{0}
Switched to a new branch 'test_2'
On branch test_2
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: .graphqlrc.yml
modified: generated-frontend.ts
modified: package.json
no changes added to commit (use "git add" and/or "git commit -a")
Dropped stash@{0} (fe4bf8f79175b8fbd3df3c4558249834ecb75cd1)

在不打扰暂存参考日志的情况下进行暂存

在极少数情况下,你可能需要创建一个暂存,同时保持暂存参考日志(reflog)的完整性。这些情况可能出现在你需要一个脚本作为一个实现细节来暂存的时候。这可以通过 git stash create 命令来实现;它创建了一个暂存条目,并返回它的对象名,而不将其推送到暂存参考日志中:

$ git stash create "sample stash"
63a711cd3c7f8047662007490723e26ae9d4acf9

有时,你可能会决定将通过 git stash create 创建的暂存条目推送到暂存参考日志:

$ git stash store -m "sample stash testing.." "63a711cd3c7f8047662007490723e26ae9d4acf9"
$ git stash list
stash @{0}: sample stash testing..

结论

我希望你觉得这篇文章很有用,并学到了新的东西。如果我遗漏了任何有用的使用暂存的选项,请在评论中告诉我。


via: https://opensource.com/article/21/4/git-stash

作者:Ramakrishna Pattnaik 选题:lujun9972 译者:wxy 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出