初探React,将我们的View标签化

前言

我之前喜欢玩一款游戏:全民飞机大战,而且有点痴迷其中,如果你想站在游戏的第一阶梯,便需要不断的练技术练装备,但是腾讯的游戏一般而言是有点恶心的,他会不断的出新飞机、新装备、新宠物,所以,很多时候你一个飞机以及装备还没满级,新的装备就又出来了,并且一定是更强!

于是很多人便直接抛弃当前的飞机与装备,追求更好的,这个时候如果是人民币玩家或者骨灰级大神玩家的话,基本可以很快站在世界的顶端,一者是装备好,一者是技术好,但是我不愿意投入太多钱,也不愿意投入过多精力,于是在一套极品装备满级后会积累资源,因为一代之间变化不会太大,到第二代甚至第三代才开始换飞机换装备,也基本处于了第一阶梯,一直到一次游戏大更新,直接导致我当前的飞机与装备完全二逼了,我当时一时脑热投入了所有资源去刷新的极品装备,最后闹的血本无归,于是便删除了该游戏,一年时间付诸东流!!!

再回过头来看最近两年前端的变化,单是一个前端工程化工具就变了几次,而且新出来的总是叫嚷着要替换之前的,grunt->gulp->webpack->es6

再看前端框架的一些产量:backbone、angularJS、react、canJS、vueJS......

真有点乱花渐欲迷人眼的意思,似乎前端技术也开始想要坑前端玩家,因为人家会了新技能,你就落后了,于是很多技术沉淀已经足够的大神便直接在团队使用某一技术,带领团队组员深入了解了该技术的好,并大势宣传新技术。

很多人在这种情况下就中招了!他们可能会抛弃现有技术栈,直接跟风新的技术,在现有装备都没满级的情况下又去刷新装备,如果哪天一次游戏玩法大更新,大神依旧一套极品装备在那风骚,而炮灰仓库中积累着一箩筐低等级的极品装备,却没有可用的,不可谓不悲哀!

一门技术从入门到精通,是需要时间的,在有限的时间中要学习那么多的新技术,还得落地到实际工作中,而每一次新技术的落地都是对曾经架构的否定与推翻,这个成本不可谓不高,对一些创业团队甚至是致命的。工作中也没那么多时间让你折腾新东西,所以一定是了解清楚了一门再去学习其它的,不要半途而废也不要盲目选型。

我最近回顾了这几年所学,可以说技术栈没有怎么更新,但是我对我所习的每一个技术基本上进入了深入的了解:

① 在MVVM还不太火的时候使用了MVC框架一直到最近,对为什么要使用这种模式,这种模式的好处有了比较深入的了解,并且已经碰到了更复杂的业务逻辑

② 当一个页面过于复杂时(比如1000多行代码的订单填写页),我能通过几年沉淀,将之拆分为多个业务组件模块,保持主控制器的业务清晰,代码量维护在500行之内,并且各子模块业务也清晰,根据model进行通信

③ 使用Grunt完成前端工程化,从构建项目,到打包压缩项目,到优化项目,总的来说无往不利

④ ......

就编程方法,思维习惯,解决问题的方法来说,与两年前有了很大的变化,而且感觉很难提高了。于是我认识到,就现有的装备下,可能已经玩到极限了,可能到了跟风的时候了,而时下热门的ReactJS似乎是一个很好的切入点,React一端代码多端运行的噱头也足够。

初识ReactJS

我最初接触ReactJS的时候,最火的好像是angular,React Native也没有出现,看了他的demo,对其局部刷新的实现很感兴趣。结果,翻看源码一看洋洋洒洒一万多行代码,于是马上便退却了。却不想现在火成了这般模样,身边学习的人多,用于生产的少,我想幕后必然有黑手在推动!也可以预测的是,1,2年后会有更好的框架会取代他,可能是原团队的自我推翻,也有可能是Google公司又新出了什么框架,毕竟前端最近几年才开始真正富客户端,还有很长的路要走。当然,这不是我们关心的重点,我们这里的重点是Hello world。

ReactJS的Hello World是这样写的:

复制代码
 1 <!DOCTYPE html>2 <html>3 <head>4     <script src="build/react.js" type="text/javascript"></script>5     <script src="build/JSXTransformer.js" type="text/javascript"></script>6 </head>7 <body>8     <div id="example">9     </div>
10     <script type="text/jsx">
11       React.render(
12         <h1>Hello, world!</h1>,
13         document.getElementById('example')
14       );
15     </script>
16 </body>
17 </html>
复制代码
<div id="example"><h1 data-reactid=".0">Hello, world!</h1></div>

React一来就搞了一个标新立异的地方:jsx(js扩展),说实话,这种做法真的有点大手笔,最初的这种声明式标签写法,在我脑中基本可以追溯到5年前的.net控件了,比如gridview与datalist组件。

在text/jsx中的代码最初不会被浏览器理会,他会被react的JSXTransformer编译为常规的JS,然后浏览器才能解析。这里与html模板会转换为js函数是一个道理,我们有一种优化方案是模板预编译,即:

在打包时候便将模板转换为js函数,免去在线解析的过程,react当然也可以这样做,这里如果要解析的话,会是这个样子:

1 React.render(
2   React.createElement("h1", null, "Hello, world!"),
3   document.getElementById('example')
4 );

因为render中的代码可以很复杂,render中的代码写法就是一种语法糖,帮助我们更好的写表现层代码:render方法中可以写html与js混杂的代码:

1 var data = [1,2,3];
2 React.render(
3     <h1>Hello, {data.toString(',')}!</h1>,
4     document.getElementById('example')
5 );
复制代码
1 var data = [1,2,3];
2 React.render(
3     <h1>{
4         data.map(function(v, i) {
5             return <div>{i}-{v}</div>
6         })
7     }</h1>,
8     document.getElementById('example')
9 );
复制代码

所以,react提供了很多类JS的语法,JSXTransformer相当于一个语言解释器,而解析逻辑长达10000多行代码,这个可不是一般屌丝可以碰的,react从这里便走出了不平常的路,而他这样做的意义是什么,我们还不知道。

标签化View

react提供了一个方法,将代码组装成一个组件,然后像HTML标签一样插入网页:

复制代码
 1 var Pili = React.createClass({2     render: function() {3         return <h1>Hello World!</h1>;4     }5 });6 7 React.render(8     <Pili />,9     document.getElementById('example')
10 );
复制代码

所谓,声明试编程,便是将需要的属性写到标签上,以一个文本框为例:

<input type="text" data-type="num" data-max="100" data-min="0" data-remove=true />

我们想要输入的是数字,有数字限制,而且在移动端输入的时候,右边会有一个X按钮清除文本,这个便是我们期望的声明式标签。

react中,标签需要和原始的类发生通信,比如属性的读取是这样的:

复制代码
 1 var Pili = React.createClass({2     render: function() {3         return <h1>Hello {this.props.name}!</h1>;4     }5 });6 7 React.render(8     <Pili name='霹雳布袋戏'/>,9     document.getElementById('example')
10 );
11 
12 //Hello 霹雳布袋戏!
复制代码

