Compare commits

...

19 Commits

Author SHA1 Message Date
dj
026f4a5958 feat(runtime): 实现类名规范化功能
- 添加 normalizeClass 函数用于处理类名数组和对象
- 在 createVNode 中集成类名规范化逻辑
- 导出 normalizeClass 供外部使用
- 创建测试 HTML 示例验证类名功能
- 处理字符串、数组和对象类型的类名输入
2026-02-27 21:00:53 +08:00
dj
abf8112359 feat(runtime): 添加 Fragment Text Comment 导出支持
- 在 runtime-core 中导出 Fragment、Text、Comment 符号
- 在 vue 主入口文件中导出 Fragment、Text、Comment
- 添加 h-other.html 示例文件展示 Text、Comment、Fragment 的使用
- 添加 h-other-ym-test.html 示例文件测试 Fragment 渲染功能
- 创建 Fragment、Text、Comment 符号常量定义
2026-02-27 20:46:53 +08:00
dj
6aa564ef7c feat(runtime): 支持对象类型的组件创建
- 在 vnode.ts 中引入 isObject 判断函数
- 修改 createVNode 函数支持对象类型组件的 shapeFlag 设置
- 更新 h-component.html 示例代码,使用 h 函数创建组件
- 新增 h-component-video-test.html 测试文件包含原始 vnode 创建方式
- 移除手动创建 vnode 对象的硬编码方式,统一使用 h 函数创建
2026-02-27 20:01:20 +08:00
dj
61edc322f2 feat(runtime): 添加H函数组件示例和数组子节点标记支持
- 新增h-component.html示例文件展示直接创建虚拟DOM节点
- 在vnode.ts中为数组子节点添加ShapeFlags.ARRAY_CHILDREN标记
- 实现了绕过h函数直接构建组件虚拟节点的演示功能
2026-02-27 17:35:51 +08:00
dj
4225ae0b8f feat(examples): 更新 h-element 示例并添加文本版本
- 将 h-element.html 重命名为 h-element-array.html
- 修改示例代码以展示数组子元素渲染功能
- 添加新的 h-element-text.html 示例文件
- 新示例演示基本文本内容渲染用法
2026-02-26 23:41:04 +08:00
dj
a3a7b8c7e4 feat(runtime): 添加 h 函数和虚拟节点系统
- 实现了 h 函数用于创建虚拟节点
- 添加了 VNode 接口定义和创建逻辑
- 引入了 ShapeFlags 枚举来标记节点类型
- 实现了虚拟节点子元素标准化功能
- 在 runtime-core 中导出 h 函数
- 添加了 h 函数使用示例页面
2026-02-26 22:35:22 +08:00
dj
164bae388f 解决问题---"响应式数据的改变并不会引起watch的触发" 2026-02-26 12:00:57 +08:00
dj
b9a9c52333 feat(watch): 实现watch功能并完善响应式系统
- 新增apiWatch.ts实现watch功能,支持immediate和deep选项
- 扩展ReactiveEffect类添加stop方法用于停止监听
- 导出ReactiveEffect和isReactive函数供外部使用
- 添加ReactiveFlags枚举和IS_REACTIVE标识符
- 在reactive对象上添加__v_isReactive标识
- 导出EMPTY_OBJ常量用于默认参数
- 添加watch功能到Vue入口文件
- 创建watch.html示例验证监听功能正常工作
2026-02-25 22:15:42 +08:00
dj
4a71105e28 feat(runtime-core): 添加预冲洗回调队列功能
- 在 runtime-core 中新增 queuePreFlushCb 函数用于管理预冲洗回调
- 在 vue 包中导出 queuePreFlushCb 函数供外部使用
- 实现调度器中的回调队列机制,包括队列管理和执行逻辑
- 添加去重逻辑确保回调函数只执行一次
- 新增示例文件展示调度器预冲洗回调的使用方法
2026-02-24 22:06:33 +08:00
dj
ba03278947 feat(scheduler): 初始化调度器挂起状态标志
- 添加 isFlushPending 变量用于跟踪刷新操作是否正在等待执行
2026-02-11 00:01:02 +08:00
dj
1f50ab1c84 feat(effects): 添加 scheduler 选项支持和 extend 工具函数
- 添加 extend 函数作为 Object.assign 的别名
- 修复 ReactiveEffectOptions 中 scheduler 属性拼写错误
- 实现 effect 选项配置的属性扩展功能
- 更新 lazy 示例展示 effect 运行逻辑
- 新增 scheduler 示例演示调度器功能
2026-02-10 17:54:23 +08:00
dj
62e40e7292 feat(effects): 添加懒执行选项和调度器支持
- 引入 ReactiveEffectOptions 接口,支持 lazy 和 scheduler 配置
- 实现懒执行功能,当 lazy 为 true 时不立即运行 effect
- 添加新的示例文件 lazy.html 演示懒执行效果
- 优化 effect 函数参数结构,支持可选配置项
2026-02-09 18:23:44 +08:00
dj
c07431db08 feat(computed): 实现计算属性缓存优化和调度器支持
- 添加 _dirty 标志位控制计算属性重新执行逻辑
- 在 ReactiveEffect 构造函数中增加调度器参数支持
- 实现计算属性值变更时的依赖触发机制
- 重构 triggerEffects 函数优先处理计算属性依赖
- 新增 EffectScheduler 类型定义统一调度器类型
- 添加 computed-cache.html 示例验证缓存功能
2026-02-08 22:39:34 +08:00
dj
4c60486511 feat(computed): 添加计算属性功能实现
- 实现了 ComputedRefImpl 类来管理计算属性
- 添加了 computed 函数用于创建计算属性
- 在 ReactiveEffect 中添加 computed 属性引用
- 将 computed 导出到 reactivity 和 vue 主包
- 添加了 isFunction 工具函数判断函数类型
- 创建了计算属性的 HTML 示例文件进行演示
2026-02-08 15:19:49 +08:00
dj
c0853b353d docs(ref): 更新 ref 实现的注释文档
- 为 RefImpl 构造函数添加原始数据注释
- 为 value setter 方法添加详细的参数和逻辑说明
- 为 newValue 和 _rawValue 的比较逻辑添加注释
- 为 value setter 中的数据更新流程添加步骤注释
- 更新 triggerRefValue 函数的注释描述
2026-02-05 23:53:27 +08:00
dj
2ed86a03b5 refactor(vue): 构建ref简单数据类型的响应性 2026-02-05 23:38:51 +08:00
dj
6b7b452a56 feat(ref): 实现 ref 值变化检测和依赖触发功能
- 在 shared 包中新增 hasChanged 函数用于比较值是否发生变化
- 修改 RefImpl 类添加 _rawValue 属性存储原始值
- 实现 ref setter 中的值变化检测逻辑
- 添加 triggerRefValue 函数用于触发 ref 依赖更新
- 优化 ref 的 getter 和 setter 方法实现响应式更新
2026-02-05 22:36:15 +08:00
dj
9aad0f6c74 Merge remote-tracking branch 'origin/main'
# Conflicts:
#	packages/vue/examples/reactivity/ref.html
2026-02-05 21:58:25 +08:00
dj
7fc2292d4b feat(core): 添加 ref 响应式引用功能
- 实现了 ref 函数用于创建响应式引用
- 添加了 RefImpl 类来管理引用值的响应式行为
- 集成了 trackRefValue 函数进行依赖追踪
- 扩展了 vue 包的导出以包含 ref 功能
- 在 shared 包中添加了 isObject 工具函数
- 创建了 toReactive 辅助函数用于对象响应式转换
- 新增 ref.html 示例文件展示 ref 使用方法
- 移除了旧的 reactive-test.html 示例文件
2026-02-05 21:57:55 +08:00
30 changed files with 829 additions and 36 deletions

