Component,中文称为组件,或者构件。使用非常比较广泛,它的核心意义在于复用,相对模块,对于依赖性有更高的要求。
Module, 中文为模块或模组。它的核心意义是分离职责,属于代码级模块化的产出。它本身是提供服务的功能逻辑,是一组具有一定内聚性代码的组合,职责明确。
Component 包含两类一类是通用组件,一类是业务组件。通用组件是一种只支持复用、且相对于模板不同的是其无任何业务逻辑或者说是无任何请求方法的组件,一般情况下通用组建构建完成后需要上传至组建库维护。而业务组件则不同,业务组件是一种使用模板、对功能做的一个集中化处理、具有一定的业务逻辑、请求方法内置等功能性组建,这种组件一般只是用来在程序内部组件·库使用无需上传至公用组件库。
前端Web应用中的组件,是指一些设计为通用性的,用来构建较大型应用程序的软件,这些组件有多种表现形式。它可以是有UI(用户界面)的,也可以是作为 “服务”的纯逻辑代码。因为有视觉上的表现形式,UI组件更容易理解。UI组件简单的例子包括按钮、输入框和文本域。不论是汉堡包状的菜单按钮(无论你是否喜欢)、标签页、日历、选项菜单或者所见即所得的富文本编辑器则是一些更加高级的例子。提供服务类型的组件可能会让人难以理解,这种类型的例子包括跨浏览器的AJAX支持,日志记录或者提供某种数据持久化的功能。
基于组件开发,最重要的就是组件可以用来构成其他组件,而富文本编辑器就是个很好的例子。它是由按钮、下拉菜单和一些可视化组件等组成。
我们将相关的一些功能组织在一起,把一切封装起来,而在组件的例子中,就可能是相关的功能逻辑和静态资源:JavaScript、HTML、CSS以及图像等。这就是我们所说的内聚。这种做法将让组件更容易维护,并且这么做之后,组件的可靠性也将提高。同时,它也能让组件的功能明确,增大组件重用的可能性。
你看到的示例组件,尤其是Web Component,更关心可重用的问题。功能明确,实现清晰,API易于理解。自然就能促进组件复用。通过构建可重用组件,我们不仅保持了 DRY(不要重复造轮子)原则,还得到了相应的好处。
不要过分尝试构建可重用组件。你更应该关注应用程序上所需要的那些特定部分。如果之后相应需求出现,或者组件的确到了可重用的地步,就花一点额外时间让组件重用。事实上,开发者都喜欢去创造可重用功能块(库、组件、模块、插件等),做得太早将会让你后来痛苦不堪。所以,吸取基于组件开发的其他好处,并且接受不是所有组件都能重用的事实。
一个功能明确好组件的API能让人轻易地更改其内部的功能实现。要是程序内部的组件是松耦合的,那事实上可以用一个组件轻易地替换另一个组件,只要遵循相同的 API/接口/约定。
基于组件的架构让组件组合成新组件更加容易。这样的设计让组件更加专注,也让其他组件中构建和暴露的功能更好利用。不论是给程序添加功能,还是用来制作完整的程序,更加复杂的功能也能如法炮制。这就是这种方法的主要好处。
组件名称:列表信息组件(SYCardInfo)
实现功能:主要提供统一列表信息显示、功能性事件、统一样式、可编辑样式等
页面demo:
/* 原始页面代码 */
import React, { Component } from 'react'
import { Icon } from 'antd'
import Style from './style.module.less'
class Index extends Component {
state={
showLine: true,
stripVisible: true,
showBtn: true
}
// 渲染方法的重写
render() {
let { showLine, stripVisible, showBtn } = this.state
return (
<>
{ stripVisible && }
title
this is onClike text!
this is card info!
Button1
Button2
>
)
}
}
export default Index
|------- SYCardInfo 文件夹
|---------- index.js 组件默认读取文件
|---------- index.mdx 组件说明文档
|---------- style.module.less 组件less表
import SYCardInfo from './components/SYCardInfo'
export {
SYCardInfo
}
{ stripVisible && }
title
this is onClike text!
this is card info!
Button1
Button2
import React, { Component } from 'react'
import Style from './style.module.less'
import propTypes from 'prop-types'
class class Index extends Component {
static defaultProps={}
static propTypes={}
state = {}
render(){
<>>
}
}
在提取改造代码的时候需要把动态的参数、方法、样式等需要有的变化做一个抽象化
render() {
let { showLine, stripVisible, showBtn, disContent, disFooter } = this.state
let { leftColor, btnOkStyle, padding, title, rightContent, children, btnOk, btnCancel } = this.props
return (
<>
{ stripVisible && }
{title}
{rightContent && rightContent}
{disContent && (
{children}
)}
{disFooter && (
{btnOk}
{btnCancel}
)}
>
)
}
父子间的通讯主要有两种,第一种是父传子,第二种是子传父。
父传子:
1) 通过以value的进行传递
例如:
父组件使用value传递属性
点击
子组建接收数据,使用props
let { leftColor, btnOkStyle, padding, title, rightContent, children, btnOk, btnCancel } = this.props
2)子节点的传递
意思是说在父组件调用过程中可以使用组件标签进行包裹起来传递给子组件的内标签。
例如
父组件
let array = []
for (let i = 1; i < this.state.number; i += 1) {
array.push(
抚摸了
{i}
{' '}
次小宝贝!
)
}
render(){
点击
子组件接收方法
{this.props.children}
子传父意思是说,在父组件中调用子组件中的方法或者是通过父组件去改变对应子组件中的方法以及传值问题,下面是我的一个简单的解决方案。
子组件使用父组件传递进来的一个onRef方法,通过该方法将组件间的this对象传递给父组件的回调方法,然后使用该方法做事件处理。
子组件
componentDidMount() {
if (this.props.onRef) {
this.props.onRef(this)
}
}
父组件的使用
onRef={ref => { this.onRef = ref }} // 绑定回调方法
//使用 该方法一般用作通过父组件获取新数据,使用该方法来完成数据刷新功能
OkOnClick = v => {
this.onRef.onRefClike('来自父组件的关怀!')
}
使用生命周期方法一边用来处理复杂组件传递进来的请求信息等,可以使用生命周期方法来进行处理,然后进行渲染。
componentDidMount() {
if (this.props.disFooter) {
this.setStateZet('disFooter', true)
}
if (this.props.children) {
this.setStateZet('disContent', true)
}
if (this.props.onRef) {
this.props.onRef(this)
}
}
setStateZet = (index, val) => {
this.setState({
[index]: val
})
}
前面讲述了组件间的数据传递,其中也包括了一些方法的传递等,在此处将做一个方法的传递实现。
父组件:
//方法
OkOnClick = v => {
console.log('--------这里是爸爸----------')
this.setStateZet('number', this.state.number + 1)
this.onRef.onRefClike('来自父组件的关怀!')
}
{ this.onRef = ref }}
/>
子组件:
btnOnClick = v => {
if (this.props.OkOnClick) {
this.props.OkOnClick(v)
}
}
{btnOk}
{btnCancel}
该文档是发布至npm公有云环境
首先需要https://www.npmjs.com/创建npm账号
其次是验证邮箱https://www.npmjs.com/email-edit
进入组件文档根目录下
切换npm源路径
#查询配置
npm config get registry
npm config set registry http://registry.npmjs.org
使用npm adduser进行账号登陆
上传文件目录以及配置文件
{
"name": "songshao-component", # 组件名称
"version": "2.2.1", # 版本号
"description": "测试组件库", # 中文名称
"main": "dist/index.js", # 主方法js
"module": "dist/index.esm.js", # 模板方法js
"author": "shaosong", # npm 用户
"license": "ISC"
}
使用npm publish进行组件上传
使用已发布组件库组件
npm install songshao-component -d
使用方法直接使用
import React, { Component } from 'react'
import { Icon } from 'antd'
import { SYCardInfo } from 'songshao-component'
import Style from './style.module.less'
class Index extends Component {
state={
showLine: true,
stripVisible: true,
showBtn: true,
number: 1,
newBoby: false
}
OkOnClick = v => {
console.log('--------这里是爸爸----------')
this.setStateZet('number', this.state.number + 1)
this.onRef.onRefClike('来自父组件的关怀!')
}
CancelOnClick = v => {
console.log('--------这里是爸爸----------')
this.setStateZet('number', this.state.number - 1)
}
setStateZet = (index, value) => {
this.setState({
[index]: value
})
}
leftOnClick = v => {
this.setStateZet('newBoby', true)
}
render() {
let { newBoby, stripVisible, showBtn, number } = this.state
let array = []
for (let i = 1; i < this.state.number; i += 1) {
array.push(
<div key={i}>
抚摸了
{i}
{' '}
次小宝贝!
</div>
)
}
return (
<>
<SYCardInfo
title='小宝贝'
btnOk='抚摸'
btnCancel='暴扣'
OkOnClick={this.OkOnClick}
CancelOnClick={this.CancelOnClick}
disFooter
rightContent={(
<div onClick={this.leftOnClick}>
<span>点击</span>
<Icon type='right' style={{ color: '#4A90E2' }} />
</div>
)}
onRef={ref => { this.onRef = ref }}
>
{
array
}
</SYCardInfo>
{newBoby && (
<SYCardInfo title='new小宝贝'>
点击右上角打开下面卡片
</SYCardInfo>
)}
</>
)
}
}
export default Index
任何一个组件都应该遵守一套标准,可以使得不同区域的开发人员据此标准开发出一套标准统一的组件。
// title.jsx (Title组件)
import React, { Component, PropTypes } from 'react';
import propTypes from 'prop-types';
export default class Title extends Component {
static propTypes={
title: propTypes.string,
btnOk: propTypes.string,
btnCancel: propTypes.string,
rightContent: propTypes.element || propTypes.string,
leftColor: propTypes.string,
onRef: propTypes.func,
disFooter: propTypes.bool
}
static defaultProps={
title: 'title',
btnOk: '确定',
btnCancel: '取消',
rightContent: null,
leftColor: '#4A90E2',
onRef: ref => { },
disFooter: false
}
state={
showLine: true,
stripVisible: true,
showBtn: true,
disFooter: false,
disContent: false,
}
constructor(props) {
super(props)
this.state = {
showLine: true,
stripVisible: true,
showBtn: true,
disFooter: false,
disContent: false
}
}
}
// 判断一个函数的第一个必填,且为 String 格式
// ES6 语法
changeTitle(title) {
if (typeof title !== 'string') {
throw new Error('必须传入一个 title,才能修改 title。')
}
// 满足条件,可以进行修改
this.setState({ // react 语法,修改state的值
title
})
}
rue,
showBtn: true,
disFooter: false,
disContent: false,
}
constructor(props) {
super(props)
this.state = {
showLine: true,
stripVisible: true,
showBtn: true,
disFooter: false,
disContent: false
}
}
}
// 判断一个函数的第一个必填,且为 String 格式
// ES6 语法
changeTitle(title) {
if (typeof title !== 'string') {
throw new Error('必须传入一个 title,才能修改 title。')
}
// 满足条件,可以进行修改
this.setState({ // react 语法,修改state的值
title
})
}