benjycui / benjycui.github.io Goto Github PK
View Code? Open in Web Editor NEWHome Page: https://benjycui.github.io
Home Page: https://benjycui.github.io
学习是一件很枯燥的事,还是一件很有趣的事?因人而异,也因方法而异。而这篇文章,将会向各位分享一下在学英语过程中可以使用的一个相对有趣的方法,听音乐。或者更准确一点,听英文歌。其实这个方法并不新鲜,想必各位都听说过。类似的学英语的方法还有看剧、看书,当然必需是英文的。
考虑到程序员的风格,在介绍任何东西的时候,都需要一个 Quick Start。所以接下来,本文会给出具体的步骤,并用实例演示,同时也会指出这个方法优于看剧、看书的点。
首先当然是得有喜欢的英文歌,实在没有,可以找人推荐下。
每次描述步骤都觉得在写菜谱,囧。
为了方便,本文就只是分析句子中的组合。以 Because you live 为例:
Staring out at the rain with a heavy heart
It's the end of the world in my mind
Then your voice calls me back like a wake up call
*I've been looking for* the answer
#1. have been doing
# 曾经做过某事,强调做这件事持续的时间,并且可能还会继续下去,如:
# I have been programming for *five years*.
#2. have done
# 曾经做过某事,强调所做的事,如:I have *programmed* for five years.
Somewhere
I couldn't see that it was right there
But now I know what I really know
Because you live and breathe
Because you make me *believe in* myself when nobody else can help
#1. believe somebody
# 相信某人说的话,如:I believe Tom.
#2. believe in somebody
# 相信某人(人品之类),如:I believe in Tom.
Because you live, girl
My world has twice as many stars in the sky
It's alright, I survived, I'm alive again
*Cuz* of you, made it though every storm
# cuz => because,其实歌词中是有着大量口语化的单词,除了 cuz,常见的还有:
# * wanna => want to
# * gonna => going to
What is life, whats the use if you killed inside
I'm so glad I found an angel
Someone
Who was there when all my hopes fell
I wanna fly, looking in your eyes
# 省略若干行相似的歌词
Because you live and breathe
Because you make me believe in myself when nobody else can help
Because you live, girl
My world has everything I *need to survive*
#1. need to do something
# 需要(主动)去做某事,如:I need to wash this shirt.
#2. need to be done / need doing
# 需要被什么,如:1) This shirt needs to be washed. 2) This shirt needs washing.
Because you live, I live, I live
查自己不懂的单词相对容易,所以稍微说一下怎么分析歌词中的组合。以 I've been looking for the answer
为例:
I have been looking for the answer
have been looking for
have been looking for
为 have been doing
have been doing and have done
,也 Google 一下需要说明一下的是,句子结构分析属于语言学的范围,但并不需要太深入的学习语言学。因为歌词,以及技术文档中的句子基本都是简单句,所以分析起来相对容易,并不需要太多的语言学知识。
最重要的是,时间成本低。一首歌也就几分钟的时间(串烧除外),而且大多数情况下我们都是一边听歌一边做其它的事情。
其次,对于喜欢的歌,我们都会反复去听,自然会有较深的记忆。
同时,歌词内的单词、句型相对常用。虽然没有看剧时学的台词常用,但比看书时学到的要常用得多。
再怎么不济,去 KTV 的时候装一下 X 也好。:D
其实歌词只是一个载体,帮助我们回忆起之前学过的单词、句型等。所以最终能学到多少,还是由在分析歌词的过程中查找到的信息所决定的。
另外,还记得自己刚开始学 Emacs 的时候,看过一句话。大概如下:
Don't learn Emacs, use it!
毕竟任何技巧、方法,都只是一个辅助,要掌握一个技能,必需去使用它。所以在用各种方法学英语的时候,别忘了,use it!
情急之下,找到这来了。。。
问题:我想使用bisheng去搭建一个类似antd官网的说明性网站,看了bisheng简单的例子,是把markdown转化为页面,有一个问题是,我怎么去使用router,使菜单具有层级性,看例子中没有合适的说明,希望能得到解答,谢谢!
您好!
我在学习使用Ant Design进行开发,并在Ant Design的文档上看到您是文档贡献者。在使用Form组件时遇到一个问题,希望向您请教。
我使用了Form.List组件去动态增减表单项,如果我想为这些动态表单项设置初始值,应该怎样处理?我使用 form.setFieldsValue({...}) 的方法,只能实现对静态表单项的赋值,这样的动态表单项目前还没有想到比较好的解决办法。
下面是我写的表单
这里是动态表单项
这段是我参照文档写的代码
{
chargeOnPeriod === true && (
<Form.List name="periodPrices">
{(fields, { add, remove }) => {
console.log(Children)
return (
<>
<Form.Item label="单价">
<Button
className="addPrice"
type="link"
onClick={() => { add(); }}
>
添加时段
</Form.Item>
{fields.map((field, index) => (
<Form.Item name={[field.name, 'prices']} fieldKey={[field.fieldKey, 'prices']}>
元/度
</Form.Item>
<Form.Item name={[field.name, 'hours']} fieldKey={[field.fieldKey, 'hours']}>
</Form.Item>
{fields.length >= 1 ? (
<MinusCircleOutlined className="dynamic-delete-button"
onClick={() => { remove(field.name); }}
/>
) : null}
))}
</>
)
}}
</Form.List>
)
}
希望不吝赐教,谢谢!
Hi!
Nice project, ant.design! I believe you are the maintainer, right?
I tried filing a bug on ant.design which has bad layout on firefox android (title texts go offscreen on both sides).
Issue form is hard to fill from mobile, but worse, all my text disappeared after pressing Create leading me to an empty issue screen.
Looking at the Closed Issues I notice that other well-meaning contributors of bug reports got their issues similarly closed.
The issue bot is too aggressive, and probably has some bugs when posting.
Just saying.. but it discourages contributing :)
Most of you heard about Refactoring: Improving the Design of Existing Code, which is written by Kent Beck. And some of you may know that Kent Beck said:
I'm not a great programmer; I'm just a good programmer with great habits.
But what are those great habits?
Kent Beck had provide some in his book. Also, you can find others through searching engine. Actually, maybe searching engine is the reason that you are reading this article. But for me, the following habits are what I have learned from my classmates and colleagues. It is useful for me. So, I share them to you and hope that these habits make you a better programmer.
It is exciting or tiring for programmers that they have to learn thousands of new technologies in order to catch up with the development of industry (especially for front-end engineers). Programmers are cleaver enough to learn new technologies, but most of them do not have enough time, for their lives have been occupied by countless meetings and requirements. And then, this trick is to help programmers save time and learn new technology quickly.
Let's see...
Create indexes => Just remember how to find the answer for a specific question
Recite => Try to store the answer in your head
So, this trick means that remember how to find the answer for a question instead of storing the answer in your head.
Take jQuery for example. It is possible to remember all the APIs of jQuery, but difficult. Actually, it is unnecessary for most of programmers to remember all the APIs of a library. What we should do is that scan those APIs and know what they can do. In another word, we do not need to know how to do with those APIs. Because we know that we can open http://api.jquery.com/ and search, anytime.
Also, it is unnecessary to remember all the tricks in Refactoring. We read this book, and knew some tricks which make our code better. When need to know how to do that, we can just consult this book.
Knowledge is not breadcrumbs that are unordered and uncorrelated. So, we need to reorganize what we had learned from books and bugs and so on.
But how to do?
It depends on you 囧. As for me, writing blogs is the answer. When writing blogs, I must review what I had learned. If something makes me puzzled, I will search on the Internet or ask others. Actually, I learn more while writing a blog.
Also, sharing what you had learned to others is another answer. Your audiences will throw questions at you. And you have to reorganize what you had learn in order to make everything clear.
A well-designed document is the best gift for a programmer, for this document will help programmers start quickly, and provide answers for most of questions. But the real world is not utopia, some libraries' documents are in a mess. What is worse, some libraries do not have any document.
So, don't be afraid of codes that are written by others, even if there is no comment. Anyway, it is the only way to understand a library without document. And read unit test is still a good choice, for it shows what the author expects this library to do or not to do.
But...
What if...
There is no unit test!
Read source code of the library, and try to guess what it is designed to do from the implementation. Or, just find a well-documented library, if you can.
You can code at home, at table, at ... But you can not code at will. Coding is rigorous for your code will have a great effect on customers and your annual bonus.
As for me, think twice means that ask myself some questions. For example:
Ask yourself all the questions that you care about.
Look at $$$, think twice before coding, or thrice for important things should be repeated thrice :).
这是完整代码
import { Line } from '@antv/g2plot';
import {Button, Card, DatePicker, Input, Form, Radio, Select, Tabs} from 'antd';
import {connect} from 'dva'
import React, { useState, useRef } from 'react';
import { PageHeaderWrapper } from '@ant-design/pro-layout';
import styles from './style.less';
const { TabPane } = Tabs;
const FormItem = Form.Item;
const { Option } = Select;
const { RangePicker } = DatePicker;
const { TextArea } = Input;
let linePlot;
@connect(({auth_user, loading}) => ({
// auth_user,
// loading: loading.effects['auth_user/handleListData'],
// listData: auth_user.listData,
// pagination: auth_user.pagination,
// // msg: auth_user.msg,
// // searchAdvanceStatus: auth_user.searchAdvanceStatus,
// // searchStatus: auth_user.searchStatus,
// // dealStatus: auth_user.dealStatus,
// searchParams: auth_user.searchParams,
}))
export default class UpdateForm extends React.Component {
data = [
{ year: '1991', value: 3 },
{ year: '1992', value: 4 },
{ year: '1993', value: 3.5 },
{ year: '1994', value: 5 },
{ year: '1995', value: 4.9 },
{ year: '1996', value: 6 },
{ year: '1997', value: 7 },
{ year: '1998', value: 9 },
{ year: '1999', value: 13 },
];
constructor(props) {
super(props);
this.formRef = React.createRef();
this.newTabIndex = 0;
const panes = [
{ title: 'Tab 1', content: 'Content of Tab Pane 1', key: '1', closable: false},
{ title: 'Tab 2', content: 'Content of Tab Pane 2', key: '2', closable: false},
];
this.state = {
activeKey: panes[0].key,
panes,
};
}
componentDidMount(){
this.formData();
this.drawRangeMapCharts(this.data);
}
formData = () => {
this.formRef.current.setFieldsValue({
title: this.props.location.query.channelId,
subject: 'china',
categories: 'usa',
publicType: '1',
categoriesw: 'second',
test: '2',
categoriesw4: 'third',
});
console.log(this.props.location.query.channelId)
}
//绘制血缘关系图
drawRangeMapCharts(data){
linePlot = new Line(document.getElementById('container'), {
title: {
visible: true,
text: '带数据点的折线图',
},
description: {
visible: true,
text: '将折线图上的每一个数据点显示出来,作为辅助阅读。',
},
width: 700,
height: 463,
forceFit: false,
padding: 'auto',
data,
xField: 'year',
yField: 'value',
point: {
visible: true,
},
label: {
visible: true,
type: 'point',
},
});
linePlot.render();
}
//重置表单
handleReSetForm = () => {
this.formRef.current.resetFields();
};
onFinish = values => {
// console.log(values);
}
handleDifficulty = () => {
const data2 = [
{ year: '2016', value: '重要' },
{ year: '2017', value: '一般' },
{ year: '2018', value: '容易' },
{ year: '2019', value: '容易' },
{ year: '2020', value: '一般' },
];
linePlot.destroy();
this.drawRangeMapCharts(data2)
}
handleChange = () => {
const data3 = [
{ year: '2016', value: '一星' },
{ year: '2017', value: '二星' },
{ year: '2018', value: '一星' },
{ year: '2019', value: '三星' },
{ year: '2020', value: '三星' },
];
linePlot.destroy();
this.drawRangeMapCharts(data3)
}
onChange = activeKey => {
this.setState({ activeKey });
this.formRef.current.setFieldsValue({
title: '232334',
subject: 'china',
categories: 'usa',
publicType: '1',
categoriesw: 'second',
test: '2',
categoriesw4: 'third',
});
};
add = () => {
const { panes } = this.state;
const activeKey = `newTab${this.newTabIndex++}`;
panes.push({ title: 'New Tab', content: 'New Tab Pane', key: activeKey, closable: false });
this.setState({ panes, activeKey });
};
onEdit = (targetKey, action) => {
this[action](targetKey);
};
render(){
const { submitting,resetting } = this.props;
const {activeKey} = this.state;
const formItemLayout = {
labelCol: {
xs: {
span: 8,
},
sm: {
span: 5,
},
},
wrapperCol: {
xs: {
span: 24,
},
sm: {
span: 12,
},
md: {
span: 10,
},
},
};
const submitFormLayout = {
wrapperCol: {
xs: {
span: 0,
offset: 0,
},
sm: {
span: 0,
offset: 5,
},
},
};
console.log(this.formRef)
//2、创建dom
return(
<PageHeaderWrapper>
<div className={styles.divAll}>
<Tabs
onChange={this.onChange}
activeKey={this.state.activeKey}
type="editable-card"
onEdit={this.onEdit}
className={styles.flex}
>
{this.state.panes.map(pane => (
<TabPane tab={pane.title} key={pane.key} closable={pane.closable} className={styles.margin}>
{pane.content}
<Form
style={{
marginTop: 8,
}}
ref={this.formRef}
name="basic"
onFinish={this.onFinish}
// onFinishFailed={onFinishFailed}
>
<FormItem
{...formItemLayout}
label='知识点名称'
name="title"
rules={[
{
required: true,
message: "请输入知识点",
},
]}
>
<Input placeholder='给知识点起个名字'/>
</FormItem>
</Form>
{/*{ activeKey == this.state.activeKey ? :<div> </div>}*/}
</TabPane>
))}
</Tabs>
<div id='container' className={styles.lineChart} />
</div>
</PageHeaderWrapper>
);
}
}
// <FormItem
// {...formItemLayout}
// label='所属考种'
// name="subject"
// hasFeedback
// rules={[
// {
// required: true,
// message: "请选择所属考种",
// },
// ]}
// >
//
// China
// U.S.A
//
//
// <FormItem
// {...formItemLayout}
// label='所属科目'
// name="categories"
// hasFeedback
// rules={[
// {
// required: true,
// message: "请选择所属科目",
// },
// ]}
// >
//
// China
// U.S.A
//
//
// <FormItem
// {...formItemLayout}
// label='难易程度'
// name="publicType"
// >
// <Radio.Group onChange={this.handleDifficulty} >{/onChange={this.handleDifficulty}/}
//
// 容易
//
//
// 中等
//
//
// 较难
//
// </Radio.Group>
//
// <FormItem
// {...formItemLayout}
// label='重要程度'
// name="categoriesw"
// hasFeedback
// rules={[
// {
// required: true,
// message: "请选择重要程度",
// },
// ]}
// >
//
// 一星
// 二星
// 三星
//
//
// <FormItem
// {...formItemLayout}
// label='是否为考点'
// name="test"
// >
// <Radio.Group>
//
// 是
//
//
// 否
//
// </Radio.Group>
//
// <FormItem
// {...formItemLayout}
// label='年份'
// name="categoriesw4"
// hasFeedback
// rules={[
// {
// required: true,
// message: "请选择重要程度",
// },
// ]}
// >
//
// 一星
// 二星
// 三星
//
//
// <FormItem
// {...submitFormLayout}
// style={{
// marginTop: 32,
// }}
// >
//
// 重置
//
// <Button type="primary" htmlType="submit" loading={submitting} style={{
// marginLeft: 8,
// }}>
// 提交
//
//
fork [fɔ:k] n. 叉子
Fork 是开源社区每一个参与者的基本权利。为了充分运用这一权利,我们需要了解该权利有哪些使用场景,以及该如何使用,可以先参考 GitHub 官方文档。
但其实,除了 GitHub 文档里提到的两种情况,我们还有其他必须 fork 的场景:
这两种情况,都不能只是简单的 fork,还需要考虑原仓库与 fork 仓库之间代码同步的问题。所以,我们需要一个具体的 fork 工作流以规范原仓库与 fork 仓库之间的代码同步行为。
为了方便读者理解,先假设有一个名为 incredible 的仓库,同时 npm 上也有一个同名的包。
现在,我们业务系统中碰到了一个 bug。经排查,问题来自 incredible,然后还找到了修复办法。但问题是,这个 bugfix 需要立刻上线,而 incredible 的 maintaner 并不会立刻合并我们的 PR 并发版本。
这个时候我们就需要 fork incredible 并发布自己的 npm 包。
下图中,upstream/master 是原仓库最新代码,origin/master 是在 GitHub 上 fork 后自动生成的分支,代码与 upstream/master 同步。然后我们在 origin/master 的基础上再 fork 一个 bugfix 分支 origin/bugfix,并在上面提交了 D 以修复问题。
为了尽快的把 bugfix 上线,需要先把 origin/bugfix 的代码发到 npm。这里需要使用一个新的包名,如 @benjycui/incredible。然后在项目中安装 @benjycui/incredible,并通过 webpack 的 resolve.alias 把对 incredible 的引用指向 @benjycui/incredible 即可。
出于开源精神,我们还要把这个 bugfix PR 到 upstream/master 上。如果 maintainer 愿意合并这个 PR,那么只需在 maintainer 发布新版后,安装新版 incredible 并移除 resolve.alias
配置即可。
一切顺利的话,时序图如下:
事实上,不可能每件事都称心如意,这个 PR 被拒绝了。现在,我们需要自行维护 @benjycui/incredible。
在我们把 bugfix D 上线后,incredible 本身也提交了新的 commit E,所以需要把这些新的提交也同步过来,并发布新版 @benjycui/incredible。
为了分支名更加明确,把 origin/bugfix 重命名为 origin/incredible。
接上文的时序图,在 PR 被拒绝后,新的时序图如下:
在项目持续迭代的过程中,又碰到了 incredible 的 bug。我们需要先在 origin/incredible 上修复该 bug,新的 bugfix commit 为 F,并发布新版 @benjycui/incredible。
虽然 incredible 的 maintainer 之前拒绝了我们的 PR,但我们毕竟是有开源精神的人,所以这次的 bugfix 还会继续 PR 回 incredible。为此我们需要基于 origin/master fork 一个 bugfix 分支 origin/bugfix,并把 F pick 过去。
然后继续走普通的 PR 流程把 origin/bugfix PR 到 upstream/master 即可。
本示例完整流程图如下:
本文中以 React 为例,但其中的观点及方法论,对 Vue、Angular 等同样适用。
React 于 2013 开源至今,已经过去了五年。这五年里,前端界从一开始对 HTML in JS(JSX) 等新概念的抗拒,到接受,并且在项目中大量使用。现在,React 已经改变了 View 层的开发方式。
可惜,对于不少人而言,使用 React 也只是改变了他们的开发方式而已。React 所提供的,以组件的方式拆分 View 层代码,并通过组件组合的方式搭建页面,这一基本能力并没有被充分发挥。从我过去三年接触过的 React 项目来看,大多数的开发者(全栈 & 专业前端),只是把组件当做拆分代码的方式,很少会去思考组件该如何设计。结果就是,在项目里随处都能看到组件与 owner 的逻辑、样式强耦合。
在使用了 React 的前提下,项目里却还是一大堆没有正确封装且相互之间高度耦合的组件,相当讽刺(毕竟 React 在 README.md 里面可是强调了 Component-Based),却在意料之中。因为,React 只是降低了组件实现的难度,并没有降低组件设计的难度。
为了提高项目的质量,我们需要提高项目中 React 组件的设计质量。如果项目只有一个开发者,事情相对容易,只需要不断地提高个人的组件设计能力,并保持相关意识即可。但对由多人协作开发的项目而言,还需要有相应的开发流程保证,才能全面的提高整个项目的质量,如 ESLint 之于代码风格。
但在介绍相应的方法论之前,得先讨论一个更加基本的问题。
对于业务线的开发者而言,在组件设计上花费较多的时间,似乎不是一件值得的事情。毕竟业务系统中的组件,往往只有一个使用场景,所以即使组件与其使用场景强耦合,也不是什么罪过。
对一次性项目而言,如活动页,这个论点是对的。但对于需要长期维护的项目而言,一个组件从开发完成,到最终被废弃,它的使用场景其实是不断变化的,因为项目在不断地迭代、重构。例如,C 组件在一开始是在 A 组件下,
一段时间后,A 组件被大幅度重构,可以理解为 A 被一个更好的实现 D 替代了,
如果 A 与 C 强耦合,那么这次重构将会非常辛苦,C 也需要面临本可以避免的重构。可见,设计良好的组件,能够降低重构的成本。
当然,上面提到的优点是建立在一个组件会被长期使用,随着项目不断迭代的前提下。但前端界面是一个非常不稳定的存在,一个组件被开发出来用不了多久可能就被废弃了,这还有认真设计的必要么?
即使是会被废弃的组件,仍然需要有良好的设计。同样是上面的例子,A 组件被替换为 D 组件后,root 中与 A 相关的代码必然需要调整。如果 root 与 A 强耦合,那么 root 就需要较大的改动,而如果 A 是封装良好的组件,那么 root 中只需要移除 A 相关的 state 与 handler 即可。可见,设计良好的组件,能相对容易的移除、被其他组件替换或替换其他组件。
以上。
以下。
与其在开发组件时,时刻堤防着不能与其他组件耦合,还不如直接在一个隔离的环境中开发组件,其实这也是通用组件的开发方式。
为了方便读者理解与实践,接下来会用 Storaybook + DvaJS 展示该方法论。必需强调的是,工具和框架是可以自由选择的。
npm install dva-cli -g
安装 dva-cli,然后运行 dva new demo
生成项目目录。npm i -g @storybook/cli
安装 storybook,然后在 1 创建的项目中运行 getstorybook
。{
"scripts": {
"storybook": "start-storybook -p 9001 -c .storybook"
}
}
import { configure } from '@storybook/react';
function loadStories() {
require('../src/components/stories/Example.js');
}
configure(loadStories, module);
import React from 'react';
import { storiesOf } from '@storybook/react';
import Example from '../Example';
storiesOf('Example', module)
.add('normal', () => (
<Example />
));
然后就可以通过 npm start
和 npm run storybook
分别运行项目和 Storybook。
引入 Storybook 后,在本地开发时,需要同时运行项目与 Storybook。然后组件的开发、测试工作都先在 Storybook 中完成,再把组件接入项目系统中联调。流程如下:
在一个隔离的环境中开发组件,自然就能保证组件不与上层代码耦合。
除了上文提到的优点,引入Storybook 还带来额外的好处:
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.