上文中Pili便是一个组件,标签使用法便是一个实例,声明式写法最终也会被编译成一般的js方法,这个不是我们现在关注的重点。

由于class与for为关键字,需要使用className与htmlFor替换

通过this.props对象可以获取组件的属性,其中一个例外为children,他表示组件的所有节点:

复制代码
 1 var Pili = React.createClass({2     render: function() {3         return (4             <div>5                 {6                     this.props.children.map(function (child) {7                       return <div>{child}</div>8                     })9                 }
10             </div>
11         );
12     }
13 });
14 
15 React.render(
16     <Pili name='霹雳布袋戏'>
17         <span>素还真</span>
18         <span>叶小钗</span>
19     </Pili>
20     ,
21     document.getElementById('example')
22 );
复制代码
复制代码
1 <div id="Div1">
2     <div data-reactid=".0">
3         <div data-reactid=".0.0">
4             <span data-reactid=".0.0.0">素还真</span></div>
5         <div data-reactid=".0.1">
6             <span data-reactid=".0.1.0">叶小钗</span></div>
7     </div>
8 </div>
复制代码

PS:return的语法与js语法不太一样,不能随便加分号

如果想限制某一个属性必须是某一类型的话,便需要设置PropTypes属性:

复制代码
1 var Pili = React.createClass({
2     propType: {
3         //name必须有,并且必须是字符串
4         name:  React.PropTypes.string.isRequired
5     },
6     render: function() {
7         return <h1>Hello {this.props.name}!</h1>;
8     }
9 });
复制代码

如果想设置属性的默认值,则需要:

复制代码
 1 var Pili = React.createClass({2     propType: {3         //name必须有,并且必须是字符串4         name:  React.PropTypes.string.isRequired5     },6     getDefaultProps : function () {7         return {8             title : '布袋戏'9         };
10     },
11     render: function() {
12         return <h1>Hello {this.props.name}!</h1>;
13     }
14 });
复制代码

我们仍然需要dom交互,我们有时也需要获取真实的dom节点,这个时候需要这么做:

复制代码
 1 var MyComponent = React.createClass({2   handleClick: function() {3     React.findDOMNode(this.refs.myTextInput).focus();4   },5   render: function() {6     return (7       <div>8         <input type="text" ref="myTextInput" />9         <input type="button" value="Focus the text input" onClick={this.handleClick} />
10       </div>
11     );
12   }
13 });
复制代码

事件触发的时候通过ref属性获取当前dom元素,然后可进行操作,我们这里看看返回的dom是什么:

<input type="text" data-reactid=".0.0">

看来是真实的dom结构被返回了,另外一个比较关键的事情,便是这里的dom事件支持,需要细读文档:http://facebook.github.io/react/docs/events.html#supported-events

表单元素,属于用户与组件的交互,内容不能由props获取,这个时候一般有状态机获取,所谓状态机,便是会经常变化的属性。

复制代码
 1 var Input = React.createClass({2   getInitialState: function() {3     return {value: 'Hello!'};4   },5   handleChange: function(event) {6     this.setState({value: event.target.value});7   },8   render: function () {9     var value = this.state.value;
10     return (
11       <div>
12         <input type="text" value={value} onChange={this.handleChange} />
13         <p>{value}</p>
14       </div>
15     );
16   }
17 });
18 
19 React.render(<Input/>, document.body);
复制代码

组件有其生命周期,每个阶段会触发相关事件可被用户捕捉使用:

Mounting:已插入真实 DOM
Updating:正在被重新渲染
Unmounting:已移出真实 DOM

一般来说,我们会为一个状态发生前后绑定事件,react也是如此:

复制代码
componentWillMount()
componentDidMount()
componentWillUpdate(object nextProps, object nextState)
componentDidUpdate(object prevProps, object prevState)
componentWillUnmount()
此外,React 还提供两种特殊状态的处理函数。
componentWillReceiveProps(object nextProps):已加载组件收到新的参数时调用
shouldComponentUpdate(object nextProps, object nextState):组件判断是否重新渲染时调用
复制代码

根据之前的经验,会监控组件的生命周期的操作的时候,往往都是比较高阶的应用了,我们这里暂时不予关注。

好了,之前的例子多半来源于阮一峰老师的教程,我们这里来一个简单的验收,便实现上述只能输入数字的文本框:

复制代码
 1 var NumText = React.createClass({2     getInitialState: function() {3         return {value: 50};4     },5     propTypes: {6         value: React.PropTypes.number7     },8     handleChange: function (e) {9         var v = parseInt(e.target.value);
10         if(v > this.props.max || v < this.props.min  ) return;
11         if(isNaN(v)) v = '';
12         this.setState({value: v});
13     },
14     render: function () {
15         return (
16             <input type="text" value={this.state.value} onChange={this.handleChange} />
17         );
18     }
19 });
20 
21 React.render(
22   <NumText min="0" max="100" />,
23   document.body
24 );
复制代码

通过以上学习,我们对React有了一个初步认识,现在我们进入其todolist,看看其是如何实现的

此段参考:阮一峰老师的入门教程,http://www.ruanyifeng.com/blog/2015/03/react.html

TodoMVC

入口文件

TodoMVC为MVC框架经典的demo,难度适中,而又可以展示MVC的思想,我们来看看React此处的入口代码:

复制代码
 1 <!doctype html>2 <html lang="en" data-framework="react">3 <head>4     <meta charset="utf-8">5     <title>React • TodoMVC</title>6     <link rel="stylesheet" href="node_modules/todomvc-common/base.css">7     <link rel="stylesheet" href="node_modules/todomvc-app-css/index.css">8 </head>9 <body>
10     <section class="todoapp">
11     </section>
12     <script src="node_modules/react/dist/react-with-addons.js"></script>
13     <script src="node_modules/react/dist/JSXTransformer.js"></script>
14     <script src="node_modules/director/build/director.js"></script>
15     <script src="js/utils.js"></script>
16     <script src="js/todoModel.js"></script>
17 
18     <script type="text/jsx" src="js/todoItem.jsx"></script>
19     <script type="text/jsx" src="js/footer.jsx"></script>
20     <script type="text/jsx" src="js/app.jsx"></script>
21 </body>
22 </html>
复制代码

