Angular.js 实现带手柄自由调整页面大小的功能

因为目前是处于在angular项目中,所以下面分别一个记录简易的angular.js和在angular项目中使用的版本,仅供大家参考。

Angular.js

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Resizable Element with Angular Directive</title>
  <style>
    .resizable {
      width: 200px;
      height: 200px;
      background-color: lightgray;
      border: 1px solid #ccc;
      overflow: auto;
      position: relative;
    }
    .resize-handle {
      width: 10px;
      height: 10px;
      background-color: #000;
      position: absolute;
      bottom: 0;
      right: 0;
      cursor: nwse-resize;
    }
  </style>
</head>
<body>
  <div ng-app="resizableApp">
    <div ng-controller="ResizableController">
      <div resizable></div>
    </div>
  </div>

  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.2/angular.min.js"></script>
  <script>
    angular.module('resizableApp', [])
      .controller('ResizableController', function($scope) {
        // 可以在这里添加控制器逻辑
      })
      .directive('resizable', function() {
        return {
          restrict: 'A',
          link: function(scope, element) {
            const resizableElement = element[0];
            const resizeHandle = document.createElement('div');
            resizeHandle.classList.add('resize-handle');
            resizableElement.appendChild(resizeHandle);

            let isResizing = false;
            let initialX;
            let initialY;
            let originalWidth;
            let originalHeight;

            resizeHandle.addEventListener('mousedown', function(event) {
              event.preventDefault();
              isResizing = true;
              initialX = event.clientX;
              initialY = event.clientY;
              originalWidth = parseFloat(getComputedStyle(resizableElement, null).getPropertyValue('width'));
              originalHeight = parseFloat(getComputedStyle(resizableElement, null).getPropertyValue('height'));

              document.addEventListener('mousemove', resize);
              document.addEventListener('mouseup', stopResize);
            });

            function resize(event) {
              if (isResizing) {
                const width = originalWidth + (event.clientX - initialX);
                const height = originalHeight + (event.clientY - initialY);
                resizableElement.style.width = width + 'px';
                resizableElement.style.height = height + 'px';
              }
            }

            function stopResize() {
              isResizing = false;
              document.removeEventListener('mousemove', resize);
              document.removeEventListener('mouseup', stopResize);
            }
          }
        };
      });
  </script>
</body>
</html>

在Angular项目中

