Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: Tencent/omi
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 3fe356fe49eafa3db53165797d5a60fb015c2aae
Choose a base ref
...
head repository: Tencent/omi
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: fe8265c10010a1b02cb50ab3023f60a766825ee7
Choose a head ref
  • 8 commits
  • 7 files changed
  • 4 contributors

Commits on Jan 13, 2025

  1. chore(omi): publish

    dntzhang committed Jan 13, 2025

    Verified

    This commit was signed with the committer’s verified signature.
    antfu Anthony Fu
    Copy the full SHA
    ae6d17b View commit details

Commits on Jan 24, 2025

  1. fix: omi-templates页面滚动自动切换右边的导航active项

    Fanceir committed Jan 24, 2025

    Verified

    This commit was signed with the committer’s verified signature.
    antfu Anthony Fu
    Copy the full SHA
    04cf9c3 View commit details

Commits on Feb 8, 2025

  1. Merge pull request #943 from Fanceir/issue-#876

    fix: omi-templates页面滚动自动切换右边的导航active项
    dntzhang authored Feb 8, 2025

    Verified

    This commit was signed with the committer’s verified signature.
    antfu Anthony Fu
    Copy the full SHA
    10e8e21 View commit details

Commits on Feb 21, 2025

  1. Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    1fce73f View commit details
  2. Copy the full SHA
    5234a21 View commit details

Commits on Feb 24, 2025

  1. Copy the full SHA
    5883084 View commit details
  2. feat: 支持复杂对象使用DOMProperty的方式传参

    duenyang committed Feb 24, 2025
    Copy the full SHA
    6e1095f View commit details
  3. Merge pull request #944 from duenyang/master

    feat: 支持复杂对象使用DOMProperty的方式传参
    dntzhang authored Feb 24, 2025
    Copy the full SHA
    fe8265c View commit details
28 changes: 11 additions & 17 deletions packages/omi-templates/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 0 additions & 7 deletions packages/omi-templates/src/pages/food.tsx
Original file line number Diff line number Diff line change
@@ -46,13 +46,6 @@ const techniques = signal([
},
])

const navItems = [
{ label: '首页' },
{ label: '菜谱' },
{ label: '烹饪技艺' },
{ label: '关于我们' },
{ label: '联系我们' },
]