页面很干净,除了react基本js与其模板解析文件外,还多了一个director.js,因为react本身不提供路由功能,所以路由的工作便需要插件,director便是路由插件,这个不是我们今天学习的重点,然后是两个js文件:

 1 var app = app || {};2 3 (function () {4   'use strict';5 6   app.Utils = {7     uuid: function () {8       /*jshint bitwise:false */9       var i, random;
10       var uuid = '';
11 
12       for (i = 0; i < 32; i++) {
13         random = Math.random() * 16 | 0;
14         if (i === 8 || i === 12 || i === 16 || i === 20) {
15           uuid += '-';
16         }
17         uuid += (i === 12 ? 4 : (i === 16 ? (random & 3 | 8) : random))
18                     .toString(16);
19       }
20 
21       return uuid;
22     },
23 
24     pluralize: function (count, word) {
25       return count === 1 ? word : word + 's';
26     },
27 
28     store: function (namespace, data) {
29       if (data) {
30         return localStorage.setItem(namespace, JSON.stringify(data));
31       }
32 
33       var store = localStorage.getItem(namespace);
34       return (store && JSON.parse(store)) || [];
35     },
36 
37     extend: function () {
38       var newObj = {};
39       for (var i = 0; i < arguments.length; i++) {
40         var obj = arguments[i];
41         for (var key in obj) {
42           if (obj.hasOwnProperty(key)) {
43             newObj[key] = obj[key];
44           }
45         }
46       }
47       return newObj;
48     }
49   };
50 })();
utils
复制代码
 1 var app = app || {};2 3 (function () {4   'use strict';5 6   var Utils = app.Utils;7   // Generic "model" object. You can use whatever8   // framework you want. For this application it9   // may not even be worth separating this logic
10   // out, but we do this to demonstrate one way to
11   // separate out parts of your application.
12   app.TodoModel = function (key) {
13     this.key = key;
14     this.todos = Utils.store(key);
15     this.onChanges = [];
16   };
17 
18   app.TodoModel.prototype.subscribe = function (onChange) {
19     this.onChanges.push(onChange);
20   };
21 
22   app.TodoModel.prototype.inform = function () {
23     Utils.store(this.key, this.todos);
24     this.onChanges.forEach(function (cb) { cb(); });
25   };
26 
27   app.TodoModel.prototype.addTodo = function (title) {
28     this.todos = this.todos.concat({
29       id: Utils.uuid(),
30       title: title,
31       completed: false
32     });
33 
34     this.inform();
35   };
36 
37   app.TodoModel.prototype.toggleAll = function (checked) {
38     // Note: it's usually better to use immutable data structures since they're
39     // easier to reason about and React works very well with them. That's why
40     // we use map() and filter() everywhere instead of mutating the array or
41     // todo items themselves.
42     this.todos = this.todos.map(function (todo) {
43       return Utils.extend({}, todo, { completed: checked });
44     });
45 
46     this.inform();
47   };
48 
49   app.TodoModel.prototype.toggle = function (todoToToggle) {
50     this.todos = this.todos.map(function (todo) {
51       return todo !== todoToToggle ?
52                 todo :
53                 Utils.extend({}, todo, { completed: !todo.completed });
54     });
55 
56     this.inform();
57   };
58 
59   app.TodoModel.prototype.destroy = function (todo) {
60     this.todos = this.todos.filter(function (candidate) {
61       return candidate !== todo;
62     });
63 
64     this.inform();
65   };
66 
67   app.TodoModel.prototype.save = function (todoToSave, text) {
68     this.todos = this.todos.map(function (todo) {
69       return todo !== todoToSave ? todo : Utils.extend({}, todo, { title: text });
70     });
71 
72     this.inform();
73   };
74 
75   app.TodoModel.prototype.clearCompleted = function () {
76     this.todos = this.todos.filter(function (todo) {
77       return !todo.completed;
78     });
79 
80     this.inform();
81   };
82 
83 })();
复制代码

utils为简单的工具类,不予理睬;无论什么时候数据层一定是MVC的重点,这里稍微给予一点关注:

① model层实现了一个简单的事件订阅通知系统

② 从类实现来说,他仅有三个属性,key(存储与localstorage的命名空间),todos(真实的数据对象),changes(事件集合)

③ 与backbone的model不同,backbone的数据操作占了其实现大部分篇幅,backbone的TodoMVC会完整定义Model的增删差改依次触发的事件,所以Model定义结束,程序就有了完整的脉络,而我们看react这里有点“弱化”数据处理的感觉

④ 总的来说,整个Model的方法皆在操作todos数据,subscribe用于注册事件,每次操作皆会通知changes函数响应,并且存储到localstorage,从重构的角度来说inform其实只应该完成通知的工作,存储的事情不应该做,但是这与我们今天所学没有什么管理,不予理睬,接下来我们进入View层的代码。

组件化编程

React号称组件化编程,我们从标签化、声明式编程的角度来一起看看他第一个View TodoItem的实现:

  1 var app = app || {};2 3 (function () {4     'use strict';5 6     var ESCAPE_KEY = 27;7     var ENTER_KEY = 13;8 9     app.TodoItem = React.createClass({10         handleSubmit: function (event) {11             var val = this.state.editText.trim();12             if (val) {13                 this.props.onSave(val);14                 this.setState({editText: val});15             } else {16                 this.props.onDestroy();17             }18         },19 20         handleEdit: function () {21             this.props.onEdit();22             this.setState({editText: this.props.todo.title});23         },24 25         handleKeyDown: function (event) {26             if (event.which === ESCAPE_KEY) {27                 this.setState({editText: this.props.todo.title});28                 this.props.onCancel(event);29             } else if (event.which === ENTER_KEY) {30                 this.handleSubmit(event);31             }32         },33 34         handleChange: function (event) {35             this.setState({editText: event.target.value});36         },37 38         getInitialState: function () {39             return {editText: this.props.todo.title};40         },41 42         /**43          * This is a completely optional performance enhancement that you can44          * implement on any React component. If you were to delete this method45          * the app would still work correctly (and still be very performant!), we46          * just use it as an example of how little code it takes to get an order47          * of magnitude performance improvement.48          */49         shouldComponentUpdate: function (nextProps, nextState) {50             return (51                 nextProps.todo !== this.props.todo ||52                 nextProps.editing !== this.props.editing ||53                 nextState.editText !== this.state.editText54             );55         },56 57         /**58          * Safely manipulate the DOM after updating the state when invoking59          * `this.props.onEdit()` in the `handleEdit` method above.60          * For more info refer to notes at https://facebook.github.io/react/docs/component-api.html#setstate61          * and https://facebook.github.io/react/docs/component-specs.html#updating-componentdidupdate62          */63         componentDidUpdate: function (prevProps) {64             if (!prevProps.editing && this.props.editing) {65                 var node = React.findDOMNode(this.refs.editField);66                 node.focus();67                 node.setSelectionRange(node.value.length, node.value.length);68             }69         },70 71         render: function () {72             return (73                 <li className={React.addons.classSet({74                     completed: this.props.todo.completed,75                     editing: this.props.editing76                 })}>77                     <div className="view">78                         <input79                             className="toggle"80                             type="checkbox"81                             checked={this.props.todo.completed}82                             onChange={this.props.onToggle}83                         />84                         <label onDoubleClick={this.handleEdit}>85                             {this.props.todo.title}86                         </label>87                         <button className="destroy" onClick={this.props.onDestroy} />88                     </div>89                     <input90                         ref="editField"91                         className="edit"92                         value={this.state.editText}93                         onBlur={this.handleSubmit}94                         onChange={this.handleChange}95                         onKeyDown={this.handleKeyDown}96                     />97                 </li>98             );99         }
100     });
101 })();
TodoItem

