React完整上手攻略(转)

2023-11-13

转自https://typescript.bootcss.com/tutorials/react.html

这篇快速上手指南会教你如何将TypeScript与React结合起来使用。 在最后,你将学到:

  • 使用TypeScript和React创建工程
  • 使用TSLint进行代码检查
  • 使用JestEnzyme进行测试,以及
  • 使用Redux管理状态

我们会使用create-react-app工具快速搭建工程环境。

这里假设你已经在使用Node.jsnpm。 并且已经了解了React的基础知识

安装create-react-app

我们之所以使用create-react-app是因为它能够为React工程设置一些有效的工具和权威的默认参数。 它仅仅是一个用来搭建React工程的命令行工具而已。

npm install -g create-react-app

创建新工程

让我们首先创建一个叫做my-app的新工程:

create-react-app my-app --scripts-version=react-scripts-ts

react-scripts-ts是一系列适配器,它利用标准的create-react-app工程管道并把TypeScript混入进来。

此时的工程结构应如下所示:

my-app/
├─ .gitignore
├─ node_modules/
├─ public/
├─ src/
│  └─ ...
├─ package.json
├─ tsconfig.json
└─ tslint.json

注意:

  • tsconfig.json包含了工程里TypeScript特定的选项。
  • tslint.json保存了要使用的代码检查器的设置,TSLint
  • package.json包含了依赖,还有一些命令的快捷方式,如测试命令,预览命令和发布应用的命令。
  • public包含了静态资源如HTML页面或图片。除了index.html文件外,其它的文件都可以删除。
  • src包含了TypeScript和CSS源码。index.tsx是强制使用的入口文件。

运行工程

通过下面的方式即可轻松地运行这个工程。

npm run start

它会执行package.json里面指定的start命令,并且会启动一个服务器,当我们保存文件时还会自动刷新页面。 通常这个服务器的地址是http://localhost:3000,页面应用会被自动地打开。

它会保持监听以方便我们快速地预览改动。

测试工程

测试也仅仅是一行命令的事儿:

npm run test

这个命令会运行Jest,一个非常好用的测试工具,它会运行所有扩展名是.test.ts.spec.ts的文件。 好比是npm run start命令,当检测到有改动的时候Jest会自动地运行。 如果喜欢的话,你还可以同时运行npm run startnpm run test,这样你就可以在预览的同时进行测试。

生成生产环境的构建版本

在使用npm run start运行工程的时候,我们并没有生成一个优化过的版本。 通常我们想给用户一个运行的尽可能快并在体积上尽可能小的代码。 像压缩这样的优化方法可以做到这一点,但是总是要耗费更多的时间。 我们把这样的构建版本称做“生产环境”版本(与开发版本相对)。

要执行生产环境的构建,可以运行如下命令:

npm run build

这会相应地创建优化过的JS和CSS文件,./build/static/js./build/static/css

大多数情况下你不需要生成生产环境的构建版本, 但它可以帮助你衡量应用最终版本的体积大小。

创建一个组件

下面我们将要创建一个Hello组件。 这个组件接收任意一个我们想对之打招呼的名字(我们把它叫做name),并且有一个可选数量的感叹号做为结尾(通过enthusiasmLevel)。

若我们这样写<Hello name="Daniel" enthusiasmLevel={3} />,这个组件大至会渲染成<div>Hello Daniel!!!</div>。 如果没指定enthusiasmLevel,组件将默认显示一个感叹号。 若enthusiasmLevel0或负值将抛出一个错误。

下面来写一下Hello.tsx

// src/components/Hello.tsx

import * as React from 'react';

export interface Props {
  name: string;
  enthusiasmLevel?: number;
}

function Hello({ name, enthusiasmLevel = 1 }: Props) {
  if (enthusiasmLevel <= 0) {
    throw new Error('You could be a little more enthusiastic. :D');
  }

  return (
    <div className="hello">
      <div className="greeting">
        Hello {name + getExclamationMarks(enthusiasmLevel)}
      </div>
    </div>
  );
}

export default Hello;

// helpers

function getExclamationMarks(numChars: number) {
  return Array(numChars + 1).join('!');
}

