npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

ok-lit

v1.5.0

Published

proof of concept custom elements framework powered by @vue/reactivity + lit-html

Downloads

26

Readme

ok-lit 🖖🔥

npm scripts

yarn serve | npm run serve 本地运行项目

yarn build | npm run build 打包项目

示例🔥

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport"
        content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
<my-component count="1.23123" callback="function add(a,b) { return a+b }"></my-component>
<todo-list></todo-list>
</body>
</html>
<script src="../dist/ok-lit.umd.js"></script>
<script>
  const {
    defineComponent,
    reactive,
    ref,
    html,
    onMounted,
    onUpdated,
    onUnmounted,
  } = window.okLit

  defineComponent('my-component', {
    count: {
      type: [Number, String],
      required: true,
      default: 1,
      transform(value) {
        return parseInt(value)
      }
    },
    callback: {
      type: Function
    }
  }, (props, context) => {
    const state = reactive({
      text: 'hello',
      show: true,
      childData: {
        text: 'hola'
      }
    })
    const toggle = () => {
      state.show = !state.show
    }
    const onInput = e => {
      state.text = e.target.value
    }

    const onIncrease = e => {
      console.log('child increase', e.detail)
    }

    const testExpose = () => {
      console.log('TEST expose')
    }
    const testExpose2 = () => {
        console.log('TEST expose 2')
    }
    // 抛出函数,使外部可以使用
    context.expose({
        testExpose,
        testExpose2
    })

    onMounted(() => {
      console.log(context.$refs)
    })

    onUpdated(() => {
      console.log(context.$refs)
    })

    const mountedCallback = () => {
      console.log('child mounted in parent', '此时并拿不到$refs.myChild')
    }

    return () => html`
      <button @click=${toggle}>toggle child</button>
      <p>
      ${state.text} <input value=${state.text} @input=${onInput}>
      </p>
      <p v-show="${state.show}">style display v-show</p>
      <p ref="p">A: ${state.childData.text}</p>
      ${state.show ? html`<my-child @hook:mounted="${mountedCallback}" ref="myChild" .msg=${state.text} .data=${state.childData} @increase="${onIncrease}"></my-child>` : ``}
    `
    // 在defineComponent里边使用子组件传参时,使用.可以直接传入对象
  })

  defineComponent('my-child', {
    msg: {
      type: String,
    },
    data: {
      type: Object
    }
  }, (props, context) => {
    const state = reactive({ count: 0 })
    const increase = () => {
      state.count++
      context.emit('increase', state.count)
    }
    onMounted(() => {
      console.log('child mounted')
    })

    onUpdated(() => {
      console.log('child updated')
    })

    onUnmounted(() => {
      console.log('html child unmounted')
    })

    return () => html`
      <p>${props.msg}</p>
      <p>X: ${props.data?.text}<p>
      <p>${state.count}</p>
      <button @click=${increase}>increase</button>
    `
  })

  defineComponent('todo-list', () => {
    const list = ref([{ key: 1, label: '第一项' }, { key: 2, label: '第二项' }, { key: 3, label: '第三项' }])

    const classObj = {
      selected: true
    }

    return () => html`
      <ul class="${classMap(classObj)}">
        ${repeat(list.value, (item) => item.key, item => html`<li>${item.label}</li>`) }
      </ul>
    `
  })
</script>

html编写模版api参考

1. v-show 同Vue的v-show

2. ref 同Vue的ref,可以通过context.$refs取到

3. 需要判断的dom可以使用三目表达式,或者在函数中定义变量,基本等同于jsx

4. 需要循环遍历的dom,可以使用map,也可以使用lit-html内置的repeat方法:Repeating templates with the repeat directive

5. 在Vue2、React或者HTML中,在DOM上传参,如果是复杂类型(对象,数组,函数等),对象,数组需要传JSON字符串,函数需要传函数字符串(function () {} 或者 () => {})

6. 在Vue2、React或者HTML中,如果不想让props显示到元素的attribute上(Vue3可以直接使用v-bind,不会有该问题),可以通过js的方式给组件设置props值,仅限外部引用组件时可以这么使用,使用ok-lit开发组件时,需要在attribute上不展示的属性,请使用.attr=value代替, 例如:

<body>
  <my-component></my-component>
</body>
<script>
  // 外部使用组件
  const myComponent = document.querySelector('my-component')
  myComponent.count = 1
  myComponent.callback = function(a, b) {
    return a + b
  }
  
  // 开发组件
  defineComponent('test-component', () => {
    const count = 1
    const add = (a, b) => {
      return a + b
    }
    
    return () => html`
      <my-component .count="${count}" .callback="${add}"></my-component>
    `
  })
</script>

API🖖

defineComponent

// name参数是注册的组件名, props 组件接收的参数类型定义, setup 类似于Vue3的setup函数,在内部执行@vue/reactivity的内容,并return一个返回htmlTemplate的函数(参考上例)
declare function defineComponent(name: string, props: PropsType | SetupFn, setup?: SetupFn)

props

为了解决web components 组件只能接收字符串的问题,ok-lit为props提供了一定的类型转换能力,内置了String,Number,Boolean,Function,Array,Object六种类型的转换,当type提供一个数组的时候,会尝试按照数组的顺序进行转换

Props会有一定的类型推导能力,如果需要指定精确的类型,请使用PropType

import { PropType, defineComponent } from 'ok-lit'

interface Item {
  name: string
  type: string
}
defineComponent('my-component', { prop: {
  type: Array as unknown as PropType<Array<Item>>
  } }, props => {
  console.log(props.prop[0].name) // 可以正确的进行typescript类型推导
})
export type PropType<T = any> = T
export type PropTypes<T = any> = StringConstructor | NumberConstructor | BooleanConstructor | ObjectConstructor | ArrayConstructor | FunctionConstructor | PropType<T>
export interface Prop<T = PropTypes> {
  type: PropTypes<T> | PropTypes<T>[]
  default?: string | number | boolean | object | Array<any> | Function
  required?: boolean
  // 可以使用transform进行手动格式转换,不采用ok-lit默认提供的格式转换方法
  transform?: (value: string) => any
  // 可以使用validator进行参数格式校验,但这并不会影响组件的运行
  validator?: (value: unknown) => boolean | never | Promise<boolean>
}
export interface PropsType {
  [key: string]: Prop
}

setup

// props是外部传入的属性对象, context 当前的CustomElement实例
type SetupFn = (props: object, context: {
  // 当前的shadow dom
  $el: ShadowRoot
  // 当前TemplateResult上边的ref的dom
  $refs: Record<string, HTMLElement>
  // 事件发布,event参数是事件名称,payload参数是携带的值
  emit(event: string, payload?: any): void
}) => () => TemplateResult
  // 暴露方法或属性给外部调用,注意不能和props重名
  expose(exposeMap: Record<string, any>): void

其余api参考

  1. lit-html
  2. @vue/reactivity