根据我们之前的知识,这里是创建了一个自定义标签,而标签返回的内容是:

复制代码
render: function () {return (<li className={React.addons.classSet({completed: this.props.todo.completed,editing: this.props.editing})}><div className="view"><inputclassName="toggle"type="checkbox"checked={this.props.todo.completed}onChange={this.props.onToggle}/><label onDoubleClick={this.handleEdit}>{this.props.todo.title}</label><button className="destroy" onClick={this.props.onDestroy} /></div><inputref="editField"className="edit"value={this.state.editText}onBlur={this.handleSubmit}onChange={this.handleChange}onKeyDown={this.handleKeyDown}/></li>);
}
复制代码

要展示这个View需要依赖其属性与状态:

getInitialState: function () {return {editText: this.props.todo.title};
},

这里没有属性的描写,而他本身也仅仅是标签组件,更多的信息我们需要去看调用方,该组件显示的是body部分,TodoMVC还有footer部分的操作工具条,这里的实现便比较简单了:

 1 var app = app || {};2 3 (function () {4     'use strict';5 6     app.TodoFooter = React.createClass({7         render: function () {8             var activeTodoWord = app.Utils.pluralize(this.props.count, 'item');9             var clearButton = null;
10 
11             if (this.props.completedCount > 0) {
12                 clearButton = (
13                     <button
14                         className="clear-completed"
15                         onClick={this.props.onClearCompleted}>
16                         Clear completed
17                     </button>
18                 );
19             }
20 
21             // React idiom for shortcutting to `classSet` since it'll be used often
22             var cx = React.addons.classSet;
23             var nowShowing = this.props.nowShowing;
24             return (
25                 <footer className="footer">
26                     <span className="todo-count">
27                         <strong>{this.props.count}</strong> {activeTodoWord} left
28                     </span>
29                     <ul className="filters">
30                         <li>
31                             <a
32                                 href="#/"
33                                 className={cx({selected: nowShowing === app.ALL_TODOS})}>
34                                     All
35                             </a>
36                         </li>
37                         {' '}
38                         <li>
39                             <a
40                                 href="#/active"
41                                 className={cx({selected: nowShowing === app.ACTIVE_TODOS})}>
42                                     Active
43                             </a>
44                         </li>
45                         {' '}
46                         <li>
47                             <a
48                                 href="#/completed"
49                                 className={cx({selected: nowShowing === app.COMPLETED_TODOS})}>
50                                     Completed
51                             </a>
52                         </li>
53                     </ul>
54                     {clearButton}
55                 </footer>
56             );
57         }
58     });
59 })();
TodoFooter

我们现在将关注点放在其所有标签的调用方,app.jsx(TodoApp),因为我没看见这个TodoMVC的控制器在哪,也就是我没有看见控制逻辑的js文件在哪,所以控制流程的代码只能在这里了:

  1 var app = app || {};2 3 (function () {4     'use strict';5 6     app.ALL_TODOS = 'all';7     app.ACTIVE_TODOS = 'active';8     app.COMPLETED_TODOS = 'completed';9     var TodoFooter = app.TodoFooter;10     var TodoItem = app.TodoItem;11 12     var ENTER_KEY = 13;13 14     var TodoApp = React.createClass({15         getInitialState: function () {16             return {17                 nowShowing: app.ALL_TODOS,18                 editing: null19             };20         },21 22         componentDidMount: function () {23             var setState = this.setState;24             var router = Router({25                 '/': setState.bind(this, {nowShowing: app.ALL_TODOS}),26                 '/active': setState.bind(this, {nowShowing: app.ACTIVE_TODOS}),27                 '/completed': setState.bind(this, {nowShowing: app.COMPLETED_TODOS})28             });29             router.init('/');30         },31 32         handleNewTodoKeyDown: function (event) {33             if (event.keyCode !== ENTER_KEY) {34                 return;35             }36 37             event.preventDefault();38 39             var val = React.findDOMNode(this.refs.newField).value.trim();40 41             if (val) {42                 this.props.model.addTodo(val);43                 React.findDOMNode(this.refs.newField).value = '';44             }45         },46 47         toggleAll: function (event) {48             var checked = event.target.checked;49             this.props.model.toggleAll(checked);50         },51 52         toggle: function (todoToToggle) {53             this.props.model.toggle(todoToToggle);54         },55 56         destroy: function (todo) {57             this.props.model.destroy(todo);58         },59 60         edit: function (todo) {61             this.setState({editing: todo.id});62         },63 64         save: function (todoToSave, text) {65             this.props.model.save(todoToSave, text);66             this.setState({editing: null});67         },68 69         cancel: function () {70             this.setState({editing: null});71         },72 73         clearCompleted: function () {74             this.props.model.clearCompleted();75         },76 77         render: function () {78             var footer;79             var main;80             var todos = this.props.model.todos;81 82             var shownTodos = todos.filter(function (todo) {83                 switch (this.state.nowShowing) {84                 case app.ACTIVE_TODOS:85                     return !todo.completed;86                 case app.COMPLETED_TODOS:87                     return todo.completed;88                 default:89                     return true;90                 }91             }, this);92 93             var todoItems = shownTodos.map(function (todo) {94                 return (95                     <TodoItem96                         key={todo.id}97                         todo={todo}98                         onToggle={this.toggle.bind(this, todo)}99                         onDestroy={this.destroy.bind(this, todo)}
100                         onEdit={this.edit.bind(this, todo)}
101                         editing={this.state.editing === todo.id}
102                         onSave={this.save.bind(this, todo)}
103                         onCancel={this.cancel}
104                     />
105                 );
106             }, this);
107 
108             var activeTodoCount = todos.reduce(function (accum, todo) {
109                 return todo.completed ? accum : accum + 1;
110             }, 0);
111 
112             var completedCount = todos.length - activeTodoCount;
113 
114             if (activeTodoCount || completedCount) {
115                 footer =
116                     <TodoFooter
117                         count={activeTodoCount}
118                         completedCount={completedCount}
119                         nowShowing={this.state.nowShowing}
120                         onClearCompleted={this.clearCompleted}
121                     />;
122             }
123 
124             if (todos.length) {
125                 main = (
126                     <section className="main">
127                         <input
128                             className="toggle-all"
129                             type="checkbox"
130                             onChange={this.toggleAll}
131                             checked={activeTodoCount === 0}
132                         />
133                         <ul className="todo-list">
134                             {todoItems}
135                         </ul>
136                     </section>
137                 );
138             }
139 
140             return (
141                 <div>
142                     <header className="header">
143                         <h1>todos</h1>
144                         <input
145                             ref="newField"
146                             className="new-todo"
147                             placeholder="What needs to be done?"
148                             onKeyDown={this.handleNewTodoKeyDown}
149                             autoFocus={true}
150                         />
151                     </header>
152                     {main}
153                     {footer}
154                 </div>
155             );
156         }
157     });
158 
159     var model = new app.TodoModel('react-todos');
160 
161     function render() {
162         React.render(
163             <TodoApp model={model}/>,
164             document.getElementsByClassName('todoapp')[0]
165         );
166     }
167 
168     model.subscribe(render);
169     render();
170 })();
TodoAPP