注意我们定义了一个类型Props,它指定了我们组件要用到的属性。 name是必需的且为string类型,同时enthusiasmLevel是可选的且为number类型(你可以通过名字后面加?为指定可选参数)。

我们创建了一个无状态的函数式组件(Stateless Functional Components,SFC)Hello。 具体来讲,Hello是一个函数,接收一个Props对象并拆解它。 如果Props对象里没有设置enthusiasmLevel,默认值为1

使用函数是React中定义组件的两种方式之一。 如果你喜欢的话,也可以通过类的方式定义:

class Hello extends React.Component<Props, object> {
  render() {
    const { name, enthusiasmLevel = 1 } = this.props;

    if (enthusiasmLevel <= 0) {
      throw new Error('You could be a little more enthusiastic. :D');
    }

    return (
      <div className="hello">
        <div className="greeting">
          Hello {name + getExclamationMarks(enthusiasmLevel)}
        </div>
      </div>
    );
  }
}

当我们的组件具有某些状态的时候,使用类的方式是很有用处的。 但在这个例子里我们不需要考虑状态 - 事实上,在React.Component<Props, object>我们把状态指定为了object,因此使用SFC更简洁。 当在创建可重用的通用UI组件的时候,在表现层使用组件局部状态比较适合。 针对我们应用的生命周期,我们会审视应用是如何通过Redux轻松地管理普通状态的。

现在我们已经写好了组件,让我们仔细看看index.tsx,把<App />替换成<Hello ... />

首先我们在文件头部导入它:

import Hello from './components/Hello.tsx';

然后修改render调用:

ReactDOM.render(
  <Hello name="TypeScript" enthusiasmLevel={10} />,
  document.getElementById('root') as HTMLElement
);

类型断言

这里还有一点要指出,就是最后一行document.getElementById('root') as HTMLElement。 这个语法叫做类型断言,有时也叫做转换。 当你比类型检查器更清楚一个表达式的类型的时候,你可以通过这种方式通知TypeScript。

这里,我们之所以这么做是因为getElementById的返回值类型是HTMLElement | null。 简单地说,getElementById返回null是当无法找对对应id元素的时候。 我们假设getElementById总是成功的,因此我们要使用as语法告诉TypeScript这点。

TypeScript还有一种感叹号(!)结尾的语法,它会从前面的表达式里移除nullundefined。 所以我们也可以写成document.getElementById('root')!,但在这里我们想写的更清楚些。

:sunglasses:添加样式

通过我们的设置为一个组件添加样式很容易。 若要设置Hello组件的样式,我们可以创建这样一个CSS文件src/components/Hello.css

.hello {
  text-align: center;
  margin: 20px;
  font-size: 48px;
  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif
}

.hello button {
    margin-left: 25px;
    margin-right: 25px;
    font-size: 40px;
    min-width: 50px;
}

create-react-app包含的工具(Webpack和一些加载器)允许我们导入样式表文件。 当我们构建应用的时候,所有导入的.css文件会被拼接成一个输出文件。 因此在src/components/Hello.tsx,我们需要添加如下导入语句。

import './Hello.css';

使用Jest编写测试

我们对Hello组件有一些假设。 让我们在此重申一下:

  • 当这样写<Hello name="Daniel" enthusiasmLevel={3} />时,组件应被渲染成<div>Hello Daniel!!!</div>
  • 若未指定enthusiasmLevel,组件应默认显示一个感叹号。
  • enthusiasmLevel0或负值,它应抛出一个错误。

我们将针对这些需求为组件写一些注释。

但首先,我们要安装Enzyme。 Enzyme是React生态系统里一个通用工具,它方便了针对组件的行为编写测试。 默认地,我们的应用包含了一个叫做jsdom的库,它允许我们模拟DOM以及在非浏览器的环境下测试运行时的行为。 Enzyme与此类似,但是是基于jsdom的,并且方便我们查询组件。

让我们把它安装为开发依赖项。

npm install -D enzyme @types/enzyme react-addons-test-utils

