中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁 > news >正文

烏魯木齊經(jīng)濟(jì)開發(fā)區(qū)建設(shè)局網(wǎng)站如何創(chuàng)建自己的網(wǎng)址

烏魯木齊經(jīng)濟(jì)開發(fā)區(qū)建設(shè)局網(wǎng)站,如何創(chuàng)建自己的網(wǎng)址,水磨溝網(wǎng)頁設(shè)計(jì),網(wǎng)站免費(fèi)站基于特定的應(yīng)用場景,需要在頁面中以網(wǎng)格的方式,實(shí)現(xiàn)目標(biāo)組件在網(wǎng)格中可以進(jìn)行拖拉拽、修改大小等交互。本章開始分享如何一步步從代碼設(shè)計(jì),最后到如何在 NPM 上發(fā)布。 請大家動動小手,給我一個免費(fèi)的 Star 吧~ 大家如果發(fā)現(xiàn)了 Bug…

基于特定的應(yīng)用場景,需要在頁面中以網(wǎng)格的方式,實(shí)現(xiàn)目標(biāo)組件在網(wǎng)格中可以進(jìn)行拖拉拽、修改大小等交互。本章開始分享如何一步步從代碼設(shè)計(jì),最后到如何在 NPM 上發(fā)布。

請大家動動小手,給我一個免費(fèi)的 Star 吧~

大家如果發(fā)現(xiàn)了 Bug,歡迎來提 Issue 喲~

github源碼

示例地址

特別說明一下,此組件是基于 CSS 的 display: grid 的,并非全能型拖拉拽交互,grid 不支持的基本就是不支持的,此組件的目標(biāo)是達(dá)到一些簡易的網(wǎng)格布局拖拉拽交互。

效果圖

在這里插入圖片描述

項(xiàng)目結(jié)構(gòu)

項(xiàng)目結(jié)構(gòu)是基于另外一個項(xiàng)目 konva-designer-sample,特別說一下需要關(guān)注的部分:

└─ dist - 構(gòu)建的組件庫文件
└─ docs - 構(gòu)建的在線示例網(wǎng)站
└─ src└─ demo│   └─ App.vue - 在線示例頁面└─ lib└─ components└─ GridDragResize - 組件目錄└─ GridDragResize.vue - 組件└─ GridDragResizeItem.vue - 子組件└─ index.ts - 組件入口└─ style.less - 組件樣式└─ types.ts - 組件配套類型聲明└─ main.ts - 在線示例代碼入口
└─ index.html - 在線示例HTML入口
└─ package.json - 庫信息
└─ tsconfig.build.json - 用于構(gòu)建組件庫配套的類型聲明文件
└─ vite.config.ts - 構(gòu)建配置

使用方式

直接先看看組件的使用方式:

src/demo/App.vue

<script setup lang="ts">
import { ref, h, type Ref } from 'vue'
// 組件
import { GridDragResize } from '@/lib/components/GridDragResize'
// 組件配套類型聲明
import type { GridDragResizeProps } from '@/lib/components/GridDragResize/types'// 組件數(shù)據(jù)結(jié)構(gòu)
const children: Ref<GridDragResizeProps['children']> = ref([{dragHandler: '.demo-item>button',render: () => h('div', { class: "demo-item", style: { background: '#eb9c64' } }, [h('button', 'drag handler')])},{columnStart: 2,draggable: false,render: () => h('div', { class: "demo-item", style: { background: '#ff8789' } }, 'disable drag')},{rowStart: 2,columnStart: 2,render: () => h('div', { class: "demo-item", style: { background: '#554e4f' } }, '1')},{rowStart: 2,rowEnd: 4,columnStart: 4,columnEnd: 5,render: () => h('div', { class: "demo-item", style: { background: '#8fbf9f' } }, '2')},{rowStart: 4,rowEnd: 6,columnStart: 2,columnEnd: 4,render: () => h('div', { class: "demo-item", style: { background: '#346145' } }, '3')},{rowStart: 4,rowEnd: 5,columnStart: 1,columnEnd: 2,render: () => h('div', { class: "demo-item", style: { background: '#c2baa6' } }, '4')},
])
</script><template>
<div class="page"><!-- 組件使用 --><GridDragResize :columns="4" :rows="5" :gap="10" :row-size="100" :readonly="false" :children="children"></GridDragResize><!-- 組件數(shù)據(jù)結(jié)構(gòu) 實(shí)時狀態(tài) --><div v-html="JSON.stringify(children, null, 2).replace(/\n/g, '<br>').replace(/\s/g, '&nbsp; ')"></div>
</div>
</template><style lang="less">
// 一些樣式初始化*,
*::before,
*::after {box-sizing: border-box;margin: 0;font-weight: normal;
}body {min-height: 100vh;color: var(--color-text);background: var(--color-background);transition:color 0.5s,background-color 0.5s;line-height: 1.6;font-family:Inter,-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Fira Sans','Droid Sans','Helvetica Neue',sans-serif;font-size: 15px;text-rendering: optimizeLegibility;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;
}
</style>
<style lang="less">
// 示例樣式
.page {padding: 32px;
}.demo-item {padding: 10px;height: 100%;
}// 組件樣式覆蓋
.grid-drag-resize {background-color: #eee;.grid-drag-resize__item {background-color: #ddd;&--dragging {box-shadow: 0 0 6px 2px #0000ff;}}
}
</style>