这里同样是创建了一个标签,然后最后一段代码有所不同:

复制代码
 1 var model = new app.TodoModel('react-todos');2 3 function render() {4     React.render(5         <TodoApp model={model}/>,6         document.getElementsByClassName('todoapp')[0]7     );8 }9 
10 model.subscribe(render);
11 render();
复制代码

① 这里创建了一个Model的实例,我们知道创建的时候,todos便由localstorage获取了数据(如果有的话)

② 这里了定义了一个方法,以todoapp为容器,装载标签

③ 为model订阅render方法,意思是每次model有变化都将重新渲染页面,这里的代码比较关键,按照代码所示,每次数据变化都应该执行render方法,如果list数量比较多的话,每次接重新渲染岂不是浪费性能,但真实使用过程中,可以看到React竟然是局部刷新的,他这个机制非常牛逼啊!

④ 最后执行了render方法,开始了TodoApp标签的渲染,我们这里再将TodoApp的渲染逻辑贴出来

复制代码
 1 render: function () {2         var footer;3         var main;4         var todos = this.props.model.todos;5 6         var shownTodos = todos.filter(function (todo) {7             switch (this.state.nowShowing) {8             case app.ACTIVE_TODOS:9                 return !todo.completed;
10             case app.COMPLETED_TODOS:
11                 return todo.completed;
12             default:
13                 return true;
14             }
15         }, this);
16 
17         var todoItems = shownTodos.map(function (todo) {
18             return (
19                 <TodoItem
20                     key={todo.id}
21                     todo={todo}
22                     onToggle={this.toggle.bind(this, todo)}
23                     onDestroy={this.destroy.bind(this, todo)}
24                     onEdit={this.edit.bind(this, todo)}
25                     editing={this.state.editing === todo.id}
26                     onSave={this.save.bind(this, todo)}
27                     onCancel={this.cancel}
28                 />
29             );
30         }, this);
31 
32         var activeTodoCount = todos.reduce(function (accum, todo) {
33             return todo.completed ? accum : accum + 1;
34         }, 0);
35 
36         var completedCount = todos.length - activeTodoCount;
37 
38         if (activeTodoCount || completedCount) {
39             footer =
40                 <TodoFooter
41                     count={activeTodoCount}
42                     completedCount={completedCount}
43                     nowShowing={this.state.nowShowing}
44                     onClearCompleted={this.clearCompleted}
45                 />;
46         }
47 
48         if (todos.length) {
49             main = (
50                 <section className="main">
51                     <input
52                         className="toggle-all"
53                         type="checkbox"
54                         onChange={this.toggleAll}
55                         checked={activeTodoCount === 0}
56                     />
57                     <ul className="todo-list">
58                         {todoItems}
59                     </ul>
60                 </section>
61             );
62         }
63 
64         return (
65             <div>
66                 <header className="header">
67                     <h1>todos</h1>
68                     <input
69                         ref="newField"
70                         className="new-todo"
71                         placeholder="What needs to be done?"
72                         onKeyDown={this.handleNewTodoKeyDown}
73                         autoFocus={true}
74                     />
75                 </header>
76                 {main}
77                 {footer}
78             </div>
79         );
80     }
复制代码

说句实话,这段代码不知为什么有一些令人感到难受......

① 他首先获取了注入的model实例,获取其所需的数据todos,注入点在:

<TodoApp model={model}/>

② 然后他由自身状态机,获取真实要显示的项目,其实这里如果不考虑路由的变化,完全显示即可

复制代码
1 getInitialState: function () {
2     return {
3         nowShowing: app.ALL_TODOS,
4         editing: null
5     };
6 },
复制代码

③ 数据获取成功后,便使用该数据组装为一个个独立的TodoItem标签:

复制代码
 1 var todoItems = shownTodos.map(function (todo) {2     return (3         <TodoItem4             key={todo.id}5             todo={todo}6             onToggle={this.toggle.bind(this, todo)}7             onDestroy={this.destroy.bind(this, todo)}8             onEdit={this.edit.bind(this, todo)}9             editing={this.state.editing === todo.id}
10             onSave={this.save.bind(this, todo)}
11             onCancel={this.cancel}
12         />
13     );
14 }, this);
复制代码

标签具有很多事件,这里要注意一下各个事件这里事件绑定与控制器上绑定有何不同

④ 然后其做了一些工作处理底部工具条或者头部全部选中的工作

⑤ 最后开始渲染整个标签:

复制代码
 1 return (2     <div>3         <header className="header">4             <h1>todos</h1>5             <input6                 ref="newField"7                 className="new-todo"8                 placeholder="What needs to be done?"9                 onKeyDown={this.handleNewTodoKeyDown}
10                 autoFocus={true}
11             />
12         </header>
13         {main}
14         {footer}
15     </div>
16 );
复制代码

该标签事实上为3个模块组成的了:header部分、body部分、footer部分,模块与模块之间的通信依赖便是model数据了,因为这里最终的渲染皆在app的render处,而render处渲染所有标签全部共同依赖于一个model,就算这里依赖于多个model,只要是统一在render处做展示即可。

流程分析

我们前面理清了整个脉络,接下来我们理一理几个关键脉络:

① 新增

TodoApp为其头部input标签绑定了一个onKeyDown事件,事件代理到了handleNewTodoKeyDown:

复制代码
 1 handleNewTodoKeyDown: function (event) {2     if (event.keyCode !== ENTER_KEY) {3         return;4     }5 6     event.preventDefault();7 8     var val = React.findDOMNode(this.refs.newField).value.trim();9 
10     if (val) {
11         this.props.model.addTodo(val);
12         React.findDOMNode(this.refs.newField).value = '';
13     }
14 },
复制代码

因为用户输入的数据不能由属性或者状态值获取,这里使用了dom操作的方法获取输入数据,这里的钩子是ref,事件触发了model新增一条记录,并且将文本框置为空,现在我们进入model新增的逻辑:

复制代码
1 app.TodoModel.prototype.addTodo = function (title) {
2   this.todos = this.todos.concat({
3     id: Utils.uuid(),
4     title: title,
5     completed: false
6   });
7 
8   this.inform();
9 };
复制代码

model以最简的方式构造了一个数据对象,改变了todos的值,然后通知model发生了变化,而我们都知道informa程序干了两件事:

1 app.TodoModel.prototype.inform = function () {
2   Utils.store(this.key, this.todos);
3   this.onChanges.forEach(function (cb) { cb(); });
4 };

存储localstorage、触发订阅model变化的回调,也就是:

复制代码
1 function render() {
2     React.render(
3         <TodoApp model={model}/>,
4         document.getElementsByClassName('todoapp')[0]
5     );
6 }
7 
8 model.subscribe(render);
复制代码

于是整个标签可耻的重新渲染了,我们再来看看编辑是怎么回事:

② 编辑

这个编辑便与TodoApp没有什么关系了:

1 <label onDoubleClick={this.handleEdit}>
2     {this.props.todo.title}
3 </label>

