officialblock 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,82 @@
1
+ # OfficialBlock
2
+
3
+ A Vue 3 article list component library.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install officialblock
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ### 方式一:全部引入
14
+
15
+ ```javascript
16
+ import { createApp } from 'vue'
17
+ import OfficialBlock from 'officialblock'
18
+ import 'officialblock/style.css'
19
+
20
+ const app = createApp(App)
21
+ app.use(OfficialBlock)
22
+
23
+ // 现在可以在任何组件中使用
24
+ // <ArticleList />
25
+ // <HeroSlide />
26
+ ```
27
+
28
+ ### 方式二:按需引入组件
29
+
30
+ ```javascript
31
+ import { ArticleList, HeroSlide } from 'officialblock'
32
+ import 'officialblock/style.css'
33
+
34
+ export default {
35
+ components: {
36
+ ArticleList,
37
+ HeroSlide
38
+ }
39
+ }
40
+ ```
41
+
42
+ ### 方式三:按需引入插件
43
+
44
+ ```javascript
45
+ import { createApp } from 'vue'
46
+ import { ArticleListPlugin, HeroSlidePlugin } from 'officialblock'
47
+ import 'officialblock/style.css'
48
+
49
+ const app = createApp(App)
50
+ app.use(ArticleListPlugin) // 只注册 ArticleList 组件
51
+ app.use(HeroSlidePlugin) // 只注册 HeroSlide 组件
52
+ ```
53
+
54
+ ### TypeScript Support
55
+
56
+ This package includes TypeScript definitions.
57
+
58
+ ```typescript
59
+ import type { ComponentProps, ComponentEmits, ComponentSlots } from 'officialblock'
60
+ ```
61
+
62
+ ## Components
63
+
64
+ - **ArticleList**: 文章列表组件
65
+ - **HeroSlide**: 轮播图组件
66
+
67
+ ## Development
68
+
69
+ ```bash
70
+ # Install dependencies
71
+ npm install
72
+
73
+ # Start development server
74
+ npm run dev
75
+
76
+ # Build for production
77
+ npm run build
78
+ ```
79
+
80
+ ## License
81
+
82
+ MIT
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("vue"),_={class:"content"},f=e.defineComponent({__name:"index",props:{size:{default:"medium"},disabled:{type:Boolean,default:!1},modelValue:{}},emits:["update:modelValue","change","focus"],setup(t,{emit:o}){const l=t,n=o,c=e.computed(()=>`Current value: ${l.modelValue}`);function a(){l.disabled||n("change",l.modelValue)}return(s,m)=>(e.openBlock(),e.createElementBlock("div",{class:e.normalizeClass(["your-component",[`size-${s.size}`,{"is-disabled":s.disabled}]]),onClick:a},[e.renderSlot(s.$slots,"header",{title:c.value},void 0,!0),e.createElementVNode("div",_,[e.renderSlot(s.$slots,"default",{value:s.modelValue},()=>[e.createTextVNode(e.toDisplayString(s.modelValue),1)],!0)])],2))}}),v=(t,o)=>{const l=t.__vccOpts||t;for(const[n,c]of o)l[n]=c;return l},k=v(f,[["__scopeId","data-v-6e4f6df3"]]),d={install:t=>{t.component("ArticleList",k)}},S={class:"hero-slide"},g={class:"slide-container"},h={class:"slide-indicators"},B=["onClick"],y=e.defineComponent({__name:"index",setup(t){const o=e.ref(0),l=e.ref([{title:"轮播图标题 1",description:"这是第一张轮播图的描述内容"},{title:"轮播图标题 2",description:"这是第二张轮播图的描述内容"},{title:"轮播图标题 3",description:"这是第三张轮播图的描述内容"}]);let n=null;const c=p=>{o.value=p},a=()=>{o.value=(o.value+1)%l.value.length},s=()=>{n=window.setInterval(a,3e3)},m=()=>{n&&(clearInterval(n),n=null)};return e.onMounted(()=>{s()}),e.onUnmounted(()=>{m()}),(p,C)=>(e.openBlock(),e.createElementBlock("div",S,[e.createElementVNode("div",g,[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(l.value,(r,i)=>(e.openBlock(),e.createElementBlock("div",{key:i,class:e.normalizeClass(["slide-item",{active:o.value===i}])},[e.createElementVNode("h2",null,e.toDisplayString(r.title),1),e.createElementVNode("p",null,e.toDisplayString(r.description),1)],2))),128))]),e.createElementVNode("div",h,[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(l.value,(r,i)=>(e.openBlock(),e.createElementBlock("span",{key:i,class:e.normalizeClass(["indicator",{active:o.value===i}]),onClick:$=>c(i)},null,10,B))),128))])]))}}),V=v(y,[["__scopeId","data-v-73cbd566"]]),u={install:t=>{t.component("HeroSlide",V)}},E={install:t=>{t.component("ArticleList",d),t.component("HeroSlide",u)}};exports.ArticleList=d;exports.ArticleListPlugin=d;exports.HeroSlide=u;exports.HeroSlidePlugin=u;exports.default=E;
@@ -0,0 +1,92 @@
1
+ import { defineComponent as k, computed as $, createElementBlock as i, openBlock as a, normalizeClass as m, renderSlot as f, createElementVNode as d, createTextVNode as V, toDisplayString as p, ref as h, onMounted as A, onUnmounted as C, Fragment as S, renderList as g } from "vue";
2
+ const L = { class: "content" }, b = /* @__PURE__ */ k({
3
+ __name: "index",
4
+ props: {
5
+ size: { default: "medium" },
6
+ disabled: { type: Boolean, default: !1 },
7
+ modelValue: {}
8
+ },
9
+ emits: ["update:modelValue", "change", "focus"],
10
+ setup(e, { emit: l }) {
11
+ const t = e, o = l, c = $(() => `Current value: ${t.modelValue}`);
12
+ function r() {
13
+ t.disabled || o("change", t.modelValue);
14
+ }
15
+ return (n, v) => (a(), i("div", {
16
+ class: m(["your-component", [`size-${n.size}`, { "is-disabled": n.disabled }]]),
17
+ onClick: r
18
+ }, [
19
+ f(n.$slots, "header", { title: c.value }, void 0, !0),
20
+ d("div", L, [
21
+ f(n.$slots, "default", { value: n.modelValue }, () => [
22
+ V(p(n.modelValue), 1)
23
+ ], !0)
24
+ ])
25
+ ], 2));
26
+ }
27
+ }), y = (e, l) => {
28
+ const t = e.__vccOpts || e;
29
+ for (const [o, c] of l)
30
+ t[o] = c;
31
+ return t;
32
+ }, H = /* @__PURE__ */ y(b, [["__scopeId", "data-v-6e4f6df3"]]), P = {
33
+ install: (e) => {
34
+ e.component("ArticleList", H);
35
+ }
36
+ }, z = { class: "hero-slide" }, I = { class: "slide-container" }, B = { class: "slide-indicators" }, T = ["onClick"], w = /* @__PURE__ */ k({
37
+ __name: "index",
38
+ setup(e) {
39
+ const l = h(0), t = h([
40
+ { title: "轮播图标题 1", description: "这是第一张轮播图的描述内容" },
41
+ { title: "轮播图标题 2", description: "这是第二张轮播图的描述内容" },
42
+ { title: "轮播图标题 3", description: "这是第三张轮播图的描述内容" }
43
+ ]);
44
+ let o = null;
45
+ const c = (_) => {
46
+ l.value = _;
47
+ }, r = () => {
48
+ l.value = (l.value + 1) % t.value.length;
49
+ }, n = () => {
50
+ o = window.setInterval(r, 3e3);
51
+ }, v = () => {
52
+ o && (clearInterval(o), o = null);
53
+ };
54
+ return A(() => {
55
+ n();
56
+ }), C(() => {
57
+ v();
58
+ }), (_, D) => (a(), i("div", z, [
59
+ d("div", I, [
60
+ (a(!0), i(S, null, g(t.value, (u, s) => (a(), i("div", {
61
+ key: s,
62
+ class: m(["slide-item", { active: l.value === s }])
63
+ }, [
64
+ d("h2", null, p(u.title), 1),
65
+ d("p", null, p(u.description), 1)
66
+ ], 2))), 128))
67
+ ]),
68
+ d("div", B, [
69
+ (a(!0), i(S, null, g(t.value, (u, s) => (a(), i("span", {
70
+ key: s,
71
+ class: m(["indicator", { active: l.value === s }]),
72
+ onClick: (F) => c(s)
73
+ }, null, 10, T))), 128))
74
+ ])
75
+ ]));
76
+ }
77
+ }), E = /* @__PURE__ */ y(w, [["__scopeId", "data-v-73cbd566"]]), N = {
78
+ install: (e) => {
79
+ e.component("HeroSlide", E);
80
+ }
81
+ }, O = {
82
+ install: (e) => {
83
+ e.component("ArticleList", P), e.component("HeroSlide", N);
84
+ }
85
+ };
86
+ export {
87
+ P as ArticleList,
88
+ P as ArticleListPlugin,
89
+ N as HeroSlide,
90
+ N as HeroSlidePlugin,
91
+ O as default
92
+ };
@@ -0,0 +1 @@
1
+ (function(l,e){typeof exports=="object"&&typeof module<"u"?e(exports,require("vue")):typeof define=="function"&&define.amd?define(["exports","vue"],e):(l=typeof globalThis<"u"?globalThis:l||self,e(l.OfficialBlock={},l.Vue))})(this,function(l,e){"use strict";const k={class:"content"},h=e.defineComponent({__name:"index",props:{size:{default:"medium"},disabled:{type:Boolean,default:!1},modelValue:{}},emits:["update:modelValue","change","focus"],setup(t,{emit:o}){const n=t,i=o,a=e.computed(()=>`Current value: ${n.modelValue}`);function m(){n.disabled||i("change",n.modelValue)}return(s,f)=>(e.openBlock(),e.createElementBlock("div",{class:e.normalizeClass(["your-component",[`size-${s.size}`,{"is-disabled":s.disabled}]]),onClick:m},[e.renderSlot(s.$slots,"header",{title:a.value},void 0,!0),e.createElementVNode("div",k,[e.renderSlot(s.$slots,"default",{value:s.modelValue},()=>[e.createTextVNode(e.toDisplayString(s.modelValue),1)],!0)])],2))}}),u=(t,o)=>{const n=t.__vccOpts||t;for(const[i,a]of o)n[i]=a;return n},S=u(h,[["__scopeId","data-v-6e4f6df3"]]),r={install:t=>{t.component("ArticleList",S)}},y={class:"hero-slide"},B={class:"slide-container"},g={class:"slide-indicators"},V=["onClick"],E=u(e.defineComponent({__name:"index",setup(t){const o=e.ref(0),n=e.ref([{title:"轮播图标题 1",description:"这是第一张轮播图的描述内容"},{title:"轮播图标题 2",description:"这是第二张轮播图的描述内容"},{title:"轮播图标题 3",description:"这是第三张轮播图的描述内容"}]);let i=null;const a=_=>{o.value=_},m=()=>{o.value=(o.value+1)%n.value.length},s=()=>{i=window.setInterval(m,3e3)},f=()=>{i&&(clearInterval(i),i=null)};return e.onMounted(()=>{s()}),e.onUnmounted(()=>{f()}),(_,A)=>(e.openBlock(),e.createElementBlock("div",y,[e.createElementVNode("div",B,[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(n.value,(p,c)=>(e.openBlock(),e.createElementBlock("div",{key:c,class:e.normalizeClass(["slide-item",{active:o.value===c}])},[e.createElementVNode("h2",null,e.toDisplayString(p.title),1),e.createElementVNode("p",null,e.toDisplayString(p.description),1)],2))),128))]),e.createElementVNode("div",g,[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(n.value,(p,c)=>(e.openBlock(),e.createElementBlock("span",{key:c,class:e.normalizeClass(["indicator",{active:o.value===c}]),onClick:L=>a(c)},null,10,V))),128))])]))}}),[["__scopeId","data-v-73cbd566"]]),d={install:t=>{t.component("HeroSlide",E)}},C={install:t=>{t.component("ArticleList",r),t.component("HeroSlide",d)}};l.ArticleList=r,l.ArticleListPlugin=r,l.HeroSlide=d,l.HeroSlidePlugin=d,l.default=C,Object.defineProperties(l,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
package/dist/style.css ADDED
@@ -0,0 +1 @@
1
+ .your-component[data-v-6e4f6df3]{padding:16px;border:1px solid #ddd;border-radius:8px;background:#fff;transition:all .3s ease}.your-component[data-v-6e4f6df3]:hover{border-color:#409eff;box-shadow:0 2px 8px #409eff33}.your-component.is-disabled[data-v-6e4f6df3]{opacity:.6;cursor:not-allowed;background:#f5f5f5}.your-component.size-small[data-v-6e4f6df3]{padding:8px;font-size:12px}.your-component.size-medium[data-v-6e4f6df3]{padding:16px;font-size:14px}.your-component.size-large[data-v-6e4f6df3]{padding:24px;font-size:16px}.content[data-v-6e4f6df3]{margin-top:8px}.hero-slide[data-v-73cbd566]{position:relative;width:100%;height:300px;overflow:hidden;border-radius:12px;box-shadow:0 4px 12px #0000001a}.slide-container[data-v-73cbd566]{position:relative;width:100%;height:100%}.slide-item[data-v-73cbd566]{position:absolute;top:0;left:0;width:100%;height:100%;display:flex;flex-direction:column;justify-content:center;align-items:center;background:linear-gradient(135deg,#667eea,#764ba2);color:#fff;opacity:0;transition:opacity .5s ease-in-out;text-align:center;padding:20px;box-sizing:border-box}.slide-item.active[data-v-73cbd566]{opacity:1}.slide-item h2[data-v-73cbd566]{margin:0 0 16px;font-size:2rem;font-weight:600}.slide-item p[data-v-73cbd566]{margin:0;font-size:1.1rem;opacity:.9;max-width:600px}.slide-indicators[data-v-73cbd566]{position:absolute;bottom:20px;left:50%;transform:translate(-50%);display:flex;gap:8px}.indicator[data-v-73cbd566]{width:12px;height:12px;border-radius:50%;background:#ffffff80;cursor:pointer;transition:background .3s ease}.indicator.active[data-v-73cbd566]{background:#fff}.indicator[data-v-73cbd566]:hover{background:#fffc}
@@ -0,0 +1 @@
1
+ export {}
package/dist/vite.svg ADDED
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "officialblock",
3
+ "private": false,
4
+ "version": "1.0.0",
5
+ "description": "A Vue 3 article list component library",
6
+ "author": "Your Name",
7
+ "license": "MIT",
8
+ "keywords": [
9
+ "vue",
10
+ "vue3",
11
+ "component",
12
+ "article",
13
+ "list"
14
+ ],
15
+ "homepage": "https://github.com/yourusername/officialblock#readme",
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "git+https://github.com/yourusername/officialblock.git"
19
+ },
20
+ "bugs": {
21
+ "url": "https://github.com/yourusername/officialblock/issues"
22
+ },
23
+ "main": "./dist/official-block.umd.js",
24
+ "module": "./dist/official-block.es.js",
25
+ "types": "./dist/types/index.d.ts",
26
+ "exports": {
27
+ ".": {
28
+ "types": "./dist/types/index.d.ts",
29
+ "import": "./dist/official-block.es.js",
30
+ "require": "./dist/official-block.umd.js"
31
+ },
32
+ "./style.css": "./dist/style.css"
33
+ },
34
+ "files": [
35
+ "dist",
36
+ "src",
37
+ "types"
38
+ ],
39
+ "scripts": {
40
+ "dev": "vite",
41
+ "build": "vue-tsc -b && vite build",
42
+ "preview": "vite preview",
43
+ "prepublishOnly": "npm run build"
44
+ },
45
+ "peerDependencies": {
46
+ "vue": "^3.0.0"
47
+ },
48
+ "devDependencies": {
49
+ "@types/node": "^24.0.10",
50
+ "@vitejs/plugin-vue": "^5.2.4",
51
+ "@vue/tsconfig": "^0.7.0",
52
+ "typescript": "~5.8.3",
53
+ "vite": "^5.4.19",
54
+ "vite-plugin-dts": "^4.5.4",
55
+ "vue": "^3.5.17",
56
+ "vue-tsc": "^2.2.12"
57
+ }
58
+ }
package/src/App.vue ADDED
@@ -0,0 +1,105 @@
1
+ <template>
2
+ <div class="app">
3
+ <header class="header">
4
+ <h1>OfficialBlock 组件库</h1>
5
+ <p>本地开发预览</p>
6
+ </header>
7
+
8
+ <main class="main">
9
+ <section class="component-section">
10
+ <h2>HeroSlide 轮播组件</h2>
11
+ <div class="component-demo">
12
+ <HeroSlide />
13
+ </div>
14
+ </section>
15
+
16
+ <section class="component-section">
17
+ <h2>ArticleList 文章列表组件</h2>
18
+ <div class="component-demo">
19
+ <ArticleList
20
+ v-model="articleValue"
21
+ size="medium"
22
+ :disabled="false"
23
+ @change="(value) => console.log('ArticleList changed:', value)"
24
+ >
25
+ <template #header="{ title }">
26
+ <h3>{{ title }}</h3>
27
+ </template>
28
+ <template #default="{ value }">
29
+ <p>当前值: {{ value }}</p>
30
+ </template>
31
+ </ArticleList>
32
+ </div>
33
+ </section>
34
+ </main>
35
+ </div>
36
+ </template>
37
+
38
+ <script setup lang="ts">
39
+ import { ref } from 'vue'
40
+ import { ArticleList } from './components/ArticleList'
41
+ import { HeroSlide } from './components/HeroSlide'
42
+
43
+ // 为 ArticleList 组件提供响应式数据
44
+ const articleValue = ref('Hello World')
45
+ </script>
46
+
47
+ <style scoped>
48
+ .app {
49
+ max-width: 1200px;
50
+ margin: 0 auto;
51
+ padding: 20px;
52
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
53
+ }
54
+
55
+ .header {
56
+ text-align: center;
57
+ margin-bottom: 40px;
58
+ padding: 20px;
59
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
60
+ color: white;
61
+ border-radius: 12px;
62
+ }
63
+
64
+ .header h1 {
65
+ margin: 0 0 10px 0;
66
+ font-size: 2.5rem;
67
+ font-weight: 600;
68
+ }
69
+
70
+ .header p {
71
+ margin: 0;
72
+ font-size: 1.1rem;
73
+ opacity: 0.9;
74
+ }
75
+
76
+ .main {
77
+ display: flex;
78
+ flex-direction: column;
79
+ gap: 30px;
80
+ }
81
+
82
+ .component-section {
83
+ background: #f8f9fa;
84
+ border-radius: 12px;
85
+ padding: 24px;
86
+ border: 1px solid #e9ecef;
87
+ }
88
+
89
+ .component-section h2 {
90
+ margin: 0 0 20px 0;
91
+ color: #495057;
92
+ font-size: 1.5rem;
93
+ font-weight: 500;
94
+ border-bottom: 2px solid #dee2e6;
95
+ padding-bottom: 10px;
96
+ }
97
+
98
+ .component-demo {
99
+ background: white;
100
+ border-radius: 8px;
101
+ padding: 20px;
102
+ border: 1px solid #dee2e6;
103
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
104
+ }
105
+ </style>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg>
@@ -0,0 +1,11 @@
1
+ import type { App, Plugin } from 'vue'
2
+ import ArticleList from './index.vue'
3
+
4
+ export default {
5
+ install: (app: App) => {
6
+ app.component('ArticleList', ArticleList)
7
+ },
8
+ } satisfies Plugin
9
+
10
+ export { default as ArticleList } from './index.vue'
11
+ export type { ComponentProps, ComponentEmits, ComponentSlots } from './type'
@@ -0,0 +1,73 @@
1
+ <template>
2
+ <div
3
+ class="your-component"
4
+ :class="[`size-${size}`, { 'is-disabled': disabled }]"
5
+ @click="handleClick"
6
+ >
7
+ <slot name="header" :title="title"></slot>
8
+ <div class="content">
9
+ <slot :value="modelValue">{{ modelValue }}</slot>
10
+ </div>
11
+ </div>
12
+ </template>
13
+
14
+ <script lang="ts" setup>
15
+ import { computed } from 'vue'
16
+ import type { ComponentProps, ComponentEmits, ComponentSlots } from './type'
17
+
18
+ const props = withDefaults(defineProps<ComponentProps>(), {
19
+ size: 'medium',
20
+ disabled: false
21
+ })
22
+
23
+ const emit = defineEmits<ComponentEmits>()
24
+ defineSlots<ComponentSlots>()
25
+
26
+ const title = computed(() => `Current value: ${props.modelValue}`)
27
+
28
+ function handleClick() {
29
+ if (!props.disabled) {
30
+ emit('change', props.modelValue)
31
+ }
32
+ }
33
+ </script>
34
+
35
+ <style scoped>
36
+ .your-component {
37
+ padding: 16px;
38
+ border: 1px solid #ddd;
39
+ border-radius: 8px;
40
+ background: #fff;
41
+ transition: all 0.3s ease;
42
+ }
43
+
44
+ .your-component:hover {
45
+ border-color: #409eff;
46
+ box-shadow: 0 2px 8px rgba(64, 158, 255, 0.2);
47
+ }
48
+
49
+ .your-component.is-disabled {
50
+ opacity: 0.6;
51
+ cursor: not-allowed;
52
+ background: #f5f5f5;
53
+ }
54
+
55
+ .your-component.size-small {
56
+ padding: 8px;
57
+ font-size: 12px;
58
+ }
59
+
60
+ .your-component.size-medium {
61
+ padding: 16px;
62
+ font-size: 14px;
63
+ }
64
+
65
+ .your-component.size-large {
66
+ padding: 24px;
67
+ font-size: 16px;
68
+ }
69
+
70
+ .content {
71
+ margin-top: 8px;
72
+ }
73
+ </style>
@@ -0,0 +1,23 @@
1
+ import type { VNode } from 'vue';
2
+
3
+ export interface ComponentProps {
4
+ /** 控制组件尺寸 */
5
+ size?: 'small' | 'medium' | 'large'
6
+ /** 是否禁用状态 */
7
+ disabled?: boolean
8
+ /** 双向绑定的值 */
9
+ modelValue: string | number
10
+ }
11
+
12
+ export interface ComponentEmits {
13
+ (e: 'update:modelValue', value: string | number): void
14
+ (e: 'change', value: string | number): void
15
+ (e: 'focus', event: FocusEvent): void
16
+ }
17
+
18
+ export type ComponentSlots = {
19
+ /** 默认插槽内容 */
20
+ default?: (props: { value: string | number }) => VNode[]
21
+ /** 头部内容 */
22
+ header?: (props: { title: string }) => VNode[]
23
+ }
@@ -0,0 +1,10 @@
1
+ import type { App, Plugin } from 'vue'
2
+ import HeroSlide from './index.vue'
3
+
4
+ export default {
5
+ install: (app: App) => {
6
+ app.component('HeroSlide', HeroSlide)
7
+ },
8
+ } satisfies Plugin
9
+
10
+ export { default as HeroSlide } from './index.vue'
@@ -0,0 +1,143 @@
1
+ <template>
2
+ <div class="hero-slide">
3
+ <div class="slide-container">
4
+ <div
5
+ v-for="(slide, index) in slides"
6
+ :key="index"
7
+ class="slide-item"
8
+ :class="{ active: currentSlide === index }"
9
+ >
10
+ <h2>{{ slide.title }}</h2>
11
+ <p>{{ slide.description }}</p>
12
+ </div>
13
+ </div>
14
+ <div class="slide-indicators">
15
+ <span
16
+ v-for="(_, index) in slides"
17
+ :key="index"
18
+ class="indicator"
19
+ :class="{ active: currentSlide === index }"
20
+ @click="goToSlide(index)"
21
+ ></span>
22
+ </div>
23
+ </div>
24
+ </template>
25
+
26
+ <script setup lang="ts">
27
+ import { ref, onMounted, onUnmounted } from 'vue'
28
+
29
+ const currentSlide = ref(0)
30
+ const slides = ref([
31
+ { title: '轮播图标题 1', description: '这是第一张轮播图的描述内容' },
32
+ { title: '轮播图标题 2', description: '这是第二张轮播图的描述内容' },
33
+ { title: '轮播图标题 3', description: '这是第三张轮播图的描述内容' }
34
+ ])
35
+
36
+ let autoPlayTimer: number | null = null
37
+
38
+ const goToSlide = (index: number) => {
39
+ currentSlide.value = index
40
+ }
41
+
42
+ const nextSlide = () => {
43
+ currentSlide.value = (currentSlide.value + 1) % slides.value.length
44
+ }
45
+
46
+ const startAutoPlay = () => {
47
+ autoPlayTimer = window.setInterval(nextSlide, 3000)
48
+ }
49
+
50
+ const stopAutoPlay = () => {
51
+ if (autoPlayTimer) {
52
+ clearInterval(autoPlayTimer)
53
+ autoPlayTimer = null
54
+ }
55
+ }
56
+
57
+ onMounted(() => {
58
+ startAutoPlay()
59
+ })
60
+
61
+ onUnmounted(() => {
62
+ stopAutoPlay()
63
+ })
64
+ </script>
65
+
66
+ <style scoped>
67
+ .hero-slide {
68
+ position: relative;
69
+ width: 100%;
70
+ height: 300px;
71
+ overflow: hidden;
72
+ border-radius: 12px;
73
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
74
+ }
75
+
76
+ .slide-container {
77
+ position: relative;
78
+ width: 100%;
79
+ height: 100%;
80
+ }
81
+
82
+ .slide-item {
83
+ position: absolute;
84
+ top: 0;
85
+ left: 0;
86
+ width: 100%;
87
+ height: 100%;
88
+ display: flex;
89
+ flex-direction: column;
90
+ justify-content: center;
91
+ align-items: center;
92
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
93
+ color: white;
94
+ opacity: 0;
95
+ transition: opacity 0.5s ease-in-out;
96
+ text-align: center;
97
+ padding: 20px;
98
+ box-sizing: border-box;
99
+ }
100
+
101
+ .slide-item.active {
102
+ opacity: 1;
103
+ }
104
+
105
+ .slide-item h2 {
106
+ margin: 0 0 16px 0;
107
+ font-size: 2rem;
108
+ font-weight: 600;
109
+ }
110
+
111
+ .slide-item p {
112
+ margin: 0;
113
+ font-size: 1.1rem;
114
+ opacity: 0.9;
115
+ max-width: 600px;
116
+ }
117
+
118
+ .slide-indicators {
119
+ position: absolute;
120
+ bottom: 20px;
121
+ left: 50%;
122
+ transform: translateX(-50%);
123
+ display: flex;
124
+ gap: 8px;
125
+ }
126
+
127
+ .indicator {
128
+ width: 12px;
129
+ height: 12px;
130
+ border-radius: 50%;
131
+ background: rgba(255, 255, 255, 0.5);
132
+ cursor: pointer;
133
+ transition: background 0.3s ease;
134
+ }
135
+
136
+ .indicator.active {
137
+ background: white;
138
+ }
139
+
140
+ .indicator:hover {
141
+ background: rgba(255, 255, 255, 0.8);
142
+ }
143
+ </style>
package/src/index.ts ADDED
@@ -0,0 +1,22 @@
1
+ import type { App, Plugin } from 'vue'
2
+ import ArticleList from './components/ArticleList'
3
+ import HeroSlide from './components/HeroSlide'
4
+
5
+ // 全部引入插件
6
+ export default {
7
+ install: (app: App) => {
8
+ app.component('ArticleList', ArticleList)
9
+ app.component('HeroSlide', HeroSlide)
10
+ },
11
+ } satisfies Plugin
12
+
13
+ // 按需引入 - 导出组件
14
+ export { ArticleList }
15
+ export { HeroSlide }
16
+
17
+ // 按需引入 - 导出单个组件的插件
18
+ export { default as ArticleListPlugin } from './components/ArticleList'
19
+ export { default as HeroSlidePlugin } from './components/HeroSlide'
20
+
21
+ // 导出类型定义
22
+ export type { ComponentProps, ComponentEmits, ComponentSlots } from './components/ArticleList/type'
package/src/main.ts ADDED
@@ -0,0 +1,5 @@
1
+ import { createApp } from 'vue'
2
+ import './style.css'
3
+ import App from './App.vue'
4
+
5
+ createApp(App).mount('#app')
package/src/style.css ADDED
@@ -0,0 +1,79 @@
1
+ :root {
2
+ font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
3
+ line-height: 1.5;
4
+ font-weight: 400;
5
+
6
+ color-scheme: light dark;
7
+ color: rgba(255, 255, 255, 0.87);
8
+ background-color: #242424;
9
+
10
+ font-synthesis: none;
11
+ text-rendering: optimizeLegibility;
12
+ -webkit-font-smoothing: antialiased;
13
+ -moz-osx-font-smoothing: grayscale;
14
+ }
15
+
16
+ a {
17
+ font-weight: 500;
18
+ color: #646cff;
19
+ text-decoration: inherit;
20
+ }
21
+ a:hover {
22
+ color: #535bf2;
23
+ }
24
+
25
+ body {
26
+ margin: 0;
27
+ display: flex;
28
+ place-items: center;
29
+ min-width: 320px;
30
+ min-height: 100vh;
31
+ }
32
+
33
+ h1 {
34
+ font-size: 3.2em;
35
+ line-height: 1.1;
36
+ }
37
+
38
+ button {
39
+ border-radius: 8px;
40
+ border: 1px solid transparent;
41
+ padding: 0.6em 1.2em;
42
+ font-size: 1em;
43
+ font-weight: 500;
44
+ font-family: inherit;
45
+ background-color: #1a1a1a;
46
+ cursor: pointer;
47
+ transition: border-color 0.25s;
48
+ }
49
+ button:hover {
50
+ border-color: #646cff;
51
+ }
52
+ button:focus,
53
+ button:focus-visible {
54
+ outline: 4px auto -webkit-focus-ring-color;
55
+ }
56
+
57
+ .card {
58
+ padding: 2em;
59
+ }
60
+
61
+ #app {
62
+ max-width: 1280px;
63
+ margin: 0 auto;
64
+ padding: 2rem;
65
+ text-align: center;
66
+ }
67
+
68
+ @media (prefers-color-scheme: light) {
69
+ :root {
70
+ color: #213547;
71
+ background-color: #ffffff;
72
+ }
73
+ a:hover {
74
+ color: #747bff;
75
+ }
76
+ button {
77
+ background-color: #f9f9f9;
78
+ }
79
+ }
@@ -0,0 +1 @@
1
+ /// <reference types="vite/client" />
@@ -0,0 +1,10 @@
1
+ import type { Component } from 'vue'
2
+ import type { ComponentProps, ComponentEmits, ComponentSlots } from '../src/components/ArticleList/type'
3
+
4
+ declare module 'vue' {
5
+ interface GlobalComponents {
6
+ ArticleList: Component<ComponentProps, ComponentEmits, ComponentSlots>
7
+ }
8
+ }
9
+
10
+ export {}