在 Angular 项目中可以将上述功能作为 Angular 指令在组件中使用。

  1. 首先,创建一个名为 resizable 的自定义指令

    javascript 复制代码
    import { Directive, ElementRef, HostListener } from '@angular/core';
    
    @Directive({
      selector: '[resizable]'
    })
    
    export class ResizeDirective {
      private isResizing: boolean = false;
      private isRightResizing: boolean = false;
      private isBottomResizing: boolean = false;
      private startX: number = 0;
      private startY: number= 0;
      private startWidth: number= 0;
      private startHeight: number= 0;
      private handle: HTMLElement;
    
      constructor(private elementRef: ElementRef,private rendere:Renderer2) {
        this.handle = document.createElement('div');
        this.rendere.addClass(this.handle,'resize-handle');
        this.rendere.appendChild(this.elementRef.nativeElement,this.handle)
      }
    
      @HostListener('document:mousemove', ['$event'])
      onMouseMove(event: MouseEvent) {
        event.stopPropagation();
        if (this.isResizing) {
          this.rendere.setStyle(document.body,'cursor','ne-size');
          this.rendere.setStyle(this.elementRef.nativeElement,'cursor','ne-size');
          const dx = event.clientX - this.startX;
          const dy = event.clientY - this.startY;
          const newWidth = this.startWidth + dx;
          const newHeight = this.startHeight + dy;
          this.elementRef.nativeElement.style.width = newWidth + 'px';
          this.elementRef.nativeElement.style.height = newHeight + 'px';
        }
    
        if (this.isBottomResizing) {
          this.rendere.setStyle(document.body,'cursor','ns-size');
          const dy = event.clientY - this.startY;
          const newHeight = this.startHeight + dy;
          this.elementRef.nativeElement.style.height = newHeight + 'px';
        }
    
        if (this.isRightResizing) {
          this.rendere.setStyle(document.body,'cursor','ew-size');
          const dx = event.clientX - this.startX;
          const newWidth = this.startWidth + dx;
          this.elementRef.nativeElement.style.width = newWidth + 'px';
        }
      }
    
      @HostListener('mousedown', ['$event'])
      onMouseDown(event: MouseEvent) {
        event.stopPropagation();
        const rect = this.elementRef.nativeElement.getBoundingClientRect();
        const borderWidth = 10;
        const isOnRightBorder = event.clientX >= rect.right - borderWidth && event.clientX >= rect.right + borderWidth;
        const isOnBottomBorder = event.clientY >= rect.bottom - borderWidth && event.clientY >= rect.bottom + borderWidth;
        if (event.target === this.handle) {
          this.isResizing = true;
          this.isBottomResizing = false;
          this.isRightResizing = false;
          this.startX = event.clientX;
          this.startY = event.clientY;
          this.startWidth = this.elementRef.nativeElement.clientWidth;
          this.startHeight = this.elementRef.nativeElement.clientHeight;
          this.rendere.setStyle(document.body,'cursor','ne-size');
          this.rendere.setStyle(this.elementRef.nativeElement,'cursor','ne-size');
          event.preventDefault();
        }else if(isOnBottomBorder) {
          this.isResizing = false;
          this.isBottomResizing = true;
          this.isRightResizing = false;
          this.startY = event.clientY;
          this.startHeight = this.elementRef.nativeElement.clientHeight;
          this.rendere.setStyle(document.body,'cursor','ns-size');
          event.preventDefault();
        }else if(isOnRightBorder) {
          this.isResizing = true;
          this.isBottomResizing = false;
          this.isRightResizing = true;
          this.startX = event.clientX;
          this.startWidth = this.elementRef.nativeElement.clientWidth;
          this.rendere.setStyle(document.body,'cursor','ew-size');
          event.preventDefault();
        }
      }
    
      @HostListener('document:mouseup')
      onMouseUp() {
        this.isResizing = false;
        this.isBottomResizing = false;
        this.isRightResizing = false;
        this.rendere.setStyle(document.body,'cursor','auto');
        this.rendere.setStyle(this.elementRef.nativeElement,'cursor','auto');
      }
    }
  2. 在组件模板中使用该指令

    html 复制代码
    <div resizable class="resizable"></div>
  3. 最后,将 `ResizableDirective` 添加到您的 Angular 模块中

    javascript 复制代码
    import { NgModule } from '@angular/core';
    import { BrowserModule } from '@angular/platform-browser';
    import { ResizableDirective } from './resizable.directive';
    import { AppComponent } from './app.component';
    
    @NgModule({
      declarations: [
        AppComponent,
        ResizableDirective
      ],
      imports: [
        BrowserModule
      ],
      providers: [],
      bootstrap: [AppComponent]
    })
    export class AppModule { }

Angular项目中的注意事项:

  • 例子中是左基线为标准的代码(即仅横向宽度改变时,整个页面是向左缩进靠齐的),如果想改成右基线为标准进行缩进的代码,可参考下面的关键代码,其他代码不需改动(只写了需要改动的代码,其它代码完全不需改动):
javascript 复制代码
@HostListener('document:mousemove', ['$event'])
  onMouseMove(event: MouseEvent) {
    event.stopPropagation();
    if (this.isResizing) {
      const newWidth = this.startWidth - dx;
    }

    if (this.isRightResizing) {
      const newWidth = this.startWidth - dx;
    }
  }
  • event.preventDefault()这个方法的位置的使用,不可改动,不然页面的默认行为将会被阻止,比如默认选中等。
  • event.stopPropagation()不可删掉,不然在当有子组件的时候,会因为冒泡导致样式受到影响。
相关推荐
mldong4 小时前
你的 Vue3 项目也能有钉钉同款审批流设计器:npm 装包,10 分钟画出第一条审批流
前端·vue.js
2分钟速写快排5 小时前
什么是 RAG?如何用 RAG 实现一个用户记忆?
前端·后端·ai编程
passerby60615 小时前
如何自己造一个时间处理库
前端·javascript·github
走到天涯海角6 小时前
react里面的长列表渲染优化
前端·react.js·前端框架
小羊没烦恼!6 小时前
Hello Web API系列教程——Web API与国际化
java·服务器·前端·javascript·php
北岛贰7 小时前
迷茫焦虑期,我做了一个带支付带官网的 AI 聊天虚拟恋人 App
前端·人工智能·后端
mayaairi8 小时前
Vue2 组件通讯(三):全局事件总线、PubSub、插槽与组件实例属性
前端·javascript·vue.js
kyriewen9 小时前
面试官问我:AI 都能写代码了,前端凭什么还值 25K
前端·javascript·人工智能
风骏时光牛马9 小时前
AI源码分析:拆解模型底层实现逻辑
前端
BillKu10 小时前
全局样式变量:CSS 自定义属性(--border-color)和SCSS 变量($border-color)的说明
javascript·css·scss