需求:封装一个函数要求监听DOM的宽高变化,并且支持自定义指令和hooks两种用法。
1.在v-resize-xm文件夹里面创建src文件夹
执行 pnpm init 命令 生成一个package.json文件
2.安装一下ts
sudo npm install -g typescript
3.执行 tsc --init生成一个 tsconfig.json 文件
4.在v-resize-xm文件夹下新建一个vite.config.ts文件
5.在v-resize-xm文件夹下新建一个index.d.ts声明文件
6.安装vue, 执行 pnpm install vue@3.2.47 -D (因为最终使用这个插件的用户他本地有vue)
7.安装vite, 执行 pnpm install vite@4.2.1 -D (因为最终使用这个插件的用户他本地有vite)
编写v-resize-xm\src\index.ts业务文件
- import type { App } from 'vue';
- // 侦听元素宽高的变化
- // Hooks
- function useResize (el:HTMLElement, callback:Function) {
- let resize = new ResizeObserver((entries) => {
- // entries 是数组, 默认监听多个
- callback(entries[0].contentRect); // 将框高回传回去
- })
- resize.observe(el)
- }
-
- let app = createApp(); // 创建一个app出来
-
- // vue插件使用如
- // app.use(router).use(xxx); // 等
- // 这个use实际上就是调用了底层的一个install方法
- // vue插件就是要去实现install函数, 他就要就调用, 并且将这个app注入进去, 它的类型就是vue里面引入的App
-
- // 自定义指令
- const install = (app:App) => { // 最终给app提供一个install方法
- // 拿到这个app之后就可以去创建directive指令了
- app.directive('resize', {
- // 第一个参数是html元素, 第二个参数是binding对象,这个对象可以要求它传入一个函数
- mounted(el, binding) {
- // 刚好复用一下useResize
- // 指令的挂载
- useResize(el, binding.value);
- }
- })
- }
- // 将 install 注册到函数上面
- useResize.install = install;
-
- export default useResize;
- import { defineConfig } from 'vite';
- // umd 支持amd cmd cjs 全局变量模式
- export default defineConfig({
- // 开发vue3库模式文档 https://cn.vitejs.dev/guide/build.html#library-mode
- build:{
- lib:{
- entry:'./src/index.ts', // 入口
- name: 'useResize' // name和hooks名称一样就可以了
- },
- // 透传一些属性给rollup
- rollupOptions:{
- // 因为这是vue插件,用户本地已经有Vue环境了,此处Vue没必要打到包里面
- external:['vue'],
- output:{
- globals:{
- useResize: 'useResize' // 提供一个全局变量给umd库用
- }
- }
- }
- }
- })
"build": "vite build"
- {
- "name": "v-resize-xm",
- "version": "1.0.0",
- "description": "",
- "main": "index.js",
- "scripts": {
- "test": "echo \"Error: no test specified\" && exit 1",
- "build": "vite build"
- },
- "keywords": [],
- "author": "",
- "license": "ISC",
- "devDependencies": {
- "vue": "3.2.47"
- }
- }
我们看到dist目录打出来两个文件
v-resize-xm.mjs ES模式
v-resize-xm.umd.js 其他模式
- declare const useResize: {
- (el: HTMLElement, callback: Function): void;
- install: (app: App) => void;
- };
-
- export default useResize;
"main": "dist/v-resize-xm.umd.js", umd它是支持commonJs规范的
"module": "dist/v-resize-xm.mjs",
这里表示发往npm的目录,我们将dist目录和声明文件发上去
"files": [ "dist", "index.d.ts"],
"version": "1.0.1",
- {
- "name": "v-resize-xm",
- "version": "1.0.0",
- "description": "",
- "main": "dist/v-resize-xm.umd.js",
- "module": "dist/v-resize-xm.mjs",
- "scripts": {
- "test": "echo \"Error: no test specified\" && exit 1",
- "build": "vite build"
- },
- "keywords": [],
- "author": "",
- "files": [ "dist", "index.d.ts"],
- "license": "ISC",
- "devDependencies": {
- "vue": "3.2.47"
- }
- }
1. 在vue3 项目环境下执行 pnpm install 库名称 -S
- <div id="resize">
- <img id="img" width="300" height="300" src="./assets/1.png">
- div>
- template>
- <script setup lang="ts">
- import userResize from 'v-resize-xm';
- import { onMounted } from 'vue';
- // 因为这是操作DOM的 所以我们要等页面渲染完成在 onMounted 生命周期里面操作
- onMounted(() => {
- userResize(document.querySelector('#resize') as HTMLElement,
- (e: any) => {
- console.log(e) // 获取元素长宽的变化
- }
- )
- })
- script>
- <style scoped>
- #resize {
- border: 1px solid #ccc;
- resize: both;
- overflow: hidden;
- }
- style>
在main.ts中引入并注册指令
- import './assets/main.css'
-
- import { createApp } from 'vue'
- import { createPinia } from 'pinia'
- import App from './App.vue'
- import router from './router'
-
- import useResize from 'v-resize-xm'; // 1、引入我们发布的指令插件
-
- const app = createApp(App)
-
- app.use(createPinia())
- app.use(router)
- app.use(useResize) // 2、注册指令
- app.mount('#app')
在页面中使用v-resize="drag"指令和回调函数
- <div v-resize="drag" id="resize">
- <img id="img" width="300" height="300" src="./assets/1.png">
- div>
- template>
- <script setup lang="ts">
- // import userResize from 'v-resize-xm';
- import { onMounted } from 'vue';
- const drag = (e: any) => {
- console.log(e) // 获取元素长宽变化
- }
- script>
- <style scoped>
- #resize {
- border: 1px solid #ccc;
- resize: both;
- overflow: hidden;
- }
- style>