js代码写Vue和React
一、前提
1. MVC情景
需要对一个数字进行加减1的操作,代码如下:
- <body>
- <div id="text">
-
- </div>
- <div>
- <input type="button" value="increase" id="btn1">
- <input type="button" value="decrease" id="btn2">
- </div>
- <script>
- var a = 0
- document.getElementById("text").innerHTML = a
-
- var btn1 = document.getElementById("btn1")
- var btn2 = document.getElementById("btn2")
- btn1.onclick =() => {a++
- document.getElementById("text").innerHTML = a}
- btn2.onclick = function(){
- a--
- document.getElementById("text").innerHTML = a
- }
- </script>
- </body>
1-1. 问题1
以上代码中,复用性可读性非常差,例如document.getElementById("text").innerHTML = a反复出现,可以通过封装函数render()解决
- btn1.onclick = () => {
- a++
- render()
- }
- btn2.onclick = function () {
- a--
- render()
- }
- render = () => {
- document.getElementById("text").innerHTML = a
- }
1-2. 问题2
能不能让a变化的时候,DOM自动变化? 例如制作一个虚拟DOM计算与实际DOM差异,再一次性更新进去;或者每当DOM有变化,简单让其上树操作等
1-3. 解决方案
Angular、React、Vue的根据以上问题,提出了解决方案,即MVVM框架,都能够实现数据变化视图自动变化。但是他们三个人的原理完全不同:
1.Angular:脏检查,词法分析,进行隐形的视图的更新;
2.React:setState()等调用视图函数,配合DIFF算法和Virtual DOM让DOM的变化效率更高;
3.Vue : 数据劫持
鉴于Angular太高深,我们以下只分析React与Vue
2. React
用js模拟react的原理
React中封装了一些函数,只有通过这些函数改变a属性的值,才能引发视图的变化。比如下面案例中的setstate()函数,通过setState()函数改变a属性值,会引发视图的变化。
-
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <meta http-equiv="X-UA-Compatible" content="ie=edge">
- <title>React原理</title>
- </head>
- <body>
- <div id="text">
- </div>
- <div>
- <input type="button" value="increase" id="btn1">
- <input type="button" value="decrease" id="btn2">
- </div>
- <script>
- render = () => {
- document.getElementById("text").innerHTML = obj.a
- }
- const obj = {
- a: 0
- }
- function setState(k, v) {
- obj[k] = v
- }
- render()
- var btn1 = document.getElementById("btn1")
- var btn2 = document.getElementById("btn2")
- btn1.onclick = () => {
- setState("a", obj.a + 1)
- render()
- }
- btn2.onclick = function () {
- setState("a", obj.a - 1)
- render()
- }
- </script>
- </body>
- </html>
用React的写法写一个简单计数器如下:
- class Counter extends React.Component {
- constructor(props) {
- super(props);
- this.state = {
- count: 0
- };
- // 套路1注册一个行为到this里,可以使之用在dom里例如onClick之流
- this.increment=this.increment.bind(this);
- this.decrement=this.decrement.bind(this);
- this.reset=this.reset.bind(this);
-
- }
- // 对套路进行具体操作,用this.setState({})一般操作数据,或this.setState(state=>{state';XX})
- increment() {
- this.setState({
- count:this.state.count+1
- })
- }
- decrement() {
- this.setState({
- count:this.state.count-1
- })
- }
- reset() {
- this.setState(state => ({
- count: 0
- }));
- }
- // change code above this line
- render() {
- return (
- <div>
- <button className='inc' onClick={this.increment}>Increment!</button>
- <button className='dec' onClick={this.decrement}>Decrement!</button>
- <button className='reset' onClick={this.reset}>Reset</button>
- <h1>Current Count: {this.state.count}</h1>
- </div>
- );
- }
- };
关系:
react中的this.state即为obj对象中的键值对
二、Vue
1. 前提:ES6--setter,getter
你可以从对象中获得一个值,也可以给对象的属性赋值。
这些通常行为被称为 getters 以及 setters。
Getter 函数的作用是可以让返回一个对象私有变量的值给用户,而不需要直接去访问私有变量。
Setter 函数的作用是可以基于传进的参数来修改对象中私有变量的值。这些修改可以是计算,或者是直接替换之前的值。
- class Book {
- constructor(author) {
- this._author = author;
- }
- // getter
- get writer(){
- return this._author;
- }
- // setter
- set writer(updatedAuthor){
- this._author = updatedAuthor;
- }
- }
- const lol = new Book('anonymous');
- console.log(lol.writer); // anonymous
- lol.writer = 'wut';
- console.log(lol.writer); // wut
了解了es6中setter与getter 那么我们用js写一个仿vue的例子:
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <meta http-equiv="X-UA-Compatible" content="ie=edge">
- <title>Vue</title>
- </head>
- <body>
- <div>
- <p id="text">0</p>
- <input type="button" value="increase" id="btn1">
- <input type="button" value="decrease" id="btn2">
- </div>
- </body>
- <script type="text/javascript">
- class Number {
- constructor(v) {
- this._count = v;
- }
- // getter
- get count() {
- return this._count;
- }
- // setter
- set count(v) {
- this._count = v;
- }
- }
- const btn1 = document.getElementById("btn1");
- const btn2 = document.getElementById("btn2");
- const a = new Number(0);
- render = () => {
- document.getElementById("text").innerHTML = a.count
- }
- btn1.onclick = () => {
- a.count ++;
- render()
- }
- btn2.onclick = () => {
- a.count --;
- render()
- }
- </script>
- </html>
用vue写
- <template>
- <div >
- <p>{{count}}</p>
- <input type="button" value="increase" id="btn1" @click=increase>
- <input type="button" value="decrease" id="btn2" @click=decrease>
- </div>
-
- </template>
- <script type='text/ecmascript-6'>
- export default {
- layout: 'blank',
- data () {
- return {
- count:0
- }
- },
- methods:{
- increase:function(){
- this.count++
- },
- decrease:function(){
- this.count--
- }
- }
- }
- </script>
- <style>
- </style>
三、小结
vue比原生简化很多,render()直接用{{}}渲染,通过数据双向绑定,节约代码量,而且在export default中泾渭分明,易于上手;react虽然代码不简单,但是对于学过es5,es6,jquery库的同志友好,代码易读,这个案例也就研究了两个框架上树的方式,仅为皮毛,不涉及其中深入的算法。