export function Food() {
return (
104 changes: 98 additions & 6 deletions packages/omi-templates/src/pages/product-docs.tsx
Original file line number Diff line number Diff line change
@@ -9,8 +9,10 @@ const MdIt = MarkdownIt.default ? MarkdownIt.default : MarkdownIt

type NavTreeNode = {
title: string
level: number
children: NavTreeNode[]
}
//这里新加入的level是为了对应markdown标题

type Props = {
lang: string
@@ -27,10 +29,10 @@ export class ProductDocs extends Component<Props> {
navTree: NavTreeNode
active: [string, string]
} = {
markdownContent: '',
navTree: { title: '', children: [] },
active: ['', ''],
}
markdownContent: '',
navTree: { title: '', level: 1, children: [] },
active: ['', ''],
}

@bind
async onChange(evt: CustomEvent) {
@@ -46,8 +48,85 @@ export class ProductDocs extends Component<Props> {

install() {
this.state.markdownContent = this.props.markdownContent

this.setNavTree()
// 添加滚动监听
window.addEventListener('scroll', this.handleScroll)
}

// 在组件销毁时移除监听器
uninstall() {
window.removeEventListener('scroll', this.handleScroll)
}

@bind
handleScroll() {
const mdDocs = this.rootElement?.querySelector('md-docs') as HTMLElement & {
rootElement: HTMLElement
}
if (!mdDocs) return

const h2Elements = mdDocs.rootElement.getElementsByTagName('h2')
const h3Elements = mdDocs.rootElement.getElementsByTagName('h3')

const threshold = window.innerHeight / 4

let activeH2: string | null = null
let activeH3: string | null = null

// 找到当前活动的 h2
for (let i = h2Elements.length - 1; i >= 0; i--) {
const h2 = h2Elements[i]
const rect = h2.getBoundingClientRect()

if (rect.top <= threshold) {
activeH2 = h2.textContent
break
}
}

// 如果找到活动的 h2,则在其范围内查找 h3
if (activeH2) {
const activeH2Node = this.state.navTree.children.find(node => node.title === activeH2)
if (activeH2Node) {
const validH3Titles = new Set(activeH2Node.children.map(child => child.title))

// 获取当前 h2 元素的位置
const currentH2 = Array.from(h2Elements).find(h2 => h2.textContent === activeH2)
const currentH2Rect = currentH2?.getBoundingClientRect()

// 获取下一个 h2 元素的位置
const nextH2Index = Array.from(h2Elements).findIndex(h2 => h2.textContent === activeH2) + 1
const nextH2Rect = h2Elements[nextH2Index]?.getBoundingClientRect()

// 从下往上查找第一个在当前 h2 范围内的可见 h3
for (let i = h3Elements.length - 1; i >= 0; i--) {
const h3 = h3Elements[i]
const rect = h3.getBoundingClientRect()

// 确保 h3 在当前 h2 和下一个 h2 之间
const isInCurrentSection =
rect.top >= (currentH2Rect?.top || 0) &&
(!nextH2Rect || rect.top <= nextH2Rect.top)

if (rect.top <= threshold &&
isInCurrentSection &&
validH3Titles.has(h3.textContent || '')) {
activeH3 = h3.textContent
break
}
}
}
}

// 如果切换到新的 h2,但没有找到对应的 h3,就清空 h3 的激活状态
if (this.state.active[0] !== activeH2) {
activeH3 = null
}

if (this.state.active[0] !== activeH2 || this.state.active[1] !== activeH3) {
this.state.active = [activeH2 || '', activeH3 || '']
this.update()
}
}

// 提取 markdown 中的标题
@@ -60,7 +139,20 @@ export class ProductDocs extends Component<Props> {
const token = tokens[i]
if (token.type === 'heading_open') {
const title = tokens[i + 1].content
const newNode: NavTreeNode = { title, children: [] }
let level = 1

// 根据标题标签设置层级
if (token.tag === 'h2') {
level = 2
} else if (token.tag === 'h3') {
level = 3
}

const newNode: NavTreeNode = {
title,
children: [],
level
}

if (token.tag === 'h2') {
this.state.navTree.children.push(newNode)
2 changes: 1 addition & 1 deletion packages/omi/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "omi",
"version": "7.7.4",
"version": "7.7.5",
"scripts": {
"start": "vite",
"dev-vite": "vite",
519 changes: 508 additions & 11 deletions packages/omi/pnpm-lock.yaml

Large diffs are not rendered by default.

120 changes: 87 additions & 33 deletions packages/omi/src/component.ts
Original file line number Diff line number Diff line change
@@ -66,6 +66,8 @@ export class Component<State = any> extends HTMLElement {
static hooks: ComponentHookRegistry
// 被所有组件继承
static props = {}
// 是否针对复杂类型使用DOMProperty的方式传值
static useDOMProperty = false

// 可以延迟定义,防止 import { } 被 tree-shaking 掉
static define(name: string): void {
@@ -161,6 +163,67 @@ export class Component<State = any> extends HTMLElement {

// @ts-ignore fix lazy load props missing
this.props = Object.assign({}, this.constructor.defaultProps, this.props)

if (!this.props.ignoreAttrs) {
this.handleComplexProps()
}
}

/**
* 处理复杂类型的属性,如对象、数组,使用 DOM Property 的方式获取值
* 其它基本类型使用 attribute 的方式获取值
*/
private handleComplexProps() {
const propTypes = this.constructor.propTypes as PropTypes
Object.keys(propTypes).forEach(propName => {
// 检查是否是复杂类型
const isComplexType = this.constructor.isComplexType(propName)

if (isComplexType) {
Object.defineProperty(this, propName, {
get: () => this.props[propName],
set: (value) => {
if (Object.is(value, this.props[propName])) return

this.props[propName] = value
this.queuedUpdate()
},
enumerable: true,
configurable: true
})
}
})
}

static isComplexType(propName: string) {
if (!this.useDOMProperty) return false

const propTypes = this.propTypes as PropTypes
if (!propTypes[propName] || /^on|children/.test(propName)) {
return false
}
const types = isArray(propTypes[propName])
? propTypes[propName] as PropType[]
: [propTypes[propName]] as PropType[]

// 检查是否是复杂类型
return types.some(t =>
t === Object || t === Array || (isArray(t) && t.includes(Object))
)
}

static get observedAttributes() {
// 兼容之前老的逻辑
if (Object.keys(this.props || {}).length > 0) {
return Object.keys(this.props).map(hyphenate)
}
// 根据 propTypes 获取需要监听的属性
if (Object.keys(this.propTypes || {}).length > 0) {
return Object.keys(this.propTypes)
.filter((p) => !/^on|children/.test(p) && !this.isComplexType(p))
.map(hyphenate)
}
return []
}

attributeChangedCallback(name, oldValue, newValue) {
@@ -173,7 +236,7 @@ export class Component<State = any> extends HTMLElement {
prop.changed.call(this, newTypeValue, oldTypeValue)
}
}
if(!this.props.ignoreAttrs){
if (!this.props.ignoreAttrs) {
this.update()
}
}
@@ -193,18 +256,6 @@ export class Component<State = any> extends HTMLElement {
}
}

static get observedAttributes() {
if (Object.keys(this.props || {}).length > 0) {
return Object.keys(this.props).map(hyphenate)
}
if(Object.keys(this.propTypes || {}).length > 0){
return Object.keys(this.propTypes)
.filter((p) => !/^on|children/.test(p))
.map(hyphenate)
}
return []
}

injectObject() {
let p: ExtendedElement = this.parentNode as ExtendedElement
// @ts-ignore deprecated
@@ -294,7 +345,7 @@ export class Component<State = any> extends HTMLElement {

// add globalCSS
styleSheets = [...options.globalCSS, ...styleSheets]
;(this.renderRoot as ShadowRoot).adoptedStyleSheets = styleSheets
;(this.renderRoot as ShadowRoot).adoptedStyleSheets = styleSheets
adoptedStyleSheetsMap.set(this.constructor, styleSheets)
} else {
if (options.globalCSS.length) {
@@ -436,19 +487,22 @@ export class Component<State = any> extends HTMLElement {
attrsToProps(): void {
if (this.props.ignoreAttrs) return
const ele = this
const constructor = this.constructor as typeof Component
ele.props['css'] = ele.getAttribute('css')
const attrs = (this.constructor as typeof Component).propTypes
const attrs = constructor.propTypes
if (!attrs) return
Object.keys(attrs).forEach((key) => {
if (constructor.isComplexType(key)) return

const val = ele.getAttribute(hyphenate(key))
if (val !== null) {
ele.props[key] = this.getTypeValueOfProp(key, val)
} else {
if (
(ele.constructor as typeof Component).defaultProps &&
(ele.constructor as typeof Component).defaultProps.hasOwnProperty(key)
constructor.defaultProps &&
constructor.defaultProps.hasOwnProperty(key)
) {
ele.props[key] = (ele.constructor as typeof Component).defaultProps[
ele.props[key] = constructor.defaultProps[
key
]
} else {
@@ -513,17 +567,17 @@ export class Component<State = any> extends HTMLElement {
}
}

install() {}
install() { }

installed() {}
installed() { }

ready() {}
ready() { }

uninstall() {}
uninstall() { }

beforeUpdate() {}
beforeUpdate() { }

updated() {}
updated() { }

beforeRender() {
// 针对非omi环境使用children的情况
@@ -532,22 +586,22 @@ export class Component<State = any> extends HTMLElement {
}
}

rendered(vnode: VNode | VNode[]) {}
rendered(vnode: VNode | VNode[]) { }

receiveProps() {}
receiveProps() { }
}

export class FormAssociatedComponent extends Component {
static formAssociated: boolean = false
_form: HTMLFormElement | null = null // 引用表单元素
_inputs: HTMLInputElement[] = [] // 引用表单元素内部的 input 元素
_internals: ElementInternals | null = null // 表单元素内部对象
formAssociatedCallback(form: HTMLFormElement) {} // 当组件被添加到表单元素内部时调用
handleFormData(event: FormDataEvent) {} // 处理表单数据事件
getFieldValue(): Record<string, any> {} // 返回获取 input 元素的值
formAssociatedCallback(form: HTMLFormElement) { } // 当组件被添加到表单元素内部时调用
handleFormData(event: FormDataEvent) { } // 处理表单数据事件
getFieldValue(): Record<string, any> { } // 返回获取 input 元素的值
resetFieldValue(): void // 当重新表单时调用
handleField(event: Event) {} // 处理 input 事件
formDisabledCallback() {} // 当表单元素被禁用时调用
formResetCallback() {} // 当表单元素被重置时调用
formStateRestoreCallback(state: any, mode: any) {} // 当表单元素状态被恢复时调用
handleField(event: Event) { } // 处理 input 事件
formDisabledCallback() { } // 当表单元素被禁用时调用
formResetCallback() { } // 当表单元素被重置时调用
formStateRestoreCallback(state: any, mode: any) { } // 当表单元素状态被恢复时调用
}
2 changes: 1 addition & 1 deletion packages/omi/src/index.ts
Original file line number Diff line number Diff line change
@@ -22,4 +22,4 @@ export type { Signal, SignalObject, Signal as SignalValue } from 'reactive-signa
export { css } from './css-tag'
export { mixin, globalCSS } from './options'
export { registerDirective } from './directive'
export const version = '7.7.4'
export const version = '7.7.5'