View File

@@ -0,0 +1,40 @@
import { isFunction } from '@vue/shared'
import { Dep } from './dep'
import { ReactiveEffect } from './effect'
import { trackRefValue, triggerRefValue } from './ref'
export class ComputedRefImpl<T> {
public dep?: Dep = undefined
private _value!: T
public readonly effect: ReactiveEffect<T>
public readonly __v_isRef = true
public _dirty = true //为true时,需要重新执行run方法, 也就是说数据脏了的意思
constructor(getter) {
this.effect = new ReactiveEffect(getter, () => {
if (!this._dirty) {
this._dirty = true
triggerRefValue(this)
}
})
this.effect.computed = this
}
get value() {
trackRefValue(this)
if (this._dirty) {
this._dirty = false
this._value = this.effect.run()
}
return this._value
}
}
export function computed(getterOrOptions) {
let getter
const onlyGetter = isFunction(getterOrOptions)
if (onlyGetter) {
getter = getterOrOptions
}
const cRef = new ComputedRefImpl(getter)
return cRef
}

View File

@@ -1,5 +1,7 @@
import { createDep, Dep } from './dep' import { createDep, Dep } from './dep'
import { isArray } from '@vue/shared' import { extend, isArray } from '@vue/shared'
import { ComputedRefImpl } from './computed'
export type EffectScheduler = (...args: any[]) => any
type KeyToDepMap = Map<any, Dep> type KeyToDepMap = Map<any, Dep>
/** /**
@@ -11,20 +13,35 @@ type KeyToDepMap = Map<any, Dep>
*/ */
const targetMap = new WeakMap<any, KeyToDepMap>() const targetMap = new WeakMap<any, KeyToDepMap>()
export function effect<T = any>(fn: () => T) { export interface ReactiveEffectOptions {
lazy?: boolean
scheduler?: EffectScheduler
}
export function effect<T = any>(fn: () => T, options?: ReactiveEffectOptions) {
const _effect = new ReactiveEffect(fn) const _effect = new ReactiveEffect(fn)
_effect.run() if (options) {
extend(_effect, options)
}
if (!options || !options.lazy) {
_effect.run()
}
} }
export let activeEffect: ReactiveEffect | undefined export let activeEffect: ReactiveEffect | undefined
export class ReactiveEffect<T = any> { export class ReactiveEffect<T = any> {
constructor(public fn: () => T) {} computed?: ComputedRefImpl<T>
constructor(
public fn: () => T,
public scheduler: EffectScheduler | null = null
) {}
run() { run() {
//当前被激活的effect实例 //当前被激活的effect实例
activeEffect = this activeEffect = this
return this.fn() //完成第一次getter行为的触发 return this.fn() //完成第一次getter行为的触发
} }
stop() {}
} }
/** /**
@@ -76,14 +93,26 @@ export function trigger(target: object, key: unknown, newValue: unknown) {
} }
/** /**
* 依次触发dep中保存的依赖 * 触发dep中保存的依赖
* @param dep * @param dep
*/ */
export function triggerEffects(dep: Dep) { export function triggerEffects(dep: Dep) {
//把dep构建为一个数组
const effects = isArray(dep) ? dep : [...dep] const effects = isArray(dep) ? dep : [...dep]
//依次触发依赖 //不再依次触发依赖
// for (const effect of effects) {
// triggerEffect(effect)
// }
//而是先触发所有的计算属性依赖, 再触发所有的非计算属性依赖
for (const effect of effects) { for (const effect of effects) {
triggerEffect(effect) if (effect.computed) {
triggerEffect(effect)
}
}
for (const effect of effects) {
if (!effect.computed) {
triggerEffect(effect)
}
} }
} }
@@ -92,5 +121,9 @@ export function triggerEffects(dep: Dep) {
* @param effect * @param effect
*/ */
export function triggerEffect(effect: ReactiveEffect) { export function triggerEffect(effect: ReactiveEffect) {
effect.run() if (effect.scheduler) {
effect.scheduler()
} else {
effect.run()
}
} }

View File

@@ -1,2 +1,4 @@
export { reactive } from './reactive' export { reactive, isReactive } from './reactive'
export { effect } from './effect' export { effect, ReactiveEffect } from './effect'
export { ref } from './ref'
export { computed } from './computed'

View File

@@ -1,4 +1,5 @@
import { mutableHandlers } from './baseHandlers' import { mutableHandlers } from './baseHandlers'
import { isObject } from '@vue/shared'
/** /**
* 响应性Map缓存对象 * 响应性Map缓存对象
@@ -7,6 +8,10 @@ import { mutableHandlers } from './baseHandlers'
*/ */
export const reactiveMap = new WeakMap<object, any>() export const reactiveMap = new WeakMap<object, any>()
export const enum ReactiveFlags {
IS_REACTIVE = '__v_isReactive'
}
/** /**
* 为复杂数据类型, 创建响应式对象 * 为复杂数据类型, 创建响应式对象
* @param target 被代理的对象 * @param target 被代理的对象
@@ -34,8 +39,16 @@ function createReactiveObject(
} }
//未被代理则生成proxy实例 //未被代理则生成proxy实例
const proxy = new Proxy(target, baseHandlers) const proxy = new Proxy(target, baseHandlers)
//添加reactive标识
proxy[ReactiveFlags.IS_REACTIVE] = true
//缓存代理对象 //缓存代理对象
proxyMap.set(target, proxy) proxyMap.set(target, proxy)
return proxy return proxy
} }
export const toReactive = <T extends unknown>(value: T): T =>
isObject(value) ? reactive(value as object) : value
export function isReactive(value): boolean {
return !!(value && value[ReactiveFlags.IS_REACTIVE])
}

View File

@@ -0,0 +1,69 @@
import { createDep, Dep } from './dep'
import { toReactive } from './reactive'
import { activeEffect, triggerEffects, trackEffects } from './effect'
import { hasChanged } from '@vue/shared'
export interface Ref<T = any> {
value: T
}
export function ref(value?: unknown) {
return createRef(value, false)
}
function createRef(rawValue: unknown, shallow: boolean) {
if (isRef(rawValue)) {
return rawValue
}
return new RefImpl(rawValue, shallow)
}
class RefImpl<T> {
private _value: T
private _rawValue: T
public dep?: Dep = undefined
public readonly __v_isRef = true
constructor(
value: T,
public readonly __v_isShallow: boolean
) {
//原始数据
this._rawValue = value
this._value = __v_isShallow ? value : toReactive(value)
}
get value() {
trackRefValue(this)
return this._value
}
/**
* newValue 新数据
* this._rawValue为旧数据(原始数据)
* 对比两个数据是否发生改变
*/
set value(newValue) {
if (hasChanged(newValue, this._rawValue)) {
//更新原始数据
this._rawValue = newValue
//更新 .value的值
this._value = toReactive(newValue)
//触发依赖
triggerRefValue(this)
}
}
}
//为ref的value进行触发依赖工作
export function triggerRefValue(ref) {
if (ref.dep) {
triggerEffects(ref.dep)
}
}
//收集依赖
export function trackRefValue(ref) {
if (activeEffect) {
trackEffects(ref.dep || (ref.dep = createDep()))
}
}
//是否为ref
export function isRef(r: any): r is Ref {
return !!(r && r.__v_isRef === true)
}

