初始化

  1. npm init stencil // 初始化stencil, 然后进入下方选择初始化类型
  2. [选择这个]> component // 选择组件方式
  3. > app [community] // 构建应用网站模式
  4. // 然后进入文件夹 安装依赖
  5. yarn install
  6. // 运行
  7. yarn start

image.png

目录介绍

  1. - dist // 存放运行编译后的代码,也就是每次修改打包后的文件、
  2. - src // 工程代码
  3. - components // 存放组件的目录
  4. - utils // 公共方法存放地址
  5. - components.d.ts // 全局组件注入类型文件(自动生成、不用管)
  6. - index.html // 也是框架自动会引入组件用作展示的地方
  7. - index.ts //
  8. - stencil.config.ts // stencil配置文件、包括打包的规则
  9. - tsconfig.json // ts 配置
  10. - www // 文件夹是在开发过程中启动调试所用到的资源文件、也就是我们yarn start运行的调试页面

介绍组件

执行 yarn generate 默认三个都选上了包括两个测试文件、取消某个按下空格、回车直接快速生成
image.png

  1. import { Component, Host, h, Prop, Event, EventEmitter, State, Watch, Method, Element } from '@stencil/core';
  2. @Component({
  3. tag: 'my-button', // 组件名称
  4. styleUrl: 'my-button.css', // 组件样式
  5. shadow: false, // 是否开启沙盒模式
  6. })
  7. export class MyButton {
  8. /***** 生命周期 start ********* */
  9. // 初次加载
  10. connectedCallback(){
  11. console.log('[lifecycle 1] connectedCallback')
  12. }
  13. componentWillLoad() {
  14. console.log('[lifecycle 2] componentWillLoad')
  15. }
  16. componentWillRender() {
  17. console.log('[lifecycle 3] componentWillRender')
  18. }
  19. componentDidRender() {
  20. console.log('[lifecycle 6] componentDidRender')
  21. }
  22. componentDidLoad() {
  23. console.log('[lifecycle 7] componentDidLoad')
  24. }
  25. // 组件重新连接[类似移除后重新插入 connectedCallback() ]
  26. /*
  27. const el = document.createElement('my-cmp');
  28. 此时由于 el 是新添加 所以会执行 组件初次加载 的逻辑
  29. document.body.appendChild(el);
  30. el.remove();
  31. // 此时由于 el 已经初始化一遍,再次添加到 body 只会执行 组件重新连接 的逻辑
  32. document.body.appendChild(el);
  33. */
  34. // 组件更新
  35. componentDidUpdate() {
  36. console.log('[lifecycle 组件更新] componentDidUpdate')
  37. }
  38. // 组件销毁
  39. disconnectedCallback(){
  40. console.log('[lifecycle] 组件销毁被执行')
  41. }
  42. /***** 生命周期 end *********** */
  43. /***** 获取整个组件元素 start ********* */
  44. @Element() el: HTMLElement;
  45. /***** 获取整个组件元素 end ********* */
  46. /***** 定义内部响应式 start ********* */
  47. @State() num: number = 0;
  48. handleNum() { this.num += 1}
  49. /***** 定义内部响应式 end *********** */
  50. /***** 监听内部num变化 start ********* */
  51. @Watch('num')
  52. watchPropHandler(newValue: number, oldValue: number) {
  53. console.log('num变化了', newValue, oldValue);
  54. }
  55. /***** 监听内部num变化 end*** ********* */
  56. /***** props定义接受一个text start ********* */
  57. @Prop() text: string
  58. /***** props定义接受一个text end ********* */
  59. /***** 定义组件元素派发的事件 start ********* */
  60. @Event({
  61. eventName: 'on-click', // 事件名称
  62. bubbles: true, // 是否支持冒泡
  63. cancelable: true, // 是否支持可取消
  64. composed: true, // 冒泡事件是否逃逸出当前的 shadowdom
  65. })
  66. displayOnClick: EventEmitter<{ data: { mes: string, el: HTMLElement } }>
  67. handClick(): void {
  68. this.displayOnClick.emit({
  69. data: {
  70. mes: '派发出来的消息',
  71. el: this.el
  72. }
  73. })
  74. }
  75. /***** 定义组件元素派发的事件 end ********* */
  76. /***** 定义外部通过节点调用内部的方法 start ********* */
  77. @Method()
  78. async showPrompt() {
  79. return {
  80. num: this.num,
  81. el: this.el
  82. }
  83. }
  84. /***** 定义外部通过节点调用内部的方法 end ********* */
  85. render() {
  86. console.log('[lifecycle 4] render')
  87. return (
  88. <Host>
  89. <div>
  90. <button onClick={ this.handClick.bind(this) }>往外部抛事件</button>
  91. {/* slot接收 */}
  92. <slot></slot>
  93. {/* 作用域插槽 */}
  94. <slot name='header'></slot>
  95. {/* 展示props值 */}
  96. <span>{this.text}</span>
  97. <button onClick={ this.handleNum.bind(this)}>num+1</button>
  98. </div>
  99. </Host>
  100. );
  101. }
  102. }

外部使用测试

  1. <!DOCTYPE html>
  2. <html dir="ltr" lang="en">
  3. <head>
  4. <meta charset="utf-8" />
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=5.0" />
  6. <title>Stencil Component Starter</title>
  7. <script type="module" src="/build/sten-components.esm.js"></script>
  8. <script nomodule src="/build/sten-components.js"></script>
  9. </head>
  10. <body>
  11. <my-button text="gf" id="myButton">
  12. <span style="color: red;">我是默认插槽内容</span>
  13. <span slot="header" style="color: blue;">我是header插槽内容</span>
  14. </my-button>
  15. </body>
  16. </html>
  17. <script>
  18. // 监听方法
  19. const button = document.getElementById('myButton')
  20. button.addEventListener('on-click', (e) => {
  21. console.log(e.detail)
  22. })
  23. // 外部调用
  24. setTimeout(async () => {
  25. const res = await button.showPrompt();
  26. console.log(res)
  27. }, 1000)
  28. </script>

文档地址