注意我们同时安装了enzyme@types/enzyme。 enzyme包指的是包含了实际运行的JavaScript代码包,而@types/enzyme则包含了声明文件(.d.ts文件)的包,以便TypeScript能够了解该如何使用Enzyme。 你可以在这里了解更多关于@types包的信息。

我们还需要安装react-addons-test-utils。 它是使用enzyme所需要安装的包。

现在我们已经设置好了Enzyme,下面开始编写测试! 先创建一个文件src/components/Hello.test.tsx,与先前的Hello.tsx文件放在一起。

// src/components/Hello.test.tsx

import * as React from 'react';
import * as enzyme from 'enzyme';
import Hello from './Hello';

it('renders the correct text when no enthusiasm level is given', () => {
  const hello = enzyme.shallow(<Hello name='Daniel' />);
  expect(hello.find(".greeting").text()).toEqual('Hello Daniel!')
});

it('renders the correct text with an explicit enthusiasm of 1', () => {
  const hello = enzyme.shallow(<Hello name='Daniel' enthusiasmLevel={1}/>);
  expect(hello.find(".greeting").text()).toEqual('Hello Daniel!')
});

it('renders the correct text with an explicit enthusiasm level of 5', () => {
  const hello = enzyme.shallow(<Hello name='Daniel' enthusiasmLevel={5} />);
  expect(hello.find(".greeting").text()).toEqual('Hello Daniel!!!!!');
});

it('throws when the enthusiasm level is 0', () => {
  expect(() => {
    enzyme.shallow(<Hello name='Daniel' enthusiasmLevel={0} />);
  }).toThrow();
});

it('throws when the enthusiasm level is negative', () => {
  expect(() => {
    enzyme.shallow(<Hello name='Daniel' enthusiasmLevel={-1} />);
  }).toThrow();
});

这些测试都十分基础,但你可以从中得到启发。

添加state管理

到此为止,如果你使用React的目的是只获取一次数据并显示,那么你已经完成了。 但是如果你想开发一个可以交互的应用,那么你需要添加state管理。

state管理概述

React本身就是一个适合于创建可组合型视图的库。 但是,React并没有任何在应用间同步数据的功能。 就React组件而言,数据是通过每个元素上指定的props向子元素传递。

因为React本身并没有提供内置的state管理功能,React社区选择了Redux和MobX库。

Redux依靠一个统一且不可变的数据存储来同步数据,并且更新那里的数据时会触发应用的更新渲染。 state的更新是以一种不可变的方式进行,它会发布一条明确的action消息,这个消息必须被reducer函数处理。 由于使用了这样明确的方式,很容易弄清楚一个action是如何影响程序的state。

MobX借助于函数式响应型模式,state被包装在了可观察对象里,并通过props传递。 通过将state标记为可观察的,即可在所有观察者之间保持state的同步性。 另一个好处是,这个库已经使用TypeScript实现了。

这两者各有优缺点。 但Redux使用得更广泛,因此在这篇教程里,我们主要看如何使用Redux; 但是也鼓励大家两者都去了解一下。

后面的小节学习曲线比较陡。 因此强烈建议大家先去熟悉一下Redux

设置actions

只有当应用里的state会改变的时候,我们才需要去添加Redux。 我们需要一个action的来源,它将触发改变。 它可以是一个定时器或者UI上的一个按钮。

为此,我们将增加两个按钮来控制Hello组件的感叹级别。

安装Redux

安装reduxreact-redux以及它们的类型文件做为依赖。

npm install -S redux react-redux @types/react-redux

这里我们不需要安装@types/redux,因为Redux已经自带了声明文件(.d.ts文件)。

定义应用的状态

我们需要定义Redux保存的state的结构。 创建src/types/index.tsx文件,它保存了类型的定义,我们在整个程序里都可能用到。

// src/types/index.tsx

export interface StoreState {
    languageName: string;
    enthusiasmLevel: number;
}

这里我们想让languageName表示应用使用的编程语言(例如,TypeScript或者JavaScript),enthusiasmLevel是可变的。 在写我们的第一个容器的时候,就会明白为什么要令state与props稍有不同。

添加actions