View File

@@ -0,0 +1,75 @@
import { EMPTY_OBJ, hasChanged, isObject } from '@vue/shared'
import { isReactive, ReactiveEffect } from '@vue/reactivity'
import { queuePreFlushCb } from '@vue/runtime-core'
export interface WatchOptions<immediate = boolean> {
immediate?: immediate
deep?: boolean
}
export function watch(source, cb: Function, options?: WatchOptions) {
return doWatch(source, cb, options)
}
function doWatch(
source,
cb: Function,
{ immediate, deep }: WatchOptions = EMPTY_OBJ
) {
let getter: () => any
if (isReactive(source)) {
getter = () => source
deep = true
} else {
getter = () => {}
}
//处理deep的状态
if (cb && deep) {
//todo
//浅拷贝的形式--指向同样的内存空间
const baseGetter = getter
//等同于将source的属性传进去了
getter = () => traverse(baseGetter())
}
let oldValue = {}
//每次执行等同于watch被触发一次
const job = () => {
if (cb) {
const newValue = effect.run()
if (deep || hasChanged(newValue, oldValue)) {
cb(newValue, oldValue)
oldValue = newValue
}
}
}
//调度器
let scheduler = () => queuePreFlushCb(job)
const effect = new ReactiveEffect(getter, scheduler)
if (cb) {
if (immediate) {
job()
} else {
oldValue = effect.run()
}
} else {
effect.run()
}
return () => {
effect.stop()
}
}
/**
* 本质上是拿value, 出发一次getter行为
* @param value
*/
export function traverse(value: unknown) {
if (!isObject(value)) {
return value
}
for (const key in value as object) {
traverse((value as object)[key])
}
return value
}

