<template> <div> <p>用户姓名:{{ userName }}</p> <p>用户年龄:{{ age }}</p> </div> </template> <script> export default { data() { return { userName: '张三', age: 25, }; }, computed: { // 堆代码 duidaima.com // 计算用户年龄显示格式 formattedAge() { return this.age.toString().padStart(2, '0'); }, }, }; </script>2. 数据过滤:利用computed属性对数据进行过滤处理,例如:
<template> <div> <p>列表数据:{{ filteredList }}</p> </div> </template> <script> export default { data() { return { list: [1, 2, 3, 4, 5], filterValue: 3, }; }, computed: { // 计算过滤后的列表数据 filteredList() { return this.list.filter((item) => item === this.filterValue); }, }, }; </script>而在computed定义中又分为两种写法:函数和属性
computed: { //1.函数 fullName() { console.log('执行') return this.firstName + this.lastName }, //2.属性 goodName: { get() { return this.firstName + this.lastName }, set(value) { // .... } } }1.2.Vue实现computed大概步骤
import Dep from "./observe/dep.js"; export function initState(vm) { // console.log(vm) // const opts = vm.$options if (opts.data) { initData(vm); } if (opts.watch) { initWatch(vm); } if (opts.props) { initProps(vm); } if (opts.computed) { initComputed(vm); } if (opts.methods) { initMethod(vm); } } function initComputed(vm) { let computed = vm.$options.computed console.log(computed) let watcher = vm.computedWatchers = {} for (let key in computed) { let userDef = computed[key] let getter = typeof userDef == 'function' ? userDef : userDef.get watcher[key] = new Watcher(vm, getter, () => {}, { //标记此为computed的watcher lazy: true }) defineComputed(vm, key, userDef) } } let sharedPropDefinition = {} function defineComputed(target, key, userDef, ) { sharedPropDefinition = { enumerable: true, configurable: true, get: () => {}, set: () => {} } if (typeof userDef == 'function') { sharedPropDefinition.get = createComputedGetter(key) } else { sharedPropDefinition.get = createComputedGetter(key) sharedPropDefinition.set = userDef.set } Object.defineProperty(target, key, sharedPropDefinition) } //高阶函数 function createComputedGetter(key) { return function () { // if (dirty) { // } let watcher = this.computedWatchers[key] if (watcher) { if (watcher.dirty) { //执行 求值 watcher.evaluate() // } if(Dep.targer){ //说明 watcher.depend() } return watcher.value } } }1.sharedPropDefinition: 这是一个空对象,用于定义计算属性的属性描述符(property descriptor)。属性配置它包含了enumerable、configurable、get和set等属性配置,这些配置决定了计算属性在对象上的可枚举性、可配置性以及获取和设置属性时的行为。
class Watcher { //vm 实例 //exprOrfn vm._updata(vm._render()) constructor(vm, exprOrfn, cb, options) { // 1.创建类第一步将选项放在实例上 this.vm = vm; this.exprOrfn = exprOrfn; this.cb = cb; this.options = options; //for conputed this.lazy = options.lazy this.dirty = this.lazy // 2. 每一组件只有一个watcher 他是为标识 this.id = id++ this.user = !!options.user // 3.判断表达式是不是一个函数 this.deps = [] //watcher 记录有多少dep 依赖 this.depsId = new Set() if (typeof exprOrfn === 'function') { this.getter = exprOrfn } else { //{a,b,c} 字符串 变成函数 this.getter = function () { //属性 c.c.c let path = exprOrfn.split('.') let obj = vm for (let i = 0; i < path.length; i++) { obj = obj[path[i]] } return obj // } } // 4.执行渲染页面 // this.value = this.get() //保存watch 初始值 this.value = this.lazy ? void 0 : this.get() } addDep(dep) { //去重 判断一下 如果dep 相同我们是不用去处理的 let id = dep.id // console.log(dep.id) if (!this.depsId.has(id)) { this.deps.push(dep) this.depsId.add(id) //同时将watcher 放到 dep中 // console.log(666) dep.addSub(this) } // 现在只需要记住 一个watcher 有多个dep,一个dep 有多个watcher //为后面的 component } run() { //old new let value = this.get() //new let oldValue = this.value //old this.value = value //执行 hendler (cb) 这个用户wathcer if (this.user) { this.cb.call(this.vm, value, oldValue) } } get() { // Dep.target = watcher pushTarget(this) //当前的实例添加 const value = this.getter.call(this.vm) // 渲染页面 render() with(wm){_v(msg,_s(name))} ,取值(执行get这个方法) 走劫持方法 popTarget(); //删除当前的实例 这两个方法放在 dep 中 return value } //问题:要把属性和watcher 绑定在一起 去html页面 // (1)是不是页面中调用的属性要和watcher 关联起来 //方法 //(1)创建一个dep 模块 updata() { //三次 //注意:不要数据更新后每次都调用 get 方法 ,get 方法回重新渲染 //缓存 // this.get() //重新 // 渲染 if(this.lazy){ this.dirty = true }else{ queueWatcher(this) } } evaluate() { this.value = this.get() this.dirty = false } depend(){ let i = this.deps.length while(i--){ this.deps[i].depend() } } }1.evaluate(): 该方法用于求值计算属性的结果。它会调用计算属性的 getter 方法(也就是sharedPropDefinition.get或createComputedGetter()函数中返回的函数),获取计算属性的最新值,并将该值保存在观察者对象的value属性中。同时,将观察者对象的dirty属性设置为false,表示计算属性的值已经是最新的了。
class Dep { constructor() { this.subs = [] this.id = id++ } //收集watcher depend() { //我们希望water 可以存放 dep //实现双休记忆的,让watcher 记住 //dep同时,让dep也记住了我们的watcher Dep.targer.addDep(this) // this.subs.push(Dep.targer) // id:1 记住他的dep } addSub(watcher){ this.subs.push(watcher) } //更新 notify() { // console.log(Dep.targer) this.subs.forEach(watcher => { watcher.updata() }) } }2.depend(): 该方法用于将计算属性的观察者对象添加到依赖收集器(Dependency)中。在计算属性的 getter 方法执行过程中,如果访问了其他响应式属性(依赖),那么这些响应式属性对应的观察者对象会将当前的计算属性的观察者对象添加到它们的依赖列表中。这样,在依赖变化时,观察者对象会被通知到,并重新执行计算属性的 getter 方法来更新计算属性的值。(在compoted的watcher执行完毕后,还有其他元素的wathcer等待执行)
三.预览效果