下面我们创建这个应用将要响应的消息类型,src/constants/index.tsx

// src/constants/index.tsx

export const INCREMENT_ENTHUSIASM = 'INCREMENT_ENTHUSIASM';
export type INCREMENT_ENTHUSIASM = typeof INCREMENT_ENTHUSIASM;


export const DECREMENT_ENTHUSIASM = 'DECREMENT_ENTHUSIASM';
export type DECREMENT_ENTHUSIASM = typeof DECREMENT_ENTHUSIASM;

这里的const/type模式允许我们以容易访问和重构的方式使用TypeScript的字符串字面量类型。

接下来,我们创建一些actions以及创建这些actions的函数,src/actions/index.tsx

import * as constants from '../constants'

export interface IncrementEnthusiasm {
    type: constants.INCREMENT_ENTHUSIASM;
}

export interface DecrementEnthusiasm {
    type: constants.DECREMENT_ENTHUSIASM;
}

export type EnthusiasmAction = IncrementEnthusiasm | DecrementEnthusiasm;

export function incrementEnthusiasm(): IncrementEnthusiasm {
    return {
        type: constants.INCREMENT_ENTHUSIASM
    }
}

export function decrementEnthusiasm(): DecrementEnthusiasm {
    return {
        type: constants.DECREMENT_ENTHUSIASM
    }
}

我们创建了两个类型,它们负责增加操作和减少操作的行为。 我们还定义了一个类型(EnthusiasmAction),它描述了哪些action是可以增加或减少的。 最后,我们定义了两个函数用来创建实际的actions。

这里有一些清晰的模版,你可以参考类似redux-actions的库。

添加reducer

现在我们可以开始写第一个reducer了! Reducers是函数,它们负责生成应用state的拷贝使之产生变化,但它并没有副作用。 它们是一种纯函数

我们的reducer将放在src/reducers/index.tsx文件里。 它的功能是保证增加操作会让感叹级别加1,减少操作则要将感叹级别减1,但是这个级别永远不能小于1。

// src/reducers/index.tsx

import { EnthusiasmAction } from '../actions';
import { StoreState } from '../types/index';
import { INCREMENT_ENTHUSIASM, DECREMENT_ENTHUSIASM } from '../constants/index';

export function enthusiasm(state: StoreState, action: EnthusiasmAction): StoreState {
  switch (action.type) {
    case INCREMENT_ENTHUSIASM:
      return { ...state, enthusiasmLevel: state.enthusiasmLevel + 1 };
    case DECREMENT_ENTHUSIASM:
      return { ...state, enthusiasmLevel: Math.max(1, state.enthusiasmLevel - 1) };
  }
  return state;
}

注意我们使用了对象展开...state),当替换enthusiasmLevel时,它可以对状态进行浅拷贝。 将enthusiasmLevel属性放在末尾是十分关键的,否则它将被旧的状态覆盖。

你可能想要对reducer写一些测试。 因为reducers是纯函数,它们可以传入任意的数据。 针对每个输入,可以测试reducers生成的新的状态。 可以考虑使用Jest的toEqual方法。

创建容器

在使用Redux时,我们常常要创建组件和容器。 组件是数据无关的,且工作在表现层。 容器通常包裹组件及其使用的数据,用以显示和修改状态。 你可以在这里阅读更多关于这个概念的细节:Dan Abramov写的表现层的容器组件

现在我们修改src/components/Hello.tsx,让它可以修改状态。 我们将添加两个可选的回调属性到Props,它们分别是onIncrementonDecrement

export interface Props {
  name: string;
  enthusiasmLevel?: number;
  onIncrement?: () => void;
  onDecrement?: () => void;
}

然后将这两个回调绑定到两个新按钮上,将按钮添加到我们的组件里。

function Hello({ name, enthusiasmLevel = 1, onIncrement, onDecrement }: Props) {
  if (enthusiasmLevel <= 0) {
    throw new Error('You could be a little more enthusiastic. :D');
  }

  return (
    <div className="hello">
      <div className="greeting">
        Hello {name + getExclamationMarks(enthusiasmLevel)}
      </div>
      <div>
        <button onClick={onDecrement}>-</button>
        <button onClick={onIncrement}>+</button>
      </div>
    </div>
  );
}