上面可以看出,render 是比較關(guān)鍵的地方,該組件使用方式并非 插槽,而是通過數(shù)據(jù)結(jié)構(gòu)傳入的 render 實(shí)現(xiàn)每一塊的顯示的,它可以是 h 可以是一個個 其他組件。

接下來,可以看看定義:

組件 Props 定義

// src/lib/components/GridDragResize/types.tsimport type { VNode } from 'vue'// 子組件的 Props
export interface GridDragResizeItemProps {draggable?: booleandragHandler?: string // 滿足 querySelector 的查詢字符串,指向可拖拉拽的元素位置// css display grid 屬性columnStart?: numbercolumnEnd?: numberrowStart?: numberrowEnd?: number//render?: () => VNode
}// 組件的 Props
export interface GridDragResizeProps {dragHandler?: string // 同上,優(yōu)先級 低于 子組件readonly?: boolean // 優(yōu)先級 低于 子組件 的 draggable//columns?: number // 列數(shù)rows?: number // 行數(shù)gap?: number // 間隙columnSize?: number // 列寬,默認(rèn)是 1frrowSize?: number // 行高,默認(rèn)是 1fr//children?: GridDragResizeItemProps[] // 子組件
}

目前為止,定義非常簡單。

組件

src/lib/components/GridDragResize/GridDragResize.vue
邏輯說明,請留意代碼注釋