View File

@@ -0,0 +1,25 @@
import { createVNode, isVNode, VNode } from './vnode'
import { isObject } from '@vue/shared'
export function h(type: any, propsOrChildren?: any, children?: any): VNode {
const l = arguments.length
if (l === 2) {
//是对象
if (isObject(propsOrChildren) && !Array.isArray(propsOrChildren)) {
if (isVNode(propsOrChildren)) {
return createVNode(type, null, [propsOrChildren])
}
return createVNode(type, propsOrChildren, [])
} else {
//是数组
return createVNode(type, null, propsOrChildren)
}
} else {
if (l > 3) {
children = Array.prototype.slice.call(arguments, 2) //生成新的children
} else if (l === 3 && isVNode(children)) {
children = [children]
}
return createVNode(type, propsOrChildren, children)
}
}

View File

@@ -0,0 +1,4 @@
export { queuePreFlushCb } from './scheduler'
export { watch } from './apiWatch'
export { h } from './h'
export { Fragment, Text, Comment } from './vnode'

View File

@@ -0,0 +1,35 @@
let isFlushPending = false
const resolvedPromise = Promise.resolve() as Promise<any>
let currentFlushPromise: Promise<void> | null = null
const pendingPreFlushCbs: Function[] = []
export function queuePreFlushCb(cb: Function) {
queueCb(cb, pendingPreFlushCbs)
}
function queueCb(cb: Function, pendingQueue: Function[]) {
pendingQueue.push(cb)
queueFlush()
}
function queueFlush() {
if (!isFlushPending) {
isFlushPending = true
currentFlushPromise = resolvedPromise.then(flushJobs)
}
}
function flushJobs() {
isFlushPending = false
flushPreFlushCbs()
}
export function flushPreFlushCbs() {
if (pendingPreFlushCbs.length) {
//拷贝去重,类似深拷贝
let activePreFlushCbs = [...new Set(pendingPreFlushCbs)]
pendingPreFlushCbs.length = 0
for (let i = 0; i < activePreFlushCbs.length; i++) {
activePreFlushCbs[i]()
}
}
}