通常情况下,我们应该给onIncrementonDecrement写一些测试,它们是在各自的按钮被点击时调用。 试一试以便掌握编写测试的窍门。

现在我们的组件更新好了,可以把它放在一个容器里了。 让我们来创建一个文件src/containers/Hello.tsx,在开始的地方使用下列导入语句。

import Hello from '../components/Hello';
import * as actions from '../actions/';
import { StoreState } from '../types/index';
import { connect, Dispatch } from 'react-redux';

两个关键点是初始的Hello组件和react-redux的connect函数。 connect可以将我们的Hello组件转换成一个容器,通过以下两个函数:

  • mapStateToProps将当前store里的数据以我们的组件需要的形式传递到组件。
  • mapDispatchToProps利用dispatch函数,创建回调props将actions送到store。

回想一下,我们的应用包含两个属性:languageNameenthusiasmLevel。 我们的Hello组件,希望得到一个name和一个enthusiasmLevel。 mapStateToProps会从store得到相应的数据,如果需要的话将针对组件的props调整它。 下面让我们继续往下写。

export function mapStateToProps({ enthusiasmLevel, languageName }: StoreState) {
  return {
    enthusiasmLevel,
    name: languageName,
  }
}

注意mapStateToProps仅创建了Hello组件需要的四个属性中的两个。 我们还想要传入onIncrementonDecrement回调函数。 mapDispatchToProps是一个函数,它需要传入一个调度函数。 这个调度函数可以将actions传入store来触发更新,因此我们可以创建一对回调函数,它们会在需要的时候调用调度函数。

export function mapDispatchToProps(dispatch: Dispatch<actions.EnthusiasmAction>) {
  return {
    onIncrement: () => dispatch(actions.incrementEnthusiasm()),
    onDecrement: () => dispatch(actions.decrementEnthusiasm()),
  }
}

最后,我们可以调用connect了。 connect首先会接收mapStateToPropsmapDispatchToProps,然后返回另一个函数,我们用它来包裹我们的组件。 最终的容器是通过下面的代码定义的:

export default connect(mapStateToProps, mapDispatchToProps)(Hello);

现在,我们的文件应该是下面这个样子:

// src/containers/Hello.tsx

import Hello from '../components/Hello';
import * as actions from '../actions/';
import { StoreState } from '../types/index';
import { connect, Dispatch } from 'react-redux';

export function mapStateToProps({ enthusiasmLevel, languageName }: StoreState) {
  return {
    enthusiasmLevel,
    name: languageName,
  }
}