当双击标签项时,触发了代理的处理程序:

1 handleEdit: function () {
2     this.props.onEdit();
3     this.setState({editText: this.props.todo.title});
4 },

这里他做了两个事情:

onEdit,为父标签注入的方法,他这里执行函数作用域是指向this.props的,所以外层定义时指定了作用域:

复制代码
 1 return (2     <TodoItem3         key={todo.id}4         todo={todo}5         onToggle={this.toggle.bind(this, todo)}6         onDestroy={this.destroy.bind(this, todo)}7         onEdit={this.edit.bind(this, todo)}
 8         editing={this.state.editing === todo.id}9         onSave={this.save.bind(this, todo)}
10         onCancel={this.cancel}
11     />
12 );
复制代码

其次,他改变了自身状态机,而状态机或者属性的变化皆会引起标签重新渲染,然后当触发keydown事件后,完成的逻辑便与上面一致了

思考

经过之前的学习,我们对React有了一个大概的了解,是时候搬出React设计的初衷了:

 Just the uivirtual domdata flow

后面两个概念还没强烈的感触,这里仅仅对Just the ui有一些认识,似乎React仅仅提供了MVC中View的实现,但是这个View又强大到可以抛弃C了,可以看到上述代码控制器被无限的弱化了,而我觉得React其实真实想提供的可能是一种开发方式的思路,React便是如何帮你实现这种思路的方案:

模块化编程、组件化编程、标签化编程,可能是React真正想表达的思想

我们在组织负责业务逻辑时,也会分模块、分UI,但是我们一般是采用控制器调用组件的方式使用,React这里不同的一点是使用标签分模块,孰优孰劣要真实开发过生产项目的朋友才能认识,真实的应用路由的功能必不可少,应该有不少插件会主动抱大腿,但使用灵活性仍然得项目实践验证。

react本身很干净,不包括模块加载的机制,真正发布生产前需要通过webpack打包处理,但是对于复杂项目来说,按需加载是必不可少的,这块不知道如何

而我的关注点仍然落在了样式上,之前做组件或者做页面时,有一个优化方案,是将对应的样式作为一个View的依赖项加载,一个View保持最小的html&css&js量加载,而react对样式与动画一块的支持如何,也需要生产验证;复杂的项目开发,Model的设计一定是至关重要的,也许借鉴Backbone Model的实现+React的View处理,会是一个不错的选择

最后,因为现在没有生产项目能让我使用React试水,过多的话基本就是意淫了,根据我之前MVC的使用经验,感觉灵活性上估计React仍然有一段路要走,但是其模块化编程的思路倒是对我的项目有莫大的指导作用,对于这门技术的深入,经过今天的学习,我打算再观望一下,不知道angularJS怎么样,我也许该对这门MVVM的框架展开调研

 

参考资料:

http://www.cnblogs.com/yexiaochai/p/4853398.html

http://stackoverflow.com/questions/17585787/whats-data-reactid-attribute-in-html

 

转载于:https://www.cnblogs.com/junneyang/p/5420170.html

查看全文
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