View File

@@ -0,0 +1,66 @@
import {
isArray,
isFunction,
isObject,
isString,
normalizeClass,
ShapeFlags
} from '@vue/shared'
export const Fragment = Symbol('Fragment')
export const Text = Symbol('Text')
export const Comment = Symbol('Comment')
export interface VNode {
__v_isVNode: true
type: any
props: any
children: any
shapeFlag: number
}
export function isVNode(value): value is VNode {
return value ? value.__v_isVNode === true : false
}
export function createVNode(type, props, children): VNode {
if (props) {
let { class: klass, style } = props
if (klass && !isString(klass)) {
props.class = normalizeClass(klass)
}
}
const shapeFlag = isString(type)
? ShapeFlags.ELEMENT
: isObject(type)
? ShapeFlags.STATEFUL_COMPONENT
: 0
return createBaseVNode(type, props, children, shapeFlag)
}
function createBaseVNode(type, props, children, shapeFlag) {
const vnode = {
__v_isVNode: true,
type,
props,
shapeFlag
} as VNode
//解析/标准化当前vnode下的children
normalizeChildren(vnode, children)
return vnode
}
export function normalizeChildren(vnode: VNode, children: unknown) {
let type = 0
const { shapeFlag } = vnode
if (children == null) {
children = null
} else if (isArray(children)) {
type = ShapeFlags.ARRAY_CHILDREN
} else if (typeof children === 'object') {
} else if (isFunction(children)) {
} else {
children = String(children)
type = ShapeFlags.TEXT_CHILDREN
}
vnode.children = children
vnode.shapeFlag |= type
}

View File

@@ -1,2 +1,25 @@
export { ShapeFlags } from './shapeFlags'
export { normalizeClass } from './normalizeProp'
//判断是否为一个数组 //判断是否为一个数组
export const isArray = Array.isArray export const isArray = Array.isArray
export const isObject = (val: unknown) =>
val !== null && typeof val === 'object'
/**
* 对比两个数据是否发生改变, 如果发生改变则返回true
*/
export const hasChanged = (value: any, oldValue: any): boolean =>
!Object.is(value, oldValue)
export const isFunction = (val: unknown): val is Function => {
return typeof val === 'function'
}
export const isString = (val: unknown): val is string => {
return typeof val === 'string'
}
export const extend = Object.assign
export const EMPTY_OBJ: { readonly [key: string]: any } = {}

View File

@@ -0,0 +1,24 @@
import { isArray, isObject, isString } from '@vue/shared'
export function normalizeClass(value: unknown): string {
let res = ''
if (isString(value)) {
res = value
} else if (isArray(value)) {
for (let i = 0; i < value.length; i++) {
const normalized = normalizeClass(value[i])
if (normalized) {
res += normalized + ' '
}
}
} else if (isObject(value)) {
for (const name in value as object) {
if ((value as object)[name]) {
res += name + ' '
}
}
}
return res.trim()
}

