简单实现一个vue的双向绑定www.129028.com金沙:

日期:2020-05-07编辑作者:Web前端

时间: 2019-09-07阅读: 149标签: 双向绑定

## 属性的类型
  - 属性可分为类属性和实例属性

首先我们来看一些,vue的基本使用方法

  - 实例属性可以通过在类中使用self定义,或者直接在类外部使用实例变量定义

new Vue({el:'#app',data:{price:27,info:{title:'猪肉的价格'},name:23},beforeCreate() {// console.log(this.info)},created(){// console.log(this.info)},beforeMount () {// console.log(document.querySelector('#home'))},mounted(){// console.log(document.querySelector('#home'))},render(createElement) {return createElement('div',{attrs:{title:this.info.title,id:'home'}},[createElement('span',{},this.price)]) }})
 1 class Person(object):
 2     def __init__(self, name, age):
 3         self.name = name
 4         self.age = age
 5 
 6 
 7 per1 = Person("Stanley", 22)
 8 print(per1.name)        # 输出:Stanley
 9 per1.weight = "50kg"    
10 print(per1.weight)      # 输出:50kg

然后我们根据使用方法,来设计一个类和一些基础的声明周期

 

class Vue {constructor(options) {this.$el = document.querySelector(options.el) // 获取根元素this.beforeCreate = options.beforeCreate // 生命周期 beforeCreateif(this.beforeCreate)this.beforeCreate() this._data = options.data || options.data() // 获取初始数据this._render = options.render // 获取渲染函数new Observer(this._data) // 进行深度代理for ( let key in this._data){ // 代理data 元素,把元素代理到this实例上proxy(this,this._data,key)}this.created = options.created // 生命周期 createdif(this.created)this.created()this.beforeMount = options.beforeMount // 生命周期 beforeMountif(this.beforeMount)this.beforeMount()new Watch(()={this._update() // 渲染页面})this.mounted = options.mounted // 生命周期 mountedif(this.mounted)this.mounted()}_update () { // 渲染函数const node = this._render(this._createElement) // 执行渲染函数replaceChild(node,this.$el)this.$el = node}_createElement (targetName,data,chilren) {const tag = document.createElement(targetName)const {attrs = {}} = datafor ( let attr in attrs){tag.setAttribute(attr,attrs[attr])}if(Object.prototype.toString.call(chilren) !== '[object Array]'){let child = document.createTextNode(chilren) // 创建一个文本节点tag.appendChild(child)}else {chilren.forEach(child = {tag.appendChild(child)})}return tag}}function replaceChild (newNode,oldNode) {return oldNode.parentElement.replaceChild(newNode,oldNode)}function proxy (target,data,key) { // 代理函数,代理最外层dataObject.defineProperty(target,key,{get () {return data[key]},set (newValue) {data[key] = newValue}})}function defineProperty (target,key,value) { // 深度监听const dep = new Dep()Object.defineProperty(target,key,{get () {if(Dep.targets.length0){ // 为了排除后面来的dep.addDepend()}return value},set (newValue) {value = newValuedep.notify()}})}class Dep { // 发布订阅者constructor(arg) { this.subs = []}addSub(obj){ // 添加,if(this.subs.indexOf(obj) === -1) { // 如不存在该对象,则添加该对象this.subs.push(obj)}}notify(){ // 发布for(let i = 0;ithis.subs.length;i++){this.subs[i].update()}}addDepend () {Dep.targets[Dep.targets.length-1].addDep(this)}}Dep.targets = [] // 添加function pushTarget (instance) { // 入栈Dep.targets.push(instance)}function popTarget () { // 出栈return Dep.targets.pop()}class Watch { // 事件监听类constructor(getter){this.getter = getterthis.get()}get () {pushTarget(this)let value = this.getter()popTarget()return value}addDep (dep) {dep.addSub(this)}update () {this.getter()}}class Observer {constructor(obj) { this.walk(obj)}walk (obj) {for(let key in obj){if(typeof obj[key] === 'object'){this.walk(obj[key])}defineProperty (obj,key,obj[key])}}}

  - 类属性则直接在类中定义
    - 类属性通过类名访问,也可以通过实例访问

 1 class Person(object):
 2     class_name = "Person"
 3 
 4     def __init__(self, name, age):
 5         self.name = name
 6         self.age = age
 7 
 8 
 9 per1 = Person("Stanley", 22)
10 print(per1.class_name)      # 输出:Person
11 
12 print(Person.class_name)    # 输出:Person

 

  - 注意:
    - 如果实例属性和类属性使用了相同的名字,则实例化后实例属性将覆盖类属性,实例将无法在访问该同名类属性,而通过类名访问类属性将不受影响

 1 class Person(object):
 2     name = "Person"
 3 
 4     def __init__(self, name, age):
 5         self.name = name
 6         self.age = age
 7 
 8 
 9 print(Person.name)      # 输出:Person
10 
11 per1 = Person("Stanley", 22)
12 print(per1.name)        # 输出:Stanley
13 print(Person.name)      # 输出:Person

 

## 方法的类型
  - 在一个类中可以存在三种类型的方法
  - 在类的定义中,以self(即实例本身)作为第一个参数的方法为实例方法

 1 class Person(object):
 2 
 3     def __init__(self, name, age):
 4         self.name = name
 5         self.age = age
 6 
 7     # 这是一个实例方法,self为实例本身,作为第一个参数传入,通过实例调用
 8     def eat(self):
 9         print("I'm %s, I want to eat!" % self.name)
10 
11 
12 per1 = Person("Stanley", 22)
13 per1.eat()      # 输出:I'm Stanley, I want to eat!

www.129028.com金沙, 

  - 在类的内部定义,用修饰符@classmethod指定的方法是类方法
  - 类方法会作用于整个类,该方法对类做出的改变会影响该类的所有实例
  - 与实例方法类似,类方法的第一个参数是类本身,通常写作cls

class Person(object):
    count = 0

    def __init__(self, name, age):
        self.name = name
        self.age = age
        Person.count += 1   # 每实例化一个对象,count加1

    # 这是一个实例方法,self作为第一个参数传入,通过实例调用
    def eat(self):
        print("I'm %s, I want to eat!" % self.name)

    @classmethod        # 使用@classmethod修饰
    def kids(cls):      # 第一个参数为类本身,这是一个类方法
        print("class %s has %d instance(es)." % (cls.__name__, Person.count))


per1 = Person("Stanley", 22)
per2 = Person("Bob", 18)
per3 = Person("Lily", 17)
Person.kids()       # 输出:class Person has 3 instance(es).

 

  - 第三种方法类型称为静态方法
  - 静态方法使用@staticmethod修饰,它不需要self参数或者cls参数
  - 静态方法的存在不会影响类也不会影响类的实例,仅仅是为了代码的逻辑性
  - 静态方法可以通过类名或者实例调用

本文由www.129028.com金沙发布于Web前端,转载请注明出处:简单实现一个vue的双向绑定www.129028.com金沙:

关键词:

【www.129028.com金沙】说说这碗青春饭

时间: 2019-09-08阅读: 311标签: 程序员 前不久,又听到有人说程序员这一行是碗青春饭,言语之中充满了鄙夷。当然他并...

详细>>

Js如何获取某一天所在的星期www.129028.com金沙?

时间: 2019-09-10阅读: 159标签: 日期 我们会遇到的需求的是,获取今天或者某一天所在星期的开始和结束日期。 我们这...

详细>>

www.129028.com金沙缓存一致性策略以及雪崩、穿透问题

为了表述方便,本文以数据库查询缓存为例,使用缓存可以减小对数据库的压力。 一、缓存原理 高并发情境下首先考...

详细>>

前端工程师如何才能不焦虑?

时间: 2019-09-09阅读: 99标签: 焦虑引言 时间: 2019-07-28阅读: 247标签: 技术 进入2019年,中国互联网充满了焦虑的气息,不...

详细>>