export function mapDispatchToProps(dispatch: Dispatch<actions.EnthusiasmAction>) {
  return {
    onIncrement: () => dispatch(actions.incrementEnthusiasm()),
    onDecrement: () => dispatch(actions.decrementEnthusiasm()),
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(Hello);

创建store

让我们回到src/index.tsx。 要把所有的东西合到一起,我们需要创建一个带初始状态的store,并用我们所有的reducers来设置它。

import { createStore } from 'redux';
import { enthusiasm } from './reducers/index';
import { StoreState } from './types/index';

const store = createStore<StoreState>(enthusiasm, {
  enthusiasmLevel: 1,
  languageName: 'TypeScript',
});

store可能正如你想的那样,它是我们应用全局状态的核心store。

接下来,我们将要用./src/containers/Hello来包裹./src/components/Hello,然后使用react-redux的Provider将props与容器连通起来。 我们将导入它们:

import Hello from './containers/Hello';
import { Provider } from 'react-redux';

storeProvider的属性形式传入:

ReactDOM.render(
  <Provider store={store}>
    <Hello />
  </Provider>,
  document.getElementById('root') as HTMLElement
);

注意,Hello不再需要props了,因为我们使用了connect函数为包裹起来的Hello组件的props适配了应用的状态。

退出

如果你发现create-react-app使一些自定义设置变得困难,那么你就可以选择不使用它,使用你需要配置。 比如,你要添加一个Webpack插件,你就可以利用create-react-app提供的“eject”功能。

运行:

npm run eject

这样就可以了!

你要注意,在运行eject前最好保存你的代码。 你不能撤销eject命令,因此退出操作是永久性的除非你从一个运行eject前的提交来恢复工程。

下一步

create-react-app带有很多很棒的功能。 它们的大多数都在我们工程生成的README.md里面有记录,所以可以简单阅读一下。

如果你想学习更多关于Redux的知识,你可以前往官方站点查看文档。 同样的,MobX官方站点。

如果你想要在某个时间点eject,你需要了解再多关于Webpack的知识。 你可以查看React & Webpack教程

有时候你需要路由功能。 已经有一些解决方案了,但是对于Redux工程来讲react-router是最流行的,并经常与react-router-redux联合使用。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

React完整上手攻略(转) 的相关文章

  • 5.1-操作系统的状态机模型

    复习 并发 就这么 讲完了 理解的方式 玩一玩 示例代码 本次课回答的问题 Q 听说操作系统也是程序 那到底是鸡生蛋还是蛋生鸡 本次课主要内容 软件和硬件的桥梁 操作系统的加载和初始化 AbstractMachine 代码导读 一 自己动手
  • 我们该如何进行bug总结?

    前言 在项目过程中 测试同学会发现大量的bug 但同时也不可避免的会存在一些遗漏的bug 为了能够减少遗漏bug的现象 我们需要针对遗漏的问题进行总结 从教训中积累经验 总结方法 从而提高测试的覆盖度 提升产品的整体质量 我们该如何进行bu
  • Python教材课后简答题答案

    简答题答案 第一章 1 Python主要的特点有代码简洁 语法优美 简单易学 开源 可移植 类库丰富 中文支持等 2 Python中可以使用关键字import导入一个或多个模块 也可以使用from 模块名 import 导入模块中的全部内容
  • VMware Workstation 不支持在此主机上使用虚拟化性能计数器。

    原因 因为VMware15 5以后包含和Hyper v的功能 所以在电脑安装了Hyper V之后 对应的功能则无法使用 解决方法 1 虚拟机中不会再二次虚拟化 需要关闭VMware的虚拟技术器 步骤 虚拟机 设置 处理器 三个全部取消勾选即
  • 文本匹配模型实验报告-text2vec

    文本匹配模型实验报告 text2vec 尽管基于BERT的模型在NLP诸多下游任务中取得了成功 直接从BERT导出的句向量表示往往被约束在一个很小的区域内 表现出很高的相似度 因而难以直接用于文本语义匹配 为解决BERT原生句子表示这种 坍
  • (初级)PHP经典面试题目汇总-沃森建站教程博客

    原文地址 http wosn net 355 html
  • 【华为OD机试】数组去重和排序 (C++ Python Java)2023 B卷

    时间限制 C C 1秒 其他语言 2秒 空间限制 C C 262144K 其他语言524288K 64bit IO Format lld 题目描述 给定一个乱序的数组 删除所有的重复元素 使得每个元素只出现一次 并且按照出现的次数从高到低进
  • jsp与java的通信_javaEE jsp与servlet之间通信

    html与jsp或者servlet的通信相信大家都会了 就是使用form的get或者post提交即可 ajax异步通信将在后面讲到 但 是jsp与servlet之间怎么通信呢 servlet与jsp的通信 指从servlet中调用jsp 从
  • Centos 7 安装 搭建rabbitMQ Erlang

    Centos 7 安装 搭建rabbitMQ软件配置 Centos7 erlang 20 0 rabbit 3 7 9 配合 Springboot 2 1 5 AMQP 全称Advanced Message Queuing Protocol
  • mysql> GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'root' WITH GRANT OPTION; ERROR 1819

    mysql gt GRANT ALL PRIVILEGES ON TO root IDENTIFIED BY root WITH GRANT OPTION ERROR 1819 HY000 Your password does not sa
  • [知识图谱构建] 二.《Neo4j基础入门》基础学习之创建图数据库节点及关系

    该系列文章主要讲解知识图谱及Neo4j图数据库的用法 本篇文章是作者学习 Neo4j基础入门 书籍的在线笔记 主要讲解Neo4j的基础知识及基本语法 希望大家喜欢 前文 知识图谱构建 一 Neo4j图数据库安装初识及药材供应图谱实例 neo
  • linux目录功能

    Linux 系统目录结构 登录系统后 在当前命令窗口下输入命令 ls 你会看到如下图所示 树状目录结构 以下是对这些目录的解释 bin bin是Binary的缩写 这个目录存放着最经常使用的命令 boot 这里存放的是启动Linux时使用的
  • CANIOT系列车联网透传云网关解决重型卡车远程监控升级问题 云端监控,远程调试和程序上下载

    重卡行业 智能化 革新 不仅开启了重卡智造的新时代 还推动着我国物流运输业升级 重卡智能化科技不仅加快了整个重卡行业的智能化进程 也让卡友们在工作中更加安心 放心 重卡远程在线监控工作 已在多地交通运输局运输管理站主持召开专题会议 对重卡远
  • 前端将页面转换成PNG下载下来

    1 安装 npm install html2canvas save 2 引入 import html2canvas from html2canvas 3 示例 html2canvas document getElementById look
  • nacos动态更新配置RefreshScope注解后取值为null

    首先排除版本问题 如果在controller类上面直接加 RefreshScope注解 会导致name值为null count值也为null Slf4j RestController RequestMapping api RefreshSc
  • MyBatis中#{}和${}的不同之处是什么呢?

    转自 MyBatis中 和 的不同之处是什么呢 Mybatis简介 MyBatis 是一款优秀的持久层框架 它支持定制化 SQL 存储过程以及高级映射 MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集 MyBat
  • java selenium 监听页面websocket请求

    Selenium 是一个自动化测试工具 它可以模拟用户在浏览器中操作 它不能直接监听页面上的 WebSocket 请求 但是你可以使用JavaScript 代码在页面上监听WebSocket 再用Selenium模拟页面操作执行这个Java
  • 引用账户当前已锁定,且可能无法登录”--问题的解决方法(转载)

    indows 7下面 登录到另外一个AD域里面更改网络密码时遇到了错误 引用账户当前已锁定 且可能无法登录 如下图 经反复摸索 最后找到解决方法 点击 开始 gt 运行 输入gpedit msc并回车打开 组策略 依次展开 计算机配置 wi
  • package.json 里执行sh文件

    在 package json 文件的 scripts 字段中可以添加自定义命令 使得我们可以通过 npm run 命令来执行这些自定义命令 如果要执行一个 sh 文件 我们可以在 scripts 字段中添加一个对应的命令 假设我们要执行的

随机推荐

  • ionic:live reload时build apk导致白屏

    问题 live reload时会把在此文件加上 server url xxxxxxx 退出live模式时还原成之前的配置 如果这个时候进行apk打包 因为连不上服务器而出现白屏 解决方案 关闭live 正常打包 如果发现配置仍然没有还原 使
  • Vmware无法创建新虚拟机:无法配置文件“F:\...\master.vmx.”拒绝访问。

    虚拟机安装配置问题 问题 无法创建新虚拟机 无法配置文件 F master vmx 拒绝访问 解决方法 右键vmware 以管理员身份运行 再重新创建就可以了
  • Linux sh命令

    sh a c C e E f h i I k m n p r s t T u v x argument a Export all variables assigned to c Pass the string argument to the
  • element 菜单溢出问题

    vue element 菜单溢出问题 解决方法 生成的node modules element ui lib element ui common js 中handleMouseenter方法 大约3685行改为以下 if this appe
  • %appdata%

    appdata就是xp里的application data 有你在各种程序里的自定义设置 包括程序里可以个性化设置而不能影响替他用户文件 临时文件夹 快速启动文件夹等 举个例子 傲游浏览器允许用户安装各种插件 但是你如何找到自己安装的插件的
  • 第6章 Linux目录文件与系统启动知识

    第6章 Linux目录文件与系统启动知识 6 1 Linux系统目录结构介绍 6 1 1 Linux与Windows目录结构对比 相信很多读者已经熟悉了Linux的目录结构 图6 1可以进一步帮助读者对比Windows和Linux这两个系统
  • 模糊图像数据集

    去模糊算法笔记博客 去模糊算法笔记 AI视觉网奇的博客 CSDN博客 GoPro https drive google com file d 1KStHiZn5TNm2mo3OLZLjnRvd0vVFCI0W view GoPro提供的模糊
  • umi request和mock(mock文件夹下的js文件)请求传递和接收参数

    目录 utils request js services test js mock test js 拓展 utils request js const fetch require dva fetch const checkStatus re
  • alien指令 linux,使用alien命令让deb包和rpm包互相转换

    OS version CentOS7 Debian9 发现alien这个命令时很惊喜 之前在debian上安装etcd找不到安装包感觉很不科学 有了alien命令事情一下就变简单了 这里以etcd为例 将etcd从rpm包转换成deb包 然
  • 【Redis7】--2.十大数据类型

    文章目录 Redis十大数据类型 1 Key通用命令 1 1keys 1 2EXISTS 1 3DEL 1 4EXPIRE 1 5TTL 1 6TYPE 1 7DBSIZE 1 8SELECT 1 9MOVE 1 10FLUSHDB 1 1
  • Python自动化测试专栏——元素定位不到常见问题及解决办法

    1 元素id动态变化 以如下图片举例 当我们要定位到该元素时 如果采用id属性定位 那么很有可能定位不到 原因 当我们刷新一遍网页时 会发现id值发生变化 表明它是个动态id 每次自动化时会因为值不同无法定位到该元素 解决方法 采用其他属性
  • SQL Server(三)-查询数据(1)

    一 普通查询1 查询stu info表中所有数据 SELECT FROM table source 2 查询表中指定字段的数据 查询出stu info表中 depart 院系 字段的值 即可知道有哪些院系的学生 SELECT depart
  • 9.4 sobel算子和scharr算子的比较

    点击此处返回总目录 这一节我们看一下sobel算子和scharr算子的比较 首先我们看一下他们的卷积核 sobel算子和scharr算子他们的卷积核大小是一样的 这意味着他们计算起来 工作量是一样的 不同在哪呢 sobel计算起来 精确度不
  • js判断输入框不能为空格或null值

    var sno sno val var sname sname val if sno indexOf gt 0 sno null sname indexOf gt 0 sname null alert 学号和名称不能为空格或null值 re
  • Git安装(Windows)

    一 下载 官网下载页面 https git scm com downloads 我选择的是Win 64位的安装版本 地址 https github com git for windows git releases download v2 3
  • ElasticSearch (五) Postman查询数据

    match all size from size match 返回指定字段 排序 sort range wildcard查询 合并查询语句 1 match all 匹配所有文档 match all 下面为查询结果 result size 例
  • 了解Wi-fi频段概念

    前言 信道带宽 应该了解wi fi频段 这样才能分析有多少信道带宽可用 以及如何在没有任何干扰 失真 的情况下有效地使用它 2 4GHz和5GHz频段可用于wi fi 2 4 GHz Wi Fi频段 在2 4 GHz频段 可用带宽为100
  • QT窗口缩放,自定义边框,无边框缩放拉伸

    目录 什么情况下需要自定义边框 效果图 一 基本思路 二 参考程序一 2 1 源码 2 2 思路说明 2 3 缺点说明 三 参考程序2 3 1 源码 3 2 思路说明 3 3 优缺点说明 四 参考程序3 4 1源码 4 2 思路说明 4 3
  • 无缘

    何时相逢 何时相见 闲暇的日子中 总抱着那一份的想念 昨日的黄昏 急匆匆赶到那约定的地点 道旁的杨树枝繁叶茂 晚风随着鸟鸣声悠扬 我徘徊在你的身旁 你驻足于她的身边 笑语从月牙一般的屋顶上掠过 而我却不屑看上你一眼 能否相逢 能否相见 寂静
  • React完整上手攻略(转)

    转自https typescript bootcss com tutorials react html 这篇快速上手指南会教你如何将TypeScript与React结合起来使用 在最后 你将学到 使用TypeScript和React创建工程