View File

@@ -0,0 +1,30 @@
export const enum ShapeFlags {
/**
* type=Element
*/
ELEMENT = 1,
/**
* 函数组件
*/
FUNCTIONAL_COMPONENT = 1 << 1,
/**
* 有状态(响应数据)组件
*/
STATEFUL_COMPONENT = 1 << 2,
/**
* children=Text
*/
TEXT_CHILDREN = 1 << 3,
/**
* children=Array
*/
ARRAY_CHILDREN = 1 << 4,
/**
* children=slot
*/
SLOTS__CHILDREN = 1 << 5,
/**
* 组件: 有状态(响应数据)组件 | 函数组件
*/
COMPONENT = ShapeFlags.STATEFUL_COMPONENT | ShapeFlags.FUNCTIONAL_COMPONENT
}

View File

@@ -0,0 +1,28 @@
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Document</title>
<script src="../../dist/vue.js"></script>
</head>
<body>
<div id="app"></div>
</body>
<script>
const { reactive,effect,computed } = Vue
const obj=reactive({
name:'张三'
})
const computedObj= computed(()=>{
console.log('计算属性执行')
return '姓名:'+obj.name
})
effect(()=>{
document.querySelector('#app').innerText=computedObj.value
document.querySelector('#app').innerText=computedObj.value
})
setTimeout(()=>{
obj.name='李四'
},2000)
</script>
</html>

View File

@@ -0,0 +1,26 @@
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Document</title>
<script src="../../dist/vue.js"></script>
</head>
<body>
<div id="app"></div>
</body>
<script>
const { reactive,effect,computed } = Vue
const obj=reactive({
name:'张三'
})
const computedObj= computed(()=>{
return '姓名:'+obj.name
})
effect(()=>{
document.querySelector('#app').innerText=computedObj.value
})
setTimeout(()=>{
obj.name='李四'
},2000)
</script>
</html>

View File

@@ -0,0 +1,26 @@
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Document</title>
<script src="../../dist/vue.js"></script>
</head>
<body>
<div id="app"></div>
</body>
<script>
const { reactive,effect } = Vue
const obj=reactive({
count:1
})
effect(()=>{
console.log('obj.count',obj.count)
},{
lazy:false
})
obj.count=2
console.log('代码运行结束');
</script>
</html>

View File

@@ -1,19 +0,0 @@
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Document</title>
<script src="../../dist/vue.js"></script>
</head>
<body>
<div id="app">
<p id="p1"></p>
<p id="p2"></p>
</div>
</body>
<script>
const { reactive } = Vue
const obj=reactive('张三')//不能接收简单数据类型
console.log(obj)
</script>
</html>

View File

@@ -0,0 +1,21 @@
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Document</title>
<script src="../../dist/vue.js"></script>
</head>
<body>
<div id="app"></div>
</body>
<script>
const { ref,effect } = Vue
const obj=ref('张三')
effect(()=>{
document.querySelector('#app').innerText=obj.value
})
setTimeout(()=>{
obj.value='李四'
},2000)
</script>
</html>

View File

@@ -9,16 +9,15 @@
<div id="app"></div> <div id="app"></div>
</body> </body>
<script> <script>
const { reactive,effect } = Vue const { ref,effect } = Vue
const obj=reactive({ const obj=ref({
name:'张三' name:'张三'
}) })
effect(()=>{ effect(()=>{
document.querySelector('#app').innerText=name document.querySelector('#app').innerText=obj.value.name
}) })
setTimeout(()=>{ setTimeout(()=>{
obj.name='李四' obj.value.name='李四'
},2000) },2000)
</script> </script>
</html> </html>

View File

@@ -0,0 +1,28 @@
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Document</title>
<script src="../../dist/vue.js"></script>
</head>
<body>
<div id="app"></div>
</body>
<script>
const { reactive,effect,queuePreFlushCb } = Vue
const obj=reactive({
count:1
})
effect(()=>{
console.log(obj.count)
},{
scheduler(){
queuePreFlushCb(()=>console.log(obj.count));
}
})
obj.count=2
obj.count=3
</script>
</html>

View File

@@ -0,0 +1,30 @@
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Document</title>
<script src="../../dist/vue.js"></script>
</head>
<body>
<div id="app"></div>
</body>
<script>
const { reactive,effect } = Vue
const obj=reactive({
count:1
})
effect(()=>{
console.log(obj.count)
},{
scheduler(){
setTimeout(()=>{
console.log(obj.count)
})
}
})
obj.count=2
console.log('代码运行结束');
</script>
</html>

