本次串讲的主要目的在于给我们移动端的同学揭秘下目前前端开发的现状,和一些典型框架或者说是库的产生背景、以及设计思想和解决了什么样的问题。以 Vue.js 为例。此次讲解围绕以下几个方面展开:

  • MV* 框架模式
  • Vue.js 的概述
  • Vue MVVM 的实现
  • Vue 与 React 的对比
  • 有 Vue 基础如何快速上手 Weex

MV* 框架模式

历史

最早期的 Web 开发是洪荒时代,开发者可能写着类似以下的代码。检查用户的输入合法性,然后提交用户的表单字段到达服务器。服务器再校验一遍用户的合法性

<html><head><meta charset="UTF-8"><meta name="description" content="洪荒时代开发Web网页"><title>洪荒时代</title><meta></head><body><form action="http://sdg.com/login" method="POST" οnsubmit="return validate();"><label for="username">用户名</label><input type="text" name="username" id="username" placeholder="请输入用户名"><label for="password">密码</label><input type="password" name="password" id="password" placeholder="请输入密码"><input type="submit"></form></body><script>/** 判断字符串是否为空*/function isNotEmptyStr($str) {if($str == "" || $str == undefined || $str == null || $str == "null") {return false;}return true;}function validate () {var username = document.getElementById("username").value;var password = document.getElementById("password").value;if (!isNotEmptyStr(username)) {alert("请输入用户名");return false;}if (!isNotEmptyStr(password)) {alert("请输入密码");return false;}}</script>
</html>
$username = addslashes($_REQUEST['username']);
$password = md5($_REQUEST['password']);
//数据表$table = "user";//3.得到连接对象
$PdoMySQL = new PdoMySQL();
if ($action == "login") {$salt = "CRO";$identidier = md5($salt.md5($username.$salt));$token = md5(uniqid(rand(),true));$time = time()+60*60*24*7;$currentime = time();$allrow = $PdoMySQL->find($table,"username='{$username}' and password='{$password}'");$PdoMySQL->update(["time"=>$time,"identifier"=>$identidier],$table,"username='{$username}' and password='{$password}'");$autoRows = $PdoMySQL->find($table,"username='".$username."' and identifier='".$userid."'");if(count($autoRows) == 1){if($currentime < $autoRows[0]["time"]){setcookie('auth',base64_encode($autoRows[0]["id"]));// 跳转到主页 }else{// 给出用户信息失败的提示 alert}}
}

再到后来 Javascript 技术的发展越来越完善,网页开发有了更复杂的 JS 动画、CSS的特性也越来越强,让洪荒时代的 web 开发步入到“火药文明时代”。一些大型应用的场景,页面的数据状态非常多,传统的页面开发方式有了一些问题。

  1. 比如页面一个报错如果是服务端渲染,那么 error 信息直接显示到页面上。对于用户而言这些 error 信息很懵逼,体验很不好
  2. error 信息里面有你的服务端信息,比如什么语言,什么框架,什么版本,什么引擎、什么服务器,这些东西对于不怀好心的 Eve 就可以利用现有漏洞去攻击服务器
  3. 开发维护方式很不友好。假如你的页面有报错信息,你甚至需要前端开发者和服务端开发者一起去排查问题。开发方式就是前端开发者写模版代码,写好之后将代码交给服务端开发者,服务端开发者根据业务,去操作数据库执行 SQL ,再通过类似于 JSP、PHP 这种传统的技术渲染页面。开发效率极低。

后来诞生了 ajax 技术。通过 ajax 提高一个较好的体验( 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。Ajax 在浏览器与 Web 服务器之间使用异步数据传输(HTTP 请求),这样就可使网页从服务器请求少量的信息,而不是整个页面)。有了 ajax 赋能前端开发采用了前后端分离的方案,服务端、前端各司其职。前后端开发者通过接口通信,前端开发者专心做提高用户体验的前端事情,比如写酷炫的动画。传统的服务端渲染的路子走不通了。在此背景下催生了 REST api 。前端开发人员高兴坏了,开发者有了能力去开发大型应用。

再到后来旧版本、性能低、不主动拥抱变化的浏览器逐渐淘汰,体验不好,用户自然不愿意去用,那么就要淘汰。移动智能设备的诞生让传统的 PC 页面开始在移动端进行尝试,发现效果还可以。当用户也越来越挑剔、用户体验的要求也越来越高。那么传统的开发方式也不能满足现在的需求了。用户多了,业务复杂了,那么 MVC 也满足不了现在开发者的要求,于是 MVVM 诞生了。当然前端也在搞工程化。

应用越复杂,现有状况就是数据状态分散在 model 和 view 中。假如Jquery时代经常将数据隐藏在form表单中只不过是隐藏的。比如 <input class="hidden" id="userId" name="userId"> 点击按钮更新用户信息的时候经常需要将隐藏的数据也提交掉。在此背景下诞生了最早一批的框架,代表有 Backbone、Ember。

MV* 说明(MVC、MVP、MVVM…)

  1. 先不讲 MVC 是什么,先谈谈软件设计的一些原则和理念。
    • 可靠性:应用的功能可以正常使用
    • 健壮性:在用户非正常使用的时候,应用也可以正常反应,不要奔溃
    • 效率性:启动时间、响应时间、效率等在用户可以容忍范围之内

以上3点是表象层的东西,大多数开发者或者团队都会注意。除了这三点,还有一些东西是需要在工程层面需要注意的方面。

- 可拓展性:软件不是一次性产品,需要不断的迭代更新
- 容易理解:代码易读、规范
- 可测试性:代码能够方便的编写单元测试和集成测试
- 可复用性:可复用,不需要一次次编写轮子

于是,软件设计领域有了几个通用设计原则帮助我们实现这些目标:单一功能原则、聚合复用原则、接口隔离原则、依赖倒置原则…

基于这些设计目标和理念又有了设计模式:MVC、MVVM 就属于这个范畴。

  1. MV*

MVC

  • MVC:Model(模型) + View(视图) + Controller(控制器),主要目的在于分层,各司其职。 View 通过 Controller 来和 Model 联系。Controller 用来管理 View 和 Model。View 将事件传递给 Controller,Controller 完成业务逻辑后要求 Model 改变,Model 将新的数据发送到 View,用户得到反馈。

MVP

  • MVP:从 MVC 演变而来,都通过 Presenter/Controller 负责逻辑处理,View 负责界面展示,Model 负责数据。在 MVP 中主要逻辑在 Presenter 中。View 与 Model 不发生联系,都通过 Presenter 传递。View 层非常薄,不部署任何业务逻辑,没有任何主动性,而 Presenter非常厚,所有逻辑都部署在那里。

MVVM

  • MVVM:将 MVP 中的 中,Presenter 变成了 ViewModel,View 的变动会自动同步到 ViewModel,ViewModel 的变化也会同步到 View 上,这种同步的实现是对 ViewModel 中的属性实现了 Observer,当对属性存取会触发 setter 和 getter,都会触发对应的操作。

Vue.js

对于 Vue.js 来说不只是技术的革新也是开发方式的革新。前端框架和移动端框架的差异:前端框架更像是革命性的革新,连开发方式都是天翻地覆的变化。前端里面 MVVM 的思想每个库基本都有实现;移动端的话比较少,几个大厂才有实现方式,但是使用起来感觉并不是很美好。
举个例子:iOS 端的 ReactiveCocoa 使用起来高学习门槛、易出错、调试困难、风格不统一等被诟病。后来美团自研了 EasyReact。它的诞生是为了解决 iOS 工程实现 MVVM 架构但没有对应的框架支撑,而导致的风格不统一、可维护性差、开发效率低等多种问题。而 MVVM 中最重要的一个功能就是绑定,EasyReact 就是为了让绑定和响应式的代码变得 Easy 起来。

什么是 Vue.js

Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。

在我看来 Vue.js 的核心思想就是「数据驱动、组件化开发、虚拟Dom」。当然结合它的脚手架让你开发一个复杂且良好的大型应用变得很容易。下面看一个 Demo 来说明下 Vue.js 的强大威力。

<html><head><title>Vue</title><style>div{margin: 50px;}input {border: 1px solid cyan;height: 30px;line-height: 30px;}p {font-size: 30px;}</style></head><script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script><body><div id="el"><input type="text" v-model="username"><p>{ {username} }</p><ul><li v-for="(el,index) in hobby" :id="index">{ {el.msg} }</li></ul> </div> </body><script>var vm = new Vue({el: '#el',data () {return {username: '@杭城小刘',hobby:  [{msg: '电影'},{msg: '美食'},{msg: '旅游'},{msg: '乒乓球'},{msg: '编程'}]}}})</script>
</html>

在上面的代码中就声明了一个 MVVM 框架的 Web 应用,怎么体现?你可以在打开 Chrome 的调试界面,快捷键为 Command + Option + i,你可以在 console 中输入以下指令,可以看到界面会自动更新

vm.$data.username = '刘斌鹏'
vm.username = '刘斌鹏'
vm._data.username = '刘斌鹏'vm.$data.hobby.push({msg: '探索本质'})  
vm.$data.hobby.pop()
vm.$data.hobby.shift()

为什么呢?底层实现原理是通过 new Vue({}) 声明了一个 MVVM 对象,绑定的 View 通过 el 获取到,数据就是原生的 Javascript 对象,这个 ViewModel 将 View 和 Model 绑定在一起, View 和 Model 不直接联系,但是 v-model="username" 是个什么鬼? v-model 是 Vue.js 中的一个指令,底层实现就是 Vue.js 将该 input 的值和 Model 中的 username 进行了绑定,代码如下

<input v-bind:value="username" v-on:input="sth=$event.target.value">

我们通过 ViewModel 操纵的是 Model 当 Model 中的数据改变,假如通过 vm.$data.username 就会触发属性的 getter,如果通过 vm.$data.username = '刘斌鹏' 访问的就是属性的 setter,Vue 观察到属性变化会自动操作 View 的响应式变化。

如何学习(前置条件)

  • npm
    npm其实是Node.js的包管理工具(package manager)。开发时,会用到很多别人写的JavaScript代码。如果我们要使用别人写的某个包,每次都根据名称搜索一下官方网站,下载代码,解压,再使用,非常繁琐。于是一个集中管理的工具应运而生:大家都把自己开发的模块打包后放到 npm 官网上,如果要使用,直接通过npm安装就可以直接用,不用管代码存在哪,应该从哪下载。更重要的是,如果我们要使用模块A,而模块A又依赖于模块B,模块B又依赖于模块X和模块Y,npm可以根据依赖关系,把所有依赖的包都下载下来并管理起来。否则,靠我们自己手动管理,肯定既麻烦又容易出错。

  • AMD、CommonJS、CMD 等规范

    1. CommonJS 规范
      由于为了编写大型应用程序,代码不可能编写在一个文件里,所以代码(函数、变量)分散在多个文件里面,每个应用程序都有相应的解决方案,在 Node 中就是“模块”。模块的好处也是不言而喻的,当你编写好某个功能拓展的时候可以很方便的集成到其他的模块中去引用。那么 Node 如何实现模块?由于 Javascript 是函数式编程语言,所以可以利用闭包实现。将我们的代码用闭包实现起来就可以实现将“变量”只在当前代码内有效,外部无法访问,实现了模块的隔离。所以我们可以将需要暴露出去的东西暴露给外部,这样子就可以组织大型应用程序的开发

      模拟 CommonJS 的实现

      // 准备module对象:
      var module = {id: 'hello',exports: {}
      };
      var load = function (module) {// 读取的hello.js代码:function greet(name) {console.log('Hello, ' + name + '!');}module.exports = greet;// hello.js代码结束return module.exports;
      };
      var exported = load(module);
      // 保存module:
      save(module, exported);
      

      上述代码就可以实现将所需要的东西实现模块。CommonJS 规范使用步骤:1. 编写代码逻辑,通过 module.export = 变量; 暴露给外部;2. 调用者通过 let 变量名 = require('模块名') 来导入所需要的模块,用一个变量去承接,然后访问属性和方法
      2.由于 CommonJS 中的规范针对于 Node 很适合,因为代码文件是放在服务端磁盘,所以是同步的,读取速度很快,代码同步执行没问题。但是要在浏览器端使用这套规范显然是行不通的。为什么?看看下面代码有什么问题?

    let Hello = require('./Hello');
    Hello.sayHi()
    

    用户访问页面后卡死了?因为浏览器的环境下代码资源都需要通过网络获取,所以会比较慢,如果是同步用户访问的话基本上不会去第二次访问你的网站了。在此背景下产生了针对浏览器环境下的模块问题的 AMD 规范(Asynchronous Module Definition),想一想如果是你的话如何设计?采用异步加载的方式,模块的加载不影响后续代码的执行,如果遇到的代码是依赖于模块,那么这些代码都会被放到一个回调函数中,等模块加载完毕才会去执行回调函数里面的内容。AMD 也采用 require() 语句,不同于 CommonJS 它要求2个参数。

    reuqire([module], callback)
    

    说明:第一个参数是一个数组,里面是要加载模块;第二个参数 callback 是加载成功的回调函数。比如

    require(['./Hello'], () => {Hello.sayHi()
    })
    
  • Webpack
    查看以前的文章 Webpack、webpack-dev-server

  • ES6
    几个概念:ES、JS、CoffeeScript、TypeScript
    ES(ECMAScript):标准
    JS:浏览器对其的实现
    CoffeeScript:可以编译为 Javascript,抛弃 JS 中一些不好的设计
    TypeScript 是现今对 JavaScript 的改进中,唯一完全兼容并作为它的超集存在的解决方案

  • Flexbox
    传统布局解决方案比如盒模型在实现一些效果的时候不是很方便,所以 W3C 在2009年提出了 Flex 布局系统。
    Flex参考资料

  • html、CSS
    MDN

如何学习、进阶

学习

- 看着 [Vue官方文档](https://cn.vuejs.org/v2/guide/) 边看边写,因为在你 coding 的时候是拿着键盘写代码的,也需要感觉,所以平时多敲代码,边思考
- 对于没有接触过 ES6 和 Webpack 的童鞋来说,不建议直接用官方的脚手架 **vue-cli** 构件项目。所以先花点时间去学习下 ES6 的威力和 Webpack 解决了什么样的问题和它的简单用法
- 了解下 npm 的概念和解决了什么样的问题
- 一些 CSS 的知识
- 等适应了 Vue-cli 和工程构建方式以及代码组织方式后可以看看 Vue-Router、Vuex
- Vue-Router、Vuex 应用到工程项目中去,做一个 TodoList 项目
- 项目结束复盘、review 下
- [项目 Vue 小结](./2.17.md)

进阶

- [Vue 代码风格指南](https://cn.vuejs.org/v2/style-guide/#避免-v-if-和-v-for-用在一起-必要)
- ES6 吃透(万变不离其宗,不要一昧追求新技术,掌握本质核心)
- 封装高阶组件(slot 等技术点)
- 设计优秀良好的组件(比如用 TS 书写代码类型更为安全)
- 封装公司或者业务线或者产品为核心点的组件库
- 关注代码实现原理
- 关注前端的技术社区:[segmentfault](https://segmentfault.com)...
- 思考 Vue 框架设计的思想。类比其他框架甚至是大前端如何实现或者有没有类似的问题
- 尝试找到应用的性能症结所在,分析问题,给出解决方案并优化
- 参加行业的大会。VueConf、ReactConf

MVVM 实现原理

几种实现双向绑定的实现原理。

看看下面的代码

var Book = {};var name = '';Object.defineProperty(Book, 'name', {set: function (value) {name = value;console.log('本书名称叫做:' + value);},get: function () {return '<' + name + '>';}});
Book.name = 'Vue.js 权威指北'
console.log(`我买了本书叫做${Book.name}`);

Object.defineProperty

发现打印出来的东西和 Vue console 中输出基本一直,所以猜想 Vue 的实现也是依赖 Object.defineProperty

目前主流的框架基本都实现了单向数据绑定,在我看来双向数据绑定无非就是在单项数据绑定的基础上实现了给可输入元素(input、textarea)添加了 change(input)事件来动态修改 Model 和 View,所以我们的注意力不需要注意双向还是单向数据绑定。Vue 支持单双向数据绑定。

实现数据绑定的做法大致有如下几种方式:

  • 发布者-订阅者模式:Backbone.js。不去讨论
  • 脏值检查:Angular.js。基本通过 DOM 事件、比如用户输入、按钮点击、XHR 响应事件、浏览器 Location 变更事件、Timer、apply 等
  • 数据劫持:Vue.js。通过数据劫持结合发布者-订阅者模式实现。Object.defineProperty() 拦截属性的 setter 和 getter。在数据变动的时候发布消息给订阅者、触发相应的监听回调。

思路整理:

  • 实现一个属性监听器 Observer,能够对数据对象的所有属性进行监听,如果有变动则将最新的值通知给订阅者
  • 实现一个指令解析 Compiler,对每个元素节点进行扫描和解析,根据指令模版替换数据,以及绑定相应的更新函数
  • 实现一个 Wacther,作为连接 Observer 和 Compiler 的桥梁,能够订阅并观察到每个属性的变化通知,执行指令绑定的相应回调,从而更新视图
  • MVVM 入口函数,整合Observer、Compiler、Wacther

MVVM

看几个属性:Object.defineProperty 中的 writable 和 configurable 和 enumerable 的理解
configurable 如果为 false 则不可以修改, 不可以删除。writable 如果设置为 false 则不可以采用数据运算符进行赋值
做个实验看看特殊情况。如果 writable 为 true 的时候, configurable 为 false 结果如何?

var o = {}; // 创建一个新对象
Object.defineProperty(o, "a", {value : "original",writable : false, // 这个地方为 falseenumerable : true,configurable : true
});
o.a = 'LBP'; 
console.log(o.a) // "original" 此时候, 是更改不了 a 的.var o = {}; // 创建一个新对象
Object.defineProperty(o, "a", {value : "original",writable : true,enumerable : true,configurable : false //这里为false
});
o.a = "LBP";
console.log(o.a) //LBP.此时候, a 进行了改变delete o.a // 返回 false

结论:onfigurable 控制是否可以删除; writable 控制是否可以修改(赋值); enumerable 控制是否可以枚举

  1. 实现 Observer
    可以利用 Obeject.defineProperty() 来监听属性变动,将需要 Observe 的数据对象进行递归遍历,包括子属性对象的属性,都加上 setter 和 getter
    给这个对象的某个值赋值就会触发setter,那么就能监听到了数据变化。
var data = {name: '杭城小刘'};
observe(data);
data.name = 'LBP'; function observe(data) {if (!data || typeof data !== 'object') {return;}// 取出所有属性遍历Object.keys(data).forEach(function(key) {defineReactive(data, key, data[key]);});
};function defineReactive(data, key, val) {observe(val); // 监听子属性Object.defineProperty(data, key, {enumerable: true, // 可枚举configurable: false, //不能再deleteget: function() {return val;},set: function(newVal) {console.log('哈哈哈,监听到值变化了 ', val, ' --> ', newVal);val = newVal;}});
}

这样我们已经可以监听每个数据的变化了,那么监听到变化之后就是怎么通知订阅者了,所以接下来我们需要实现一个消息订阅器,很简单,维护一个数组,用来收集订阅者,数据变动触发 notify,再调用订阅者的 update 方法,代码改善之后是这样:

...
function defineReactive(data, key, val) {var dep = new Dep();observe(val); // 监听子属性Object.defineProperty(data, key, {... set: function(newVal) {if (val === newVal) return;console.log('哈哈哈,监听到值变化了 ', val, ' --> ', newVal);val = newVal;dep.notify(); // 通知所有订阅者}});
}function Dep() {this.subs = [];
}
Dep.prototype = {addSub: function(sub) {this.subs.push(sub);},notify: function() {this.subs.forEach(function(sub) {sub.update();});}
};

那么问题来了,谁是订阅者?怎么往订阅器添加订阅者?
没错,上面的思路整理中我们已经明确订阅者应该是 Watcher, 而且 var dep = new Dep() 是在 defineReactive 方法内部定义的,所以想通过 dep 添加订阅者,就必须要在闭包内操作,所以我们可以在 getter里面动手脚:

// Observer.js
...
Object.defineProperty(data, key, {get: function() {// 由于需要在闭包内添加watcher,所以通过Dep定义一个全局target属性,暂存watcher, 添加完移除Dep.target && dep.addDep(Dep.target);return val;}... 
});// Watcher.js
Watcher.prototype = {get: function(key) {Dep.target = this;this.value = data[key];	// 这里会触发属性的getter,从而添加订阅者Dep.target = null;}
}

这里已经实现了一个 Observer 了,已经具备了监听数据和数据变化通知订阅者的功能

  1. 实现 Compile

compile 主要做的事情是解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图,如图所示:
MVVM-Compile

因为遍历解析的过程有多次操作dom节点,为提高性能和效率,会先将根节点 el 转换成文档碎片 fragment 进行解析编译操作,解析完成,再将 fragment 添加回原来的真实dom节点中

function Compile(el) {this.$el = this.isElementNode(el) ? el : document.querySelector(el);if (this.$el) {this.$fragment = this.node2Fragment(this.$el);this.init();this.$el.appendChild(this.$fragment);}
}
Compile.prototype = {init: function() { this.compileElement(this.$fragment); },node2Fragment: function(el) {var fragment = document.createDocumentFragment(), child;// 将原生节点拷贝到fragmentwhile (child = el.firstChild) {fragment.appendChild(child);}return fragment;}
};

compileElement 方法将遍历所有节点及其子节点,进行扫描解析编译,调用对应的指令渲染函数进行数据渲染,并调用对应的指令更新函数进行绑定,详看代码及注释说明:

Compile.prototype = {... compileElement: function(el) {var childNodes = el.childNodes, me = this;[].slice.call(childNodes).forEach(function(node) {var text = node.textContent;var reg = /\{\{(.*)\}\}/;	// 表达式文本// 按元素节点方式编译if (me.isElementNode(node)) {me.compile(node);} else if (me.isTextNode(node) && reg.test(text)) {me.compileText(node, RegExp.$1);}// 遍历编译子节点if (node.childNodes && node.childNodes.length) {me.compileElement(node);}});},compile: function(node) {var nodeAttrs = node.attributes, me = this;[].slice.call(nodeAttrs).forEach(function(attr) {// 规定:指令以 v-xxx 命名// 如 <span v-text="content"></span> 中指令为 v-textvar attrName = attr.name;	// v-textif (me.isDirective(attrName)) {var exp = attr.value; // contentvar dir = attrName.substring(2);	// textif (me.isEventDirective(dir)) {// 事件指令, 如 v-on:clickcompileUtil.eventHandler(node, me.$vm, exp, dir);} else {// 普通指令compileUtil[dir] && compileUtil[dir](node, me.$vm, exp);}}});}
};// 指令处理集合
var compileUtil = {text: function(node, vm, exp) {this.bind(node, vm, exp, 'text');},...bind: function(node, vm, exp, dir) {var updaterFn = updater[dir + 'Updater'];// 第一次初始化视图updaterFn && updaterFn(node, vm[exp]);// 实例化订阅者,此操作会在对应的属性消息订阅器中添加了该订阅者watchernew Watcher(vm, exp, function(value, oldValue) {// 一旦属性值有变化,会收到通知执行此更新函数,更新视图updaterFn && updaterFn(node, value, oldValue);});}
};// 更新函数
var updater = {textUpdater: function(node, value) {node.textContent = typeof value == 'undefined' ? '' : value;}...
};

这里通过递归遍历保证了每个节点及子节点都会解析编译到,包括了{ {} }表达式声明的文本节点。指令的声明规定是通过特定前缀的节点属性来标记,如 <span v-text="content" other-attrv-text 便是指令,而 other-attr 不是指令,只是普通的属性。
监听数据、绑定更新函数的处理是在compileUtil.bind() 这个方法中,通过 new Watcher() 添加回调来接收数据变化的通知

  1. 实现Watcher

Watcher 订阅者作为 Observer 和 Compile 之间通信的桥梁,主要做的事情是:
1、在自身实例化时往属性订阅器(dep)里面添加自己
2、自身必须有一个 update() 方法
3、待属性变动 dep.notice() 通知时,能调用自身的 update() 方法,并触发 Compile 中绑定的回调,则功成身退。

function Watcher(vm, exp, cb) {this.cb = cb;this.vm = vm;this.exp = exp;// 此处为了触发属性的getter,从而在dep添加自己,结合Observer更易理解this.value = this.get(); 
}
Watcher.prototype = {update: function() {this.run();	// 属性值变化收到通知},run: function() {var value = this.get(); // 取到最新值var oldVal = this.value;if (value !== oldVal) {this.value = value;this.cb.call(this.vm, value, oldVal); // 执行Compile中绑定的回调,更新视图}},get: function() {Dep.target = this;	// 将当前订阅者指向自己var value = this.vm[exp];	// 触发getter,添加自己到属性订阅器中Dep.target = null;	// 添加完毕,重置return value;}
};
// 这里再次列出Observer和Dep,方便理解
Object.defineProperty(data, key, {get: function() {// 由于需要在闭包内添加watcher,所以可以在Dep定义一个全局target属性,暂存watcher, 添加完移除Dep.target && dep.addDep(Dep.target);return val;}...
});
Dep.prototype = {notify: function() {this.subs.forEach(function(sub) {sub.update(); // 调用订阅者的update方法,通知变化});}
};

实例化 Watcher 的时候,调用 get() 方法,通过 Dep.target = watcherInstance 标记订阅者是当前watcher实例,强行触发属性定义的 getter 方法,getter 方法执行的时候,就会在属性的订阅器 dep 添加当前 watcher 实例,从而在属性值有变化的时候,watcherInstance 就能收到更新通知。

  1. 实现MVVM

MVVM 作为数据绑定的入口,整合 Observer、Compile、Watcher 三者,通过 Observer 来监听自己的 Model 数据变化,通过Compile 来解析编译模板指令,最终利用 Watcher 搭起 Observer 和 Compile 之间的通信桥梁,达到数据变化 -> 视图更新;视图交互变化(input) -> 数据 Model 变更的双向绑定效果。

一个简单的 MVVM 构造器是这样子:

function MVVM(options) {this.$options = options;var data = this._data = this.$options.data;observe(data, this);this.$compile = new Compile(options.el || document.body, this)
}

但是这里有个问题,从代码中可看出监听的数据对象是 options.data,每次需要更新视图,则必须通过 var vm = new MVVM({data:{name: '杭城小刘'} }); vm._data.name = 'LBP'; 这样的方式来改变数据。

显然不符合我们一开始的期望,我们所期望的调用方式应该是这样的:
var vm = new MVVM({data: {name: '杭城小刘'} }); vm.name = 'LBP';

所以这里需要给 MVVM 实例添加一个属性代理的方法,使访问 vm 的属性代理为访问 vm._data 的属性,改造后的代码如下:

function MVVM(options) {this.$options = options;var data = this._data = this.$options.data, me = this;// 属性代理,实现 vm.xxx -> vm._data.xxxObject.keys(data).forEach(function(key) {me._proxy(key);});observe(data, this);this.$compile = new Compile(options.el || document.body, this)
}MVVM.prototype = {_proxy: function(key) {var me = this;Object.defineProperty(me, key, {configurable: false,enumerable: true,get: function proxyGetter() {return me._data[key];},set: function proxySetter(newVal) {me._data[key] = newVal;}});}
};

这里主要还是利用了 Object.defineProperty() 这个方法来劫持了 vm 实例对象的属性的读写权,使读写 vm 实例的属性转成读写了 vm._data 的属性值,达到鱼目混珠的效果

  1. 什么是单向绑定和双向绑定?
    单向绑定:将 Model 绑定到 View 上。当我们通过接口或者事件操作 Model 的改变的时候那么 View 的改变会自动触发,View 自动刷新改变。
  2. 双向绑定:将 Model 绑定到 View 上,通过也将 View 绑定到 Model 上。这样 View 的改变会触发 Model 的改变,Model 的改变也会自动触发 View 的自动更新。
  3. Vue 中如何实现单项数据绑定?
    • 通过插值表达式。通过 { {data} } 的形式将数据 Model 中的某个属性绑定到 Dom 节点上
    • 通过 v-bind 指令。通过 v-bind:class="hasError" 将某个 Model 的属性绑定到对应的属性上。这样 Vue 在识别到 v-bind 指令的时候会自动将属性跟 Model 绑定起来,这样就可以通过 ViewModel 操作 Model 来动态的更新 View 层。
  4. Vue 中实现双向绑定
    Vue 中通过 v-model 实现双向绑定。可以实现 View 到 Model 的双向绑定。View 变动了 Model 会跟着变, Model 变了 View 会自动更新。

Vue 与 React 的对比

先看看以下代码,针对同一个字符串反转的功能,2个库如何实现

<div id="app"><p>{ { message } }</p><button v-on:click="reverseMessage">Reverse Message</button>
</div>new Vue({el: '#app',data: {message: 'Hello Vue.js!},methods: {reverseMessage: function () {this.message = this.message.split('').reverse().join('');}}
});
 class App extends React.Component {constructor(props) {super(props);this.state = {message: 'Hello React.js!'};}reverseMessage() {this.setState({ message: this.state.message.split('').reverse().join('') });}render() {return (<div><p>{this.state.message}</p><button onClick={() => this.reverseMessage()}>Reverse Message</button></div>)}
}
ReactDOM.render(App, document.getElementById('app'));

相似之处:

  • 都有非常多的 star,开发者非常拥护
  • 都使用 Virtua DOM
  • 提供了响应式和组件化的视图组件
  • 将注意力放在核心实现,将其他功能比如路由、全局状态管理交给相关的库

差别:

  • React 严格上只针对 MVC 的 view 层,Vue 则是 MVVM 模式

  • 数据绑定: Vue 实现了数据的双向绑定,React 数据流动是单向的
    单向数据流是指数据的流向只能由父组件通过props将数据传递给子组件,不能由子组件向父组件传递数据,要想实现数据的双向绑定,只能由子组件接收父组件props传过来的方法去改变父组件的数据,而不是直接将子组件的数据传递给父组件。
    单向数据量组件props是父级往下传递,你不能向上去修改父组件的数据,并且也不能在自身组件中修改props的值。React不算mvvm,虽然可以实现双向绑定,在React中实现双向绑定通过state属性,但如果将state绑定到视图中时,直接修改state属性是不可的,需要通过调用setState去触发更新视图,反过来视图如果要更新也需要监听视图变化 然后调用setState去同步state状态。标准MVVM应该属于给视图绑定数据后,操作数据即是更新视图

  • virtual DOM 不一样,Vue 会跟踪每一个组件的依赖关系,不需要重新渲染整个组件树.而对于 React 而言,每当应用的状态被改变时,全部组件都会重新渲染,所以 React 中会需要 shouldComponentUpdate 这个生命周期函数方法来进行控制

  • 组件写法不一样, React推荐的做法是 JSX + inline style, 也就是把 HTML 和 CSS 全都写进 JavaScript 中,即 ‘all in js’; Vue 推荐的做法是 webpack+vue-loader 的单文件组件格式,即 html,css,JS 写在同一个文件

  • 代码书写方式
    使用 Vue 你可以很方便的将现有的工程迁移或者接入 Vue,因为工程现有的 HTML 就是 Vue 中的视图模版,你只需要做一些 Webpack 配置化的东西,代码改动成本低,后期不用 Vue 了你更换框架的成本也比较低。
    但是使用 React 你如果需要对现有工程接入的话成本很高,你甚至是重写代码,代码组织方式,工程处理方式基本也改变了。开发者可能需要适应一段时间,门槛稍高。

  • 运行时性能
    在 React 中当某个组件的状态发生变化的时候,它会以该组件为根,将所有的子组件树进行更新。对于如果知道不需要更新的组件可能需要使用 PureComponent 或者手动实现 shouldComponentUpdate 方法。Vue 中不需要额外注意这些事情,默认实现的。使得开发者专心做业务开发。
    Vue.js使用基于依赖追踪的观察并且使用异步队列更新。轻量,高性能

  • 开发方式
    在 React 中组件的渲染功能都依赖于 JSX(Javascript的一种语法糖,尽管这种方式对于 Javascript 来说很爽,但是对于已有业务进行重构是很麻烦的,为什么?你需要将你页面的东西拆分为组件,但是在 React 中组件的输出是靠 render 函数,render 函数内部不能直接写 HTML,而是需要 JSX 语法糖。
    Vue.js 在这方面就比较友好,对于已经有的项目可以低成本的接入,因为已有的 HTML 代码就是模版代码,然后将业务写入到 Script 标签,操作 ViewModel。虽然 Vue.js 的组件也支持 JSX 的方法来写代码,为的就是让 React 开发者很快上手。

    import React, { Component } from 'react';
    import { Image, ScrollView, Text } from 'react-native';class AwkwardScrollingImageWithText extends Component {render() {return (<ScrollView><Imagesource={ {uri: 'https://i.chzbgr.com/full/7345954048/h7E2C65F9/'} }style={ {width: 320, height:180} } /><Text>在iOS上,React Native的ScrollView组件封装的是原生的UIScrollView。在Android上,封装的则是原生的ScrollView。在iOS上,React Native的Image组件封装的是原生的UIImageView。在Android上,封装的则是原生的ImageView。React Native封装了这些基础的原生组件,使你在得到媲美原生应用性能的同时,还能受益于React优雅的架构设计。 </Text></ScrollView>);}
    }
    
  • 组件作用域内的 CSS
    React 中的 css 是通过 css-in-JS 来实现的,和传统书写 CSS 是有区别的,不是无缝对接的,
    Vue 中的 css 编写和传统的开发是一致的,你可以在  .vue 文件中对标签添加 scoped 属性来告诉 css-loader 这些 css 规则只在该模块内有效。

    <style scoped>
    @media (min-width: 250px) {.list-container:hover {background: orange;}
    }
    </style>
    

    这个属性的作用就是会自动添加一个属性,为组件内的 css 指定作用域,编译成 .list-container[data-v-21e5b78]:hover

  • 向上拓展
    React 和 Vue 都提供路由、全局状态管理的解决方案,区别在于 Vue 是官方维护的,React 则是社区维护的。(Vuex、Redux、Vue-Router)
    都有脚手架,Vue-cli 允许你自定义一些设备而 React 不支持。

  • 向下拓展
    React 学习曲线比较陡峭、也可以说对现有的工程改造门槛较高,需要大范围改写,相比 Vue 则较为友善点,侵入性低。可以像 jQuery 一样引入一个核心的 min.js 文件就可以改造接入现有工程。

  • 原生渲染
    React 有 React Native 一个较为成熟的方案,Vue 则有阿里的 Weex。差别在于你写了 React Native 应用则不能在浏览器运行,而 Weex 可以在浏览器中和移动设备上运行。所谓多端运行的能力,

  • 开发缺点
    Vue 中不能检测到属性的添加、删除,所以可以用类似 React 中的 set 方法。

有 Vue 基础如何快速上手 Weex

  1. quick demo

  2. 虽然都是采用 Vue.js 开发,但是存在 Weex 与平台的差异:上下文、DOM、样式、事件(Weex 不支持事件冒泡和捕获)、样式(Weex支持单个类选择器、并且只支持 CSS 规则的子集)、Vue 网页端的一些配置、钩子、在 Weex 中不支持

    • html 标签
      目前 Weex 支持了基本容器(div)、文本(text)、图片(image)、视频(video)等组件,但是需要注意是组件而不是标签,虽然写起来跟标签一样很像,但是写其他的标签必须和这些组合起来使用。类比 Native 的视图层级

    • Weex 中不存在 Dom
      Weex 解析 Vue 得到的不是 dom,而是原生布局树

    • 支持有限的事件
      因为在移动端中所有有些网页端的事件是不支持的,请查看支持的事件列表

    • 没有 BOM,但可以调用原生 Api
      DOM?BOM?
      javascript组成:ECMAScript 基本语法;BOM(Borwser Object Model:浏览器对象模型,使用对象模拟了浏览器的各个部分内容);DOM(Document Object Model:文档对象模型:浏览器加载显示网页的时候浏览器会为每个标签都创建一个对应的对象描述该标签的所有信息)

      在 Weex 中能够调用原生设备的 api,使用方法是通过注册、调用模块来实现的,其中一些模块是 Weex 内置的,比如 clipboard、navigator、storage 等。为了保持框架的通用性,Weex 内置的原生模块很有限,不过 Weex 提供了横向拓展的能力,可以拓展原生模块。具体参考 Androi 拓展、iOS 拓展

    • 样式差异
      Weex 中的样式是由原生渲染器解析的,出于性能和功能复杂角度的考虑,Weex 对于 css 特性做了一些取舍。(Weex 中只支持单个类名选择器,不支持关系选择器、也不知支持属性选择器;组件级别的作用域,为了保持 Web 和 Native 的一致性,需要使用 style scoped 的写法;支持基本的盒模型和 flexbox 的写法,box-sizing 默认为 border-box,margin,padding,border 属性不支持合并简写;不支持 display:none;可以用 display: 0; 代替,display < 0.01 的时候可以点击穿透;样式属性不支持简写、提高解析效率;css 不支持 3D 变化)

      • 单位
        Weex 中所有的 css 属性值单位为 px,也可以省略不写
      • Flexbox 支持不完全
        align-items: baseline;align-content:space-around;align-self:wrap_revserse;
      • 显隐性
        在 Weex 中的 iOS 和 Android 端不支持 display:none; 所以 v-show 条件渲染写法也是不支持的,可以用 v-if 代替,或者 display:0; 模拟。由于移动端的渲染特点是当 opacity < 0.01 的时候 view 是可以点击穿透,所以 Weex 中当元素 display < 0.01 的时候元素看不见,但是占位空间还在,但用户无法与之交互,同样点击时会发生穿透的效果。
      • css3
        相比 React Native 不能用 css3,Weex 的 css3 的支持程度算比较高,但是有一些 css3 的属性还是不支持的。transform 支持 2D;font-family 支持 ttf 和 woff 字体格式的自定义的字体;liner-gradient 只支持双色渐变
    • 调试方式
      如果说 React Native 的调试方式解放了原生开发调试、那么 Weex 就是赋予了 web 模式调试原生应用的能力。

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

相关文章

  1. javascript校验多个输入框input的值是否相等(前段校验)

    function saveDict(){//没有选择类型列表if(document.Form1.keyword.value"jerrynew"){if(Trim(document.Form1.keywordname.value)""){alert("请输入类型名称");return false;}var allkeywords document.Form1.keyword;for(var i0;i<allkeyw…...

    2024/4/21 13:30:59
  2. 小程序input提交后如何清空输入框数据:小程序与Vue的数据绑定方式

    前言 一直觉得,小程序与Vue有着神似之风。这一点在我第一天开始接触小程序时就这么认为,或者说,任何前端相关的语言,不管是node.js、Vue、angular、小程序,都和js有着千丝万缕的联系。 而最让我“着迷”的,莫过于曾让我夜夜辗转反侧的“ 数据传递(数据绑定) ”了。趁着…...

    2024/4/21 13:30:57
  3. 做埋线双眼皮手术需要多久恢复

    ...

    2024/4/20 15:56:09
  4. 做埋线双眼皮手术需要多久可以恢复

    ...

    2024/4/20 15:56:07
  5. VScode使用教程

    一、关于Vscode 1.1 VsCode是个啥 Visual Studio Code is a lightweight but powerful source code editor which runs on your desktop and is available for Windows, macOS and Linux. It comes with built-in support for JavaScript, TypeScript and Node.js and has a …...

    2024/4/20 2:25:03
  6. webstorm怎么运行调试html

    WebStorm教程&#xff08;一&#xff09;HTML5搭建&#xff1a;Hello&#xff0c;World&#xff01; 一.WebStrom 简介 三.建立一个HTML文件 1.打开WebStorm——Creat New Project——&#xff08;左边栏&#xff09;Empty Project——&#xff08;给项目命名&#xff09;—…...

    2024/4/20 15:56:05
  7. webstorm 2017.2 集成vuejs,运行方式

    学习vuejs第一步,配置环境遇到的问题,如何使用webstorm搭建vuejs的开发环境: 网上的webstorm运行vuejs都是这个版本: 但新版的已经没有了build\dev-server.js这个文件,谷歌了一下看到另一种方式,截图如下: 使用这种方式就可以一键运行vuejs的项目了....

    2024/4/20 15:56:05
  8. WebStorm 6.0下运行pomelo项目

    最近想使用WebStorm来写pomelo&#xff0c;初次使用WebStorm&#xff0c;网上找了老半天根本没有介绍WebStorm如何创建或者打开运行pomelo的教程&#xff0c;网易pomelo官网介绍的使用 WebStorm IDE 调试 Pomelo 应用程序&#xff0c;对于没有WebStorm使用经验的我来说&#xf…...

    2024/4/20 15:56:03
  9. 敏捷开发免费管理工具——火星人预览之五:常见问题问答

    这是火星人预览系列的第五篇(之一,之二,之三,之四,之五问答,之六,之七)。之一:需求与故事结构之二:编辑故事,产品管理,组织结构之三:迭代,计划会,分配任务之四:故事板,燃尽图,我的工作项之五:常见问题问答之六:我的空间,我的通知之七:自定义字段 常见问…...

    2024/5/3 2:43:39
  10. webstorm下的json-server

    目的 利用webstorm来可视化操作json-server 步骤与方法 打开面板 GET POST Post方法需要添加json数据 在 request Body -> text 中填写 其他不再列举...

    2024/4/20 15:56:01
  11. webstorm运行不了的问题!已解决

    如图一般webstorm安装后默认生成的快捷方式是针对32位jdk的 我们只需双击webstrom64.exe即可运行&#xff01; 转载于:https://my.oschina.net/u/3228182/blog/1599799...

    2024/4/21 13:30:57
  12. WebStorm2017.2.2安装与激活

    主要是WebStorm的安装与激活以及WeX5开发工具的连接 链接: WebStorm官网下载链接:http://www.jetbrains.com/webstorm/download/#section=windows WebStorm汉化链接:https://pan.baidu.com/s/1dGQijo1 密码:pgx9 WebStorm激活包链接:https://pan.baidu.com/s/1IJOtN…...

    2024/4/21 13:30:57
  13. webstorm 配置nodejs运行环境

    首先file-setting 除此之外&#xff0c;配置nodejs的运行路径 切记把这里改为项目的路径&#xff0c;这里路径的正确与否&#xff0c;关系着你在项目中引用路径。这里的路径也就是你项目中引用文件所对照的根目录。...

    2024/5/2 20:43:05
  14. 用webstorm创建运行vue项目

    准备工作&#xff0c;这些就不一一说明了&#xff0c;如果有不会的&#xff0c;可以去前面的教程里面看一看&#xff0c;找一找。 1&#xff1a;webstorm的安装&#xff1a; 2&#xff1a;node.js的安装 3&#xff1a;安装Git 4&#xff1a;vue-cli 1:初始化一个项目 打开cmd&a…...

    2024/4/21 13:30:53
  15. 关于webStorm一直频繁indexing导致项目运行变卡

    关于webStorm一直频繁indexing导致项目运行变卡 1&#xff0c;这里以vue项目为例&#xff1b;由于vue项目需要加载node_moudles依赖库&#xff0c;而这个文件异常的大&#xff1b;这里建议将webStorm调制成不要时时扫描该依赖&#xff1b; 操作如下&#xff1a; 1&#xff09;&…...

    2024/4/20 19:53:37
  16. WebStorm上运行vue2.0

    首先打开我们之前用vue-cli脚手架生成的项目&#xff0c;还没有创建项目的同学可以看我上一篇博客&#xff08;博客链接&#xff09; 1.打开WebStorm 2.点击open选择你项目的路径后打开。 3.之后在右上角&#xff0c;点击Edit Configurations 4.点击打开页面左侧的加号&#xf…...

    2024/4/21 13:30:51
  17. webstorm中用npm运行任务(显示npm面板)

    1、右击package.json文件&#xff0c;点击Show npm Scripts. 2 显示npm运行面板。自定义的运行环境 3 点击运行...

    2024/4/21 13:30:51
  18. 在webstorm中生成运行Android程序

    关于webStorm:http://www.jetbrains.com/webstorm/help/using-phonegap-cordova.html 总参考文档&#xff08;有错误--global 改成-g注意&#xff09;1.Make sure the PhoneGap and Cordova and the NodeJS plugins are enabled. 2.Download node.js from https://nodejs.org/e…...

    2024/4/21 13:30:49
  19. WebStorm 2020.3.2 安装教程

    WebStorm2020.3.2安装教程前言一、去官网下载对应的安装包二、双击打开下载好的安装包三、选择安装路径四、安装对应的配置五、直接下一步即可六、启动 WebStorm前言 此教程虽然是 WebStorm 安装教程&#xff0c;但其实与 IDEA 的安装方式相差无几&#xff0c;相信大家应该都可…...

    2024/4/21 13:30:48
  20. webstorm 如何快速运行命令行命令

    需求&#xff1a;用webstorm学习ReactNative 需要启动模拟器(Android Studio 中的模拟器) 步骤&#xff1a;1.打开Edit Configurations2.点击号 选择npm3.如下图所示4.点击下边的号 选择External tool5.如下图所示 启动命令 C:\Users\Administrator\AppData\Local\Android\Sdk…...

    2024/4/21 13:30:47

最新文章

  1. 等保测评考试重点题库分享上

    一、单选题 1、下列不属于网络安全测试范畴的是&#xff08;C&#xff09; A&#xff0e;结构安全 B.便捷完整性检查 C.剩余信息保护 D.网络设备防护 2、下列关于安全审计的内容说法中错误的是&#xff08;D&#xff09; A&#xff0e;应对网络系统中的网络设备运行情况、网…...

    2024/5/5 14:50:33
  2. 梯度消失和梯度爆炸的一些处理方法

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

    2024/3/20 10:50:27
  3. 《c++》多态案例一.电脑组装

    一.代码展示 #include <iostream> using namespace std; class CPU { public://抽象计算函数virtual void calculate() 0;};class CVideoCard { public://抽象显示函数virtual void display() 0;}; class Memory { public://抽象存储函数virtual void storage() 0;};…...

    2024/5/5 8:48:19
  4. 大数据学习十三天(hadhoop基础2)

    一: MapReduce概述(了解) MapReduce是hadoop三大组件之一,是分布式计算组件 Map阶段 : 将数据拆分到不同的服务器后执行Maptask任务,得到一个中间结果 Reduce阶段 : 将Maptask执行的结果进行汇总,按照Reducetask的计算 规则获得一个唯一的结果 我们在MapReduce计算框架的使用过…...

    2024/5/2 21:17:01
  5. 【外汇早评】美通胀数据走低,美元调整

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

    2024/5/4 23:54:56
  6. 【原油贵金属周评】原油多头拥挤,价格调整

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

    2024/5/4 23:54:56
  7. 【外汇周评】靓丽非农不及疲软通胀影响

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

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

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

    2024/5/4 23:55:17
  9. 【外汇早评】日本央行会议纪要不改日元强势

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

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

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

    2024/5/4 23:55:05
  11. 【外汇早评】美欲与伊朗重谈协议

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

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

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

    2024/5/4 23:55:16
  13. 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试

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

    2024/5/4 23:54:56
  14. 【原油贵金属早评】市场情绪继续恶化,黄金上破

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

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

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

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

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

    2024/5/4 23:55:17
  17. 氧生福地 玩美北湖(上)——为时光守候两千年

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

    2024/5/4 23:55:06
  18. 氧生福地 玩美北湖(中)——永春梯田里的美与鲜

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

    2024/5/4 23:54:56
  19. 氧生福地 玩美北湖(下)——奔跑吧骚年!

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

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

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

    2024/5/5 8:13:33
  21. 「发现」铁皮石斛仙草之神奇功效用于医用面膜

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

    2024/5/4 23:55:16
  22. 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者

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

    2024/5/4 23:54:58
  23. 广州械字号面膜生产厂家OEM/ODM4项须知!

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

    2024/5/4 23:55:01
  24. 械字号医用眼膜缓解用眼过度到底有无作用?

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

    2024/5/4 23:54:56
  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