相关文章

  1. 瑞星杀毒软件被曝高危漏洞

    1月27日消息 波兰一家安全组织(www.ntinternals.org)近日公布:瑞星杀毒软件长期存在两个“本地提权”0day安全漏洞,使木马病毒能轻易获得瑞星用户的系统控制权。国内安全厂商金山和360的技术专家均已确认了这两个漏洞的存在,一旦受到黑客攻击,数千万瑞星用户将丧失对木马…...

    2024/3/31 21:37:25
  2. 学生管理系统可行性分析

    引言 学籍管理系统是一个教育单位不可缺少的部分,它的内容对于学校的决策者和管理者来说都至关重要,所以学籍管理系统应该能够为用户提供充足的信息和快捷的查询手段。但一直以来人们使用传统人工的方式管理文件档案,这种管理方式存在着许多缺点,如效率低、保密性差,另外时…...

    2024/4/26 17:50:09
  3. 用实践做总结,Restful API风格仅适用于业务逻辑简单的小型应用

    很苦恼编程界目前的一个现状:有很多人都说Restful不行或者不好,最后大多数人都被Restful的支持和拥簇者怼了回来,说你根本就不懂得什么是Restful,因为在Restful的世界里,一切你要操作的对象都可以抽象成资源,你们这些说Restful不好的人,根本就没有理解Restful的精髓,在…...

    2024/4/17 2:25:53
  4. embedding lookup

    1.embedding embedding现在在推荐系统、ctr预估系统中的使用无处不在。简单来理解就是,对于各种高维稀疏的特征,工作将单个特征映射成为一个低维稠密向量,将高维稀疏特征由"精确匹配"变成一个在embedding向量上的"模糊匹配",从而提高了算法的性能,将高…...

    2024/4/17 2:25:47
  5. 中国民间的惊人秘术! (仅供参考,可以试验,但请别冒险)

    中国民间的惊人秘术!不要乱用啊 仅供参考,可以试验,但请别冒险http://four-corner.appspot.com/http://anforen.5d6d.com/“半夜鬼敲门”黄鳝,大家都知道吧?这里用的就是黄鳝的血,要粘稠一点但不凝固。一般夏天用。傍晚的时候,把血从外面 均匀的涂在你家大门上,然后回屋…...

    2024/4/17 2:28:17
  6. Restful API基础概念

    1.restful简介以及资源介绍1-1 RESTful是什么?本质:一种软件架构风格核心:面向对象解决问题:降低开发复杂性;提高系统可伸缩性1-2RESTful的设计概念和准则1)网络上的所有事物都可以被抽象为资源.2)每一个资源都有唯一的资源标识,对资源的操作不会改变这些标识.3)所有操作都是…...

    2024/4/17 2:26:53
  7. 轻松学 Webpack 4 视频教程(36 个视频)

    轻松学 Webpack 4 视频教程(36 个视频) 轻松学 Webpack 4 视频教程 #1 课程介绍「03:20」 轻松学 Webpack 4 视频教程 #2 安装「05:04」 轻松学 Webpack 4 视频教程 #3 zero config「05:48」 轻松学 Webpack 4 视频教程 #4 Mode「Pro」「06:46」 轻松学 Webpack 4 视频教程 #…...

    2024/4/17 2:26:53
  8. AllenNLP源码学习——Embedding

    上次阅读Vocabulary的代码时,我注意到,加入词典的token先用词频进行了排序,再加入词典的,那么它的顺序就和预训练词向量文件不一样了,于是阅读Embedding,了解了它是如何使用预训练词向量的。 Embedding.py文件中定义了一些类和函数,对于处理URL和hdf5文件相关的,我没有…...

    2024/4/27 9:04:06
  9. 一次服务器被入侵后的分析 -20130911

    最近有个朋友让我去帮他看一下他的linux服务器.说是apache启动不了,有很多诡异的情况.后来证明绝不是apache启动不了这么简单. 登上服务器之后随便看了下,最先引起我注意的是”ls”命令的输出:lars@server1:~$ lsls: invalid option -- hTry `ls --help for more information.为…...

    2024/4/17 2:26:47
  10. 《A Self-Attention Setentence Embedding》阅读笔记及实践

    算法原理本文利用self-attention的方式去学习句子的embedding,表示为二维矩阵,而不是一个向量,矩阵中的每一行都表示句子中的不同部分。模型中使用了self-attention机制和一个特殊的regularization term。 假设我们有一个句子S" role="presentation" style=&…...

    2024/4/10 20:00:52
  11. react学习笔记(一)搭建环境+整体学习

    找着工作了好像。公司是用react的,所以现在开始赶紧学点react。 截图参考来自下两个网站: 千峰培训的教程视频 https://www.bilibili.com/video/BV1eE411W7WT?p=2 react官网教程: 官网教程中最终会做一个井字棋的demo出来。也就是我们要完成的。 https://react.docschina.o…...

    2024/4/25 12:56:38
  12. Android中商品展示案例

    开发一个简单的购物车:(1)需要将购物车中的商品以列表的形式展示(2)并且还需要对购物车中的 商品进行增删改查操作。(3)要实现这些功能就需要使用 ListView 和 SQLite 数据库。 1.创建一个名为ProdectDisplay的程序2.(1)在activity_main.xml文件中设计布局:<?xm…...

    2024/4/17 2:26:59
  13. Flask-Restful详解

    Restful API规范restful api是用于在前端与后台进行通信的一套规范。使用这个规范可以让前后端开发变得更加轻松。以下将讨论这套规范的一些设计细节。协议:采用http或者https协议。数据传输格式:数据之间传输的格式应该都使用json,而不使用xml。url链接:url链接中,不能有…...

    2024/4/17 2:25:41
  14. 图书管理系统——创建菜单栏(使用JMenuBar创建菜单栏)

    编写菜单栏,方法——初始化JMenuBar类对象,创建顶层菜单。JMenuBar public JMenuBar() 创建新的菜单栏。 例如:JMenu readerMangerMItem = new JMenu("读者信息管理");主要使用的属性有 1.首先创建类:属性:JMenu——readerManagerMItem("读者信息管理"…...

    2024/4/17 22:22:56
  15. 我是如何在SQL Server中处理每天四亿三千万记录的

    首先声明,我只是个程序员,不是专业的DBA,以下这篇文章是从一个问题的解决过程去写的,而不是一开始就给大家一个正确的结果,如果文中有不对的地方,请各位数据库大牛给予指正,以便我能够更好的处理此次业务。 项目背景 这是给某数据中心做的一个项目,项目难度之大令人发…...

    2024/4/17 2:27:11
  16. 用顺序表实现图书管理系统 数据结构作业

    /*Author:SkysysSchool:NCEPU */ #include<bits/stdc++.h> using namespace std; ////////BASIC INFO////////// #define ISBN_LENGTH 13 #define NAME_LENGTH 20 #define PRESS_LENGTH 20 #define AUTHOR_LENGTH 20 typedef struct...

    2024/4/26 6:02:33
  17. Struts2 OGNL 漏洞!

    2019独角兽企业重金招聘Python工程师标准>>> 这文章有漏洞影响到百度,所以先发百度,修补后,正在和剑心商量小范围群发各个互联网安全团队,结果老外也研究出,并且直接爆出这个文章的最终POC。想想刚好明天我生日,发了,庆祝吧。身在互联网公司安全团队,有研究…...

    2024/4/17 2:25:59
  18. tf.nn.embedding_lookup()的用法

    一般在NLP中经常用到这个函数。在NLP中,词汇表中存储了所有单词的word embedding,这个词汇表中的word embedding可以是通过word2vec算法训练好的,但是我们的语料库中的文本都是按照一篇篇文档存储的,而且语料库中存储的也只是一篇篇文档的对应单词的id,而不是embedding。故…...

    2024/4/22 4:10:36
  19. android动画案例,淡入淡出效果

    转载请注明出处:http://blog.csdn.net/droyon/article/details/8689249 源代码下载 1、android动画测试程序,界面如图: 颜色随机变化,点击视图,左淡出,右淡入,下淡出,上淡入效果。主要源代码解析:package com.example.objectanimatortest;import java.util.Random;imp…...

    2024/4/17 2:26:59
  20. WEB前端HTML5,CSS3,VueJS,AngularJS,NodeJS,ReactJS,响应式开发,组件式开发,全栈架构

    WEB前端HTML5,CSS3,VueJS,AngularJS,NodeJS,ReactJS,Bootstrap,Webpack,响应式开发,组件式开发,全栈架构,高级项目,实战42套WEB前端包含:HTML5,CSS3,VueJS,AngularJS,NodeJS,ReactJS,Bootstrap,Webpack,Ajax,JQuery,WepApp,Yii2.0,ES6,Laravel5.4,响…...

    2024/4/19 21:33:54

最新文章

  1. MySQL中截取字符串有哪些方法

    文章目录 一、SUBSTRING() 或 SUBSTR() 函数二、LEFT() 函数三、RIGHT() 函数四、使用字符串连接和定位函数截取五、 正则表达式截取六、SUBSTRING_INDEX() 函数&#xff1a; 在MySQL中&#xff0c;你可以使用多种方法来截取字符串。以下是一些常用的方法&#xff1a; 一、SUB…...

    2024/4/27 13:32:11
  2. 梯度消失和梯度爆炸的一些处理方法

    在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言&#xff0c;在此感激不尽。 权重和梯度的更新公式如下&#xff1a; w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...

    2024/3/20 10:50:27
  3. 自动化标准Makefile与lds

    makefile的自动化&#xff0c;需要使用变量&#xff0c;以及自动变量。 实行命令行与参数的分离。 命令行只与变量打交道&#xff0c;而变量则携带不同的参数&#xff0c;这样&#xff0c;通过修改变量&#xff0c;命令的执行结果不同。 可以简单理解为&#xff0c;命令行是个…...

    2024/4/23 6:24:35
  4. 【图论】知识点集合

    边的类型 neighbors(邻居)&#xff1a;两个顶点有一条共同边 loop&#xff1a;链接自身 link&#xff1a;两个顶点有一条边 parallel edges&#xff1a;两个顶点有两条及以上条边 无向图 必要条件&#xff1a;删掉顶点数一定大于等于剩下的顶点数 设无向图G<V,E>是…...

    2024/4/25 6:59:51
  5. 【外汇早评】美通胀数据走低,美元调整

    原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...

    2024/4/26 18:09:39
  6. 【原油贵金属周评】原油多头拥挤,价格调整

    原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...

    2024/4/26 20:12:18
  7. 【外汇周评】靓丽非农不及疲软通胀影响

    原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...

    2024/4/26 23:05:52
  8. 【原油贵金属早评】库存继续增加,油价收跌

    原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...

    2024/4/27 4:00:35
  9. 【外汇早评】日本央行会议纪要不改日元强势

    原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...

    2024/4/25 18:39:22
  10. 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响

    原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...

    2024/4/25 18:39:22
  11. 【外汇早评】美欲与伊朗重谈协议

    原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...

    2024/4/26 21:56:58
  12. 【原油贵金属早评】波动率飙升,市场情绪动荡

    原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...

    2024/4/27 9:01:45
  13. 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试

    原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...

    2024/4/26 16:00:35
  14. 【原油贵金属早评】市场情绪继续恶化,黄金上破

    原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...

    2024/4/25 18:39:16
  15. 【外汇早评】美伊僵持,风险情绪继续升温

    原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...

    2024/4/25 18:39:16
  16. 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势

    原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...

    2024/4/26 19:03:37
  17. 氧生福地 玩美北湖(上)——为时光守候两千年

    原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...

    2024/4/26 22:01:59
  18. 氧生福地 玩美北湖(中)——永春梯田里的美与鲜

    原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...

    2024/4/25 18:39:14
  19. 氧生福地 玩美北湖(下)——奔跑吧骚年!

    原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...

    2024/4/26 23:04:58
  20. 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!

    原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...

    2024/4/25 2:10:52
  21. 「发现」铁皮石斛仙草之神奇功效用于医用面膜

    原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...

    2024/4/25 18:39:00
  22. 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者

    原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...

    2024/4/26 19:46:12
  23. 广州械字号面膜生产厂家OEM/ODM4项须知!

    原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...

    2024/4/27 11:43:08
  24. 械字号医用眼膜缓解用眼过度到底有无作用?

    原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...

    2024/4/27 8:32:30
  25. 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...

    解析如下&#xff1a;1、长按电脑电源键直至关机&#xff0c;然后再按一次电源健重启电脑&#xff0c;按F8健进入安全模式2、安全模式下进入Windows系统桌面后&#xff0c;按住“winR”打开运行窗口&#xff0c;输入“services.msc”打开服务设置3、在服务界面&#xff0c;选中…...

    2022/11/19 21:17:18
  26. 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。

    %读入6幅图像&#xff08;每一幅图像的大小是564*564&#xff09; f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...

    2022/11/19 21:17:16
  27. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...

    win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面&#xff0c;在等待界面中我们需要等待操作结束才能关机&#xff0c;虽然这比较麻烦&#xff0c;但是对系统进行配置和升级…...

    2022/11/19 21:17:15
  28. 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...

    有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows&#xff0c;请勿关闭计算机”的提示&#xff0c;要过很久才能进入系统&#xff0c;有的用户甚至几个小时也无法进入&#xff0c;下面就教大家这个问题的解决方法。第一种方法&#xff1a;我们首先在左下角的“开始…...

    2022/11/19 21:17:14
  29. win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...

    置信有很多用户都跟小编一样遇到过这样的问题&#xff0c;电脑时发现开机屏幕显现“正在配置Windows Update&#xff0c;请勿关机”(如下图所示)&#xff0c;而且还需求等大约5分钟才干进入系统。这是怎样回事呢&#xff1f;一切都是正常操作的&#xff0c;为什么开时机呈现“正…...

    2022/11/19 21:17:13
  30. 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...

    Win7系统开机启动时总是出现“配置Windows请勿关机”的提示&#xff0c;没过几秒后电脑自动重启&#xff0c;每次开机都这样无法进入系统&#xff0c;此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一&#xff1a;开机按下F8&#xff0c;在出现的Windows高级启动选…...

    2022/11/19 21:17:12
  31. 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...

    有不少windows10系统用户反映说碰到这样一个情况&#xff0c;就是电脑提示正在准备windows请勿关闭计算机&#xff0c;碰到这样的问题该怎么解决呢&#xff0c;现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法&#xff1a;1、2、依次…...

    2022/11/19 21:17:11
  32. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...

    今天和大家分享一下win7系统重装了Win7旗舰版系统后&#xff0c;每次关机的时候桌面上都会显示一个“配置Windows Update的界面&#xff0c;提示请勿关闭计算机”&#xff0c;每次停留好几分钟才能正常关机&#xff0c;导致什么情况引起的呢&#xff1f;出现配置Windows Update…...

    2022/11/19 21:17:10
  33. 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...

    只能是等着&#xff0c;别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚&#xff0c;只能是考虑备份数据后重装系统了。解决来方案一&#xff1a;管理员运行cmd&#xff1a;net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...

    2022/11/19 21:17:09
  34. 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?

    原标题&#xff1a;电脑提示“配置Windows Update请勿关闭计算机”怎么办&#xff1f;win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢&#xff1f;一般的方…...

    2022/11/19 21:17:08
  35. 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...

    关机提示 windows7 正在配置windows 请勿关闭计算机 &#xff0c;然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;关机提示 windows7 正在配…...

    2022/11/19 21:17:05
  36. 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...

    钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...

    2022/11/19 21:17:05
  37. 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...

    前几天班里有位学生电脑(windows 7系统)出问题了&#xff0c;具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面&#xff0c;长时间没反应&#xff0c;无法进入系统。这个问题原来帮其他同学也解决过&#xff0c;网上搜了不少资料&#x…...

    2022/11/19 21:17:04
  38. 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...

    本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法&#xff0c;并在最后教给你1种保护系统安全的好方法&#xff0c;一起来看看&#xff01;电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中&#xff0c;添加了1个新功能在“磁…...

    2022/11/19 21:17:03
  39. 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...

    许多用户在长期不使用电脑的时候&#xff0c;开启电脑发现电脑显示&#xff1a;配置windows更新失败&#xff0c;正在还原更改&#xff0c;请勿关闭计算机。。.这要怎么办呢&#xff1f;下面小编就带着大家一起看看吧&#xff01;如果能够正常进入系统&#xff0c;建议您暂时移…...

    2022/11/19 21:17:02
  40. 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...

    配置windows update失败 还原更改 请勿关闭计算机&#xff0c;电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;配置windows update失败 还原更改 请勿关闭计算机&#x…...

    2022/11/19 21:17:01
  41. 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...

    不知道大家有没有遇到过这样的一个问题&#xff0c;就是我们的win7系统在关机的时候&#xff0c;总是喜欢显示“准备配置windows&#xff0c;请勿关机”这样的一个页面&#xff0c;没有什么大碍&#xff0c;但是如果一直等着的话就要两个小时甚至更久都关不了机&#xff0c;非常…...

    2022/11/19 21:17:00
  42. 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...

    当电脑出现正在准备配置windows请勿关闭计算机时&#xff0c;一般是您正对windows进行升级&#xff0c;但是这个要是长时间没有反应&#xff0c;我们不能再傻等下去了。可能是电脑出了别的问题了&#xff0c;来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...

    2022/11/19 21:16:59
  43. 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...

    我们使用电脑的过程中有时会遇到这种情况&#xff0c;当我们打开电脑之后&#xff0c;发现一直停留在一个界面&#xff1a;“配置Windows Update失败&#xff0c;还原更改请勿关闭计算机”&#xff0c;等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢&#xff0…...

    2022/11/19 21:16:58
  44. 如何在iPhone上关闭“请勿打扰”

    Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...

    2022/11/19 21:16:57