View File

@@ -0,0 +1,26 @@
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Document</title>
<script src="../../dist/vue.js"></script>
</head>
<body>
<div id="app"></div>
</body>
<script>
const { reactive,watch } = Vue
const obj=reactive({
name:'张三'
})
watch(obj,(value,oldValue)=>{
console.log('watch 监听被触发---value',value);
},{
immediate:true
})
setTimeout(()=>{
obj.name='李四'
},2000)
</script>
</html>

View File

@@ -0,0 +1,38 @@
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Document</title>
<script src="../../dist/vue.js"></script>
</head>
<body>
<div id="app"></div>
</body>
<script>
const { h, render } = Vue
const component = {
render() {
// const vnode1=h('div','这是一个component')
// console.log(vnode1);
// return vnode1
//直接利用当前打印的vnode , 绕过h的渲染
return {
"__v_isVNode": true,
"type": 'div',
"children": '这是一个component',
"shapeFlag": 9
}
}
}
// const vnode2=h(component)
// console.log(vnode2);
const vnode2 = {
"__v_isVNode": true,
"shapeFlag": 4,
"type": component
}
render(vnode2, document.querySelector('#app'))
</script>
</html>

View File

@@ -0,0 +1,24 @@
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Document</title>
<script src="../../dist/vue.js"></script>
</head>
<body>
<div id="app"></div>
</body>
<script>
const { h } = Vue
const component = {
render() {
const vnode1=h('div','这是一个component')
console.log(vnode1);
return vnode1
}
}
const vnode2=h(component)
console.log(vnode2);
</script>
</html>

View File

@@ -0,0 +1,22 @@
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Document</title>
<script src="../../dist/vue.js"></script>
</head>
<body>
<div id="app"></div>
</body>
<script>
const {h} =Vue
const vnode=h('div',{
class:'test'
},[
h('p','p1'),
h('p','p2'),
h('p','p3')
])
console.log(vnode)
</script>
</html>

View File

@@ -0,0 +1,28 @@
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Document</title>
<script src="../../dist/vue.js"></script>
</head>
<body>
<div id="app"></div>
</body>
<script>
const {h} =Vue
const vnode=h('div',{
class:[
{
'red':true,
},
{
'pink':true,
},
{
'blue':false
}
]
},'增强class')
console.log(vnode)
</script>
</html>

View File

@@ -0,0 +1,18 @@
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Document</title>
<script src="../../dist/vue.js"></script>
</head>
<body>
<div id="app"></div>
</body>
<script>
const {h} =Vue
const vnode=h('div',{
class:'test'
},'hello render')
console.log(vnode)
</script>
</html>

View File

@@ -0,0 +1,27 @@
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Document</title>
<script src="../../dist/vue.js"></script>
</head>
<body>
<div id="app"></div>
</body>
<script>
//Fragment : 片段 vue3一个模板中, 可以有多个根节点,就是利用这片段完成的
const { h, render, Text,Comment,Fragment } = Vue
// const vnodeText = h(Text, '这是一个Text')
// console.log(vnodeText)
// const vnodeComment=h(Comment,'这是一个comment')
// console.log(vnodeComment);
// render(vnodeComment,document.querySelector('#app'))
const vnodeFragment=h(Fragment)
console.log(vnodeFragment);
render(vnodeFragment,document.querySelector('#app'))
</script>
</html>

View File

@@ -0,0 +1,24 @@
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Document</title>
<script src="../../dist/vue.js"></script>
</head>
<body>
<div id="app"></div>
</body>
<script>
//Fragment : 片段 vue3一个模板中, 可以有多个根节点,就是利用这片段完成的
const { h, render, Text,Comment,Fragment } = Vue
const vnodeText = h(Text, '这是一个Text')
console.log(vnodeText)
const vnodeComment=h(Comment,'这是一个comment')
console.log(vnodeComment);
const vnodeFragment=h(Fragment)
console.log(vnodeFragment);
</script>
</html>

View File

@@ -1 +1,9 @@
export { reactive, effect } from '@vue/reactivity' export { reactive, effect, ref, computed } from '@vue/reactivity'
export {
queuePreFlushCb,
watch,
h,
Fragment,
Text,
Comment
} from '@vue/runtime-core'