<script setup lang="ts">
import { ref, computed, provide, type Ref } from 'vue'import type { GridDragResizeProps, GridDragResizeItemProps } from './types'import GridDragResizeItem from './GridDragResizeItem.vue'const props = withDefaults(defineProps<GridDragResizeProps>(), {children: () => []
});const style = computed(() => {return {'grid-template-columns': Number.isInteger(props.columns) ? `repeat(${props.columns},${Number.isInteger(props.columnSize) ? `${props.columnSize}px` : '1fr'})` : '','grid-template-rows': Number.isInteger(props.rows) ? `repeat(${props.rows},${Number.isInteger(props.rowSize) ? `${props.rowSize}px` : '1fr'})` : '','grid-gap': Number.isInteger(props.gap) ? `${props.gap}px ${props.gap}px` : ''}
})const rootEle: Ref<HTMLElement | undefined> = ref()// 給子組件穿透轉(zhuǎn)遞組件 Props
provide('parentProps', props)// 組件位置、大小信息
const rootRect = computed(() => {return rootEle?.value?.getBoundingClientRect() ?? {height: 0,width: 0,x: 0,y: 0,bottom: 0,right: 0}
})// 列寬
const columnSize = computed(() => {return (rootRect.value.width - (props.gap ?? 0) * ((props.columns ?? 1) - 1)) / (props.columns ?? 1)
})// 行高
const rowSize = computed(() => {return (rootRect.value.height - (props.gap ?? 0) * ((props.rows ?? 1) - 1)) / (props.rows ?? 1)
})// 根據(jù)鼠標(biāo)拖動偏移量,計(jì)算列/行方向上,移動后最新的位置和大小
function calcStartEnd(opts: { size: number, gap: number, span: number, max: number, offset: number, startBefore: number }) {let { size, gap, span, max, offset, startBefore } = optslet offsetStart = Math.round(offset / (size + gap))let start = startBefore + offsetStartif (start < 1) {start = 1}if (start + span > max) {start = max - span + 1}return {start,end: start + span}
}// 當(dāng)前拖動小組件的數(shù)據(jù)項(xiàng)
const draggingChild: Ref<GridDragResizeItemProps | undefined> = ref()
// 當(dāng)前拖動小組件的數(shù)據(jù)項(xiàng)(初始狀態(tài))
const draggingChildBefore: Ref<GridDragResizeItemProps | undefined> = ref()
// 當(dāng)前拖動小組件的位置、大小信息
const draggingChildRect: Ref<DOMRect | undefined> = ref()// 拖動開始位置
let dragStartClientX = 0, dragStartClientY = 0;// 拖動偏移量
let dragOffsetClientX = 0, dragOffsetClientY = 0;let dragging = false// 開始拖動
function dragstart(e: MouseEvent) {if (!props.readonly) {dragging = true// 記錄 拖動開始位置dragStartClientX = e.clientXdragStartClientY = e.clientY}
}// 拖動中
function drag(e: MouseEvent) {if (dragging && draggingChild.value && draggingChildRect.value) {// 計(jì)算 拖動開始位置dragOffsetClientX = e.clientX - dragStartClientXdragOffsetClientY = e.clientY - dragStartClientY// 當(dāng)前拖動小組件的 grid 大小let rowSpan = (draggingChild.value.rowEnd ?? draggingChild.value.rowStart ?? 1) - (draggingChild.value.rowStart ?? 1)let columnSpan = (draggingChild.value.columnEnd ?? draggingChild.value.columnStart ?? 1) - (draggingChild.value.columnStart ?? 1)// 邊界處理if (rowSpan <= 0) {rowSpan = 1}if (columnSpan <= 0) {columnSpan = 1}// 計(jì)算行方向上,移動后最新的位置和大小let { start: rowStart, end: rowEnd } = calcStartEnd({size: rowSize.value, gap: (props.gap ?? 0), span: rowSpan, max: props.rows ?? 1, offset: dragOffsetClientY, startBefore: draggingChildBefore.value?.rowStart ?? 1})// 計(jì)算列方向上,移動后最新的位置和大小let { start: columnStart, end: columnEnd } = calcStartEnd({size: columnSize.value, gap: (props.gap ?? 0), span: columnSpan, max: props.columns ?? 1, offset: dragOffsetClientX, startBefore: draggingChildBefore.value?.columnStart ?? 1})// 當(dāng)前拖動小組件的數(shù)據(jù)項(xiàng)draggingChild.value.columnStart = columnStartdraggingChild.value.columnEnd = columnEnddraggingChild.value.rowStart = rowStartdraggingChild.value.rowEnd = rowEnd}
}// 拖動結(jié)束
function dragend(e: MouseEvent) {e.stopPropagation()dragging = falsedraggingChild.value = undefined
}// 超出組件區(qū)域,補(bǔ)充結(jié)束事件
document.body.addEventListener('mouseup', dragend)
</script><template>
<div class="grid-drag-resize" :style="style" @mousedown="dragstart" @mousemove="drag" @mouseup="dragend" ref="rootEle"><template v-for="(child, idx) of props.children" :key="idx"><GridDragResizeItem v-bind="child" v-model:column-start="child.columnStart" v-model:column-end="child.columnEnd"v-model:row-start="child.rowStart" v-model:row-end="child.rowEnd"@dragging="(rect) => { draggingChild = child; draggingChildBefore = { ...child }; draggingChildRect = rect }":style="{ 'zIndex': draggingChild === child ? props.children.length + 1 : idx + 1 }":class="{ 'grid-drag-resize__item--dragging': draggingChild === child }"><component :is="child.render"></component></GridDragResizeItem></template>
</div>
</template>

子組件

src/lib/components/GridDragResize/GridDragResizeItem.vue
邏輯說明,請留意代碼注釋

<script setup lang="ts">
import { ref, computed, watchEffect, inject, type Ref } from 'vue'import type { GridDragResizeProps, GridDragResizeItemProps } from './types'const parentProps = inject<GridDragResizeProps>('parentProps')const props = withDefaults(defineProps<GridDragResizeItemProps>(), {draggable: true
});const emit = defineEmits(['update:columnStart', 'update:columnEnd', 'update:rowStart', 'update:rowEnd', 'dragging'])// 數(shù)據(jù)整理
watchEffect(() => {if (props.columnStart !== void 0) {if (props.columnEnd === void 0 || props.columnEnd < props.columnStart) {emit('update:columnEnd', props.columnStart + 1)}} else {emit('update:columnStart', 1)}if (props.rowStart !== void 0) {if (props.rowEnd === void 0 || props.rowEnd < props.rowStart) {emit('update:rowEnd', props.rowStart + 1)}} else {emit('update:rowStart', 1)}
})// 樣式
const style = computed(() => {return {'grid-column-start': props.columnStart,'grid-column-end': props.columnEnd,'grid-row-start': props.rowStart,'grid-row-end': props.rowEnd,}
})const itemEle: Ref<HTMLElement | undefined> = ref()const dragHandlerParsed = computed(() => props.dragHandler ?? parentProps?.dragHandler)
const draggableParsed = computed(() => parentProps?.readonly ? false : props.draggable)// dragHandler 定位、處理、事件綁定
watchEffect(() => {if (draggableParsed.value && dragHandlerParsed.value && itemEle.value) {const handlerEle = itemEle.value.querySelector(dragHandlerParsed.value)if (handlerEle instanceof HTMLElement) {handlerEle.style.cursor = 'grab'handlerEle.addEventListener('mousedown', dragstart)}}
})// 拖動開始
function dragstart() {if (draggableParsed.value) {// 通知父組件 當(dāng)前拖動小組件emit('dragging', itemEle?.value?.getBoundingClientRect() ?? {height: 0,width: 0,x: 0,y: 0,bottom: 0,right: 0})}
}
</script><template>
<div class="grid-drag-resize__item" :class="{'grid-drag-resize__item--draggable': draggableParsed,'grid-drag-resize__item--draggable-full': draggableParsed && dragHandlerParsed === void 0
}" :style="style" @mousedown="() => dragHandlerParsed ? undefined : dragstart()" ref="itemEle"><slot></slot>
</div>
</template>

樣式

.grid-drag-resize {display: grid;.grid-drag-resize__item {&--draggable-full {cursor: grab;user-select: none;}&--dragging {opacity: 0.6;}}
}

組件入口

// src/lib/components/GridDragResize/index.ts
import GridDragResize from './GridDragResize.vue'
import GridDragResizeItem from './GridDragResizeItem.vue'import './style.less'export * from './types'export { GridDragResize, GridDragResizeItem }

Thanks watching~

下一章,我們說說如何構(gòu)建在線示例、組件庫,及其如何發(fā)布到 NPM 上供開源使用!

More Stars please!勾勾手指~

github源碼

示例地址

http://www.risenshineclean.com/news/49431.html

相關(guān)文章:

  • 有個藍(lán)色章魚做標(biāo)志的網(wǎng)站seo和sem的聯(lián)系
  • 蘇寧易購網(wǎng)站建設(shè)的目的競價關(guān)鍵詞排名軟件
  • 大連網(wǎng)站制作師企業(yè)微信scrm
  • Wordpress搜索指定頁面內(nèi)容seo網(wǎng)絡(luò)優(yōu)化推廣
  • 廣東省東莞陽光網(wǎng)seo推廣優(yōu)化外包價格
  • 網(wǎng)站如何做搜索功能的網(wǎng)絡(luò)推廣的途徑有哪些
  • 簡單制作網(wǎng)站的過程網(wǎng)站推廣軟件哪個最好
  • 騰訊微博 wordpressseo搜索引擎優(yōu)化視頻
  • wordpress 通知中心文章優(yōu)化關(guān)鍵詞排名
  • 外國英文設(shè)計(jì)網(wǎng)站搜多多搜索引擎入口
  • 學(xué)校網(wǎng)站建設(shè)計(jì)劃書什么叫網(wǎng)絡(luò)營銷
  • 網(wǎng)站正在建設(shè)中卡通源碼百度關(guān)鍵詞推廣教程
  • 答題網(wǎng)站怎么做小說網(wǎng)站排名前十
  • 免備案cdn保定關(guān)鍵詞優(yōu)化軟件
  • 重慶的汽車網(wǎng)站建設(shè)2022最新熱點(diǎn)事件及點(diǎn)評
  • 網(wǎng)頁游戲傳奇霸業(yè)seo網(wǎng)站推廣下載
  • 偷拍哪個網(wǎng)站做的好新聞營銷發(fā)稿平臺
  • 鄭州哪家公司做網(wǎng)站好關(guān)鍵詞com
  • wordpress禁止用戶儀表盤網(wǎng)站seo方法
  • 南京h5 網(wǎng)站建設(shè)展示型網(wǎng)站設(shè)計(jì)公司
  • 響應(yīng)式網(wǎng)站用什么做項(xiàng)鏈seo關(guān)鍵詞
  • 邯鄲做網(wǎng)站公司哪家好seo崗位工資
  • 手機(jī)網(wǎng)站靜態(tài)動態(tài)關(guān)鍵詞全網(wǎng)搜索
  • 東莞做網(wǎng)站的公司個人代運(yùn)營一般怎么收費(fèi)
  • 北京網(wǎng)站建設(shè)網(wǎng)絡(luò)公司百度競價調(diào)價軟件
  • 廣州建設(shè)銀行招聘網(wǎng)站百度查看訂單
  • 汽修行業(yè)做環(huán)評網(wǎng)站刷神馬seo排名首頁排名
  • 設(shè)計(jì)頁面導(dǎo)航一鍵seo提交收錄
  • 個人可以做慈善網(wǎng)站嗎今日熱點(diǎn)頭條新聞
  • 東莞做網(wǎng)站優(yōu)化哪家好北京seo專業(yè)團(tuán)隊(duì)