国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

首頁 web前端 js教程 使用Vue移動端如何實(shí)現(xiàn)圖片裁剪組件

使用Vue移動端如何實(shí)現(xiàn)圖片裁剪組件

Jun 23, 2018 pm 06:06 PM
vue

這篇文章給大家介紹了基于Vue的移動端圖片裁剪組件功能,因?yàn)橐苿佣耸怯胿ue,所以就寫成了一個vue組件,下面就說說自己的一些實(shí)現(xiàn)思路,需要的朋友可以參考下

最近項(xiàng)目上要做一個車牌識別的功能。本來以為很簡單,只需要將圖片扔給后臺就可以了,但是經(jīng)測試后識別率只有20-40%。因此產(chǎn)品建議拍攝圖片后,可以對圖片進(jìn)行拖拽和縮放,然后裁剪車牌部分上傳給后臺來提高識別率。剛開始的話還是百度了一下看看有沒有現(xiàn)成的組件,但是找來找去都沒有找到一個合適的,還好這個功能不是很著急,因此自己周末就在家里研究一下。

  Demo地址:https://vivialex.github.io/demo/imageClipper/index.html

  下載地址:https://github.com/vivialex/vue-imageClipper

  因?yàn)橐苿佣耸怯胿ue,所以就寫成了一個vue組件,下面就說說自己的一些實(shí)現(xiàn)思路(本人技術(shù)有限,各位大神請體諒。另外展示的代碼不一定是某個功能的完整代碼),先看看效果: 

 ?

  一、組件的初始化參數(shù)

  1、圖片img(url或者base64 data-url)

  2、截圖的寬clipperImgWidth

  3、截圖的高clipperImgHeight

props: {
  img: String, //url或dataUrl
  clipperImgWidth: {
    type: Number,
    default: 500
  },
  clipperImgHeight: {
    type: Number,
    default: 200
  }
}

  二、布局

  在Z軸方向看主要是由4層組成。第1層是一個占滿整個容器的canvas(稱cCanvas);第2層是一個有透明度的遮罩層;第3層是裁剪的區(qū)域(示例圖中的白色方框),里面包含一個與裁剪區(qū)域大小相等的canvas(稱pCanvas);第4層是一個透明層gesture-mask,用作綁定touchstart,touchmove,touchend事件。其中兩個canvas都會加載同一張圖片,只是起始坐標(biāo)不一樣。為什么需要兩個canvas?因?yàn)橄胱龀霎?dāng)手指離開屏幕時,裁剪區(qū)域外的部分表面會有一個遮罩層的效果,這樣能突出裁剪區(qū)域的內(nèi)容。

<p class="cut-container" ref="cut">
  <canvas ref="canvas"></canvas>
  <!-- 裁剪部分 -->
  <p class="cut-part">
    <p class="pCanvas-container">
      <canvas ref="pCanvas"></canvas>
    </p>
  </p>
  <!-- 底部操作欄 -->
  <p class="action-bar">
    <button class="btn-cancel" @click="_cancel">取消</button>
    <button class="btn-ok" @click="_cut">確認(rèn)</button>
  </p>
  <!-- 背景遮罩 -->
  <p class="mask" :class="{opacity: maskShow}"></p>
  <!-- 手勢操作層 -->
  <p class="gesture-mask" ref="gesture"></p>
</p>

  三、初始化canvas

  canvas繪制的圖片在hdpi顯示屏上會出現(xiàn)模糊,具體原因這里不作分析,可以參考下這里。我這里的做法是讓canvas的width與height為其css width/height的devicePixelRatio倍,以及調(diào)用canvas api時所傳入的參數(shù)都要乘以window.devicePixelRatio。最后還要記錄一下兩個canvas坐標(biāo)原點(diǎn)的x, y差值(originXDiff與originYDiff)。如下

_ratio(size) {
  return parseInt(window.devicePixelRatio * size);
},
_initCanvas() {
  let $canvas = this.$refs.canvas,
    $pCanvas = this.$refs.pCanvas,
    clipperClientRect = this.$refs.clipper.getBoundingClientRect(),
    clipperWidth = parseInt(this.clipperImgWidth / window.devicePixelRatio),
    clipperHeight = parseInt(this.clipperImgHeight / window.devicePixelRatio);

  this.ctx = $canvas.getContext(&#39;2d&#39;);
  this.pCtx = $pCanvas.getContext(&#39;2d&#39;);

  //判斷clipperWidth與clipperHeight有沒有超過容器值
  if (clipperWidth < 0 || clipperWidth > clipperClientRect.width) {
    clipperWidth = 250
  }

  if (clipperHeight < 0 || clipperHeight > clipperClientRect.height) {
    clipperHeight = 100
  }

  //因?yàn)閏anvas在手機(jī)上會被放大,因此里面的內(nèi)容會模糊,這里根據(jù)手機(jī)的devicePixelRatio來放大canvas,然后再通過設(shè)置css來收縮,因此關(guān)于canvas的所有值或坐標(biāo)都要乘以devicePixelRatio
  $canvas.style.width = clipperClientRect.width + &#39;px&#39;;
  $canvas.style.height = clipperClientRect.height + &#39;px&#39;;
  $canvas.width = this._ratio(clipperClientRect.width);
  $canvas.height = this._ratio(clipperClientRect.height);

  $pCanvas.style.width = clipperWidth + &#39;px&#39;;
  $pCanvas.style.height = clipperHeight + &#39;px&#39;;
  $pCanvas.width = this._ratio(clipperWidth);
  $pCanvas.height = this._ratio(clipperHeight);

  //計算兩個canvas原點(diǎn)的x y差值
  let cClientRect = $canvas.getBoundingClientRect(),
    pClientRect = $pCanvas.getBoundingClientRect();

  this.originXDiff = pClientRect.left - cClientRect.left;
  this.originYDiff = pClientRect.top - cClientRect.top;
  this.cWidth = cClientRect.width;
  this.cHeight = cClientRect.height;
}

  四、加載圖片

  加載圖片比較簡單,首先是創(chuàng)建一個Image對象并監(jiān)聽器onload事件(因?yàn)榧虞d的圖片有可能是跨域的,因此要設(shè)置其crossOrigin屬性為Anonymous,然后服務(wù)器上要設(shè)置Access-Control-Allow-Origin響應(yīng)頭)。加載的圖片如果寬高大于容器的寬高,要對其進(jìn)行縮小處理。最后垂直水平居中顯示()(這里注意的是要保存圖片繪制前的寬高值,因?yàn)槿蘸罂s放圖片是以該值為基礎(chǔ)再乘以縮放倍率,這里取imgStartWidth,imgStartHeight)如下

_loadImg() {
  if (this.imgLoading || this.loadImgQueue.length === 0) {
    return;
  }
  let img = this.loadImgQueue.shift();
  if (!img) {
    return;
  }
  let $img = new Image(),
    onLoad = e => {
      $img.removeEventListener(&#39;load&#39;, onLoad, false);
      this.$img = $img;
      this.imgLoaded = true;
      this.imgLoading = false;
      this._initImg($img.width, $img.height);
      this.$emit(&#39;loadSuccess&#39;, e);
      this.$emit(&#39;loadComplete&#39;, e);
      this._loadImg();
    },
    onError = e => {
      $img.removeEventListener(&#39;error&#39;, onError, false);
      this.$img = $img = null;
      this.imgLoading = false;
      this.$emit(&#39;loadError&#39;, e);
      this.$emit(&#39;loadComplete&#39;, e);
      this._loadImg();
    };
  this.$emit(&#39;beforeLoad&#39;);
  this.imgLoading = true;
  this.imgLoaded = false;
  $img.src = this.img;
  $img.crossOrigin = &#39;Anonymous&#39;; //因?yàn)閏anvas toDataUrl不能操作未經(jīng)允許的跨域圖片,這需要服務(wù)器設(shè)置Access-Control-Allow-Origin頭
  $img.addEventListener(&#39;load&#39;, onLoad, false);
  $img.addEventListener(&#39;error&#39;, onError, false);
}
_initImg(w, h) {
  let eW = null,
    eH = null,
    maxW = this.cWidth,
    maxH = this.cHeight - this.actionBarHeight;
  //如果圖片的寬高都少于容器的寬高,則不做處理
  if (w <= maxW && h <= maxH) {
    eW = w;
    eH = h;
  } else if (w > maxW && h <= maxH) {
    eW = maxW;
    eH = parseInt(h / w * maxW);
  } else if (w <= maxW && h > maxH) {
    eW = parseInt(w / h * maxH);
    eH = maxH;
  } else {
    //判斷是橫圖還是豎圖
    if (h > w) {
      eW = parseInt(w / h * maxH);
      eH = maxH;
    } else {
      eW = maxW;
      eH = parseInt(h / w * maxW);
    }
  }
  if (eW <= maxW && eH <= maxH) {
    //記錄其初始化的寬高,日后的縮放功能以此值為基礎(chǔ)
    this.imgStartWidth = eW;
    this.imgStartHeight = eH;
    this._drawImage((maxW - eW) / 2, (maxH - eH) / 2, eW, eH);
  } else {
    this._initImg(eW, eH);
  }
}

   五、繪制圖片

  下面的_drawImage有四個參數(shù),分別是圖片對應(yīng)cCanvas的x,y坐標(biāo)以及圖片目前的寬高w,h。函數(shù)首先會清空兩個canvas的內(nèi)容,方法是重新設(shè)置canvas的寬高。然后更新組件實(shí)例中對應(yīng)的值,最后再調(diào)用兩個canvas的drawImage去繪制圖片。對于pCanvas來說,其繪制的圖片坐標(biāo)值為x,y減去對應(yīng)的originXDiff與originYDiff(其實(shí)相當(dāng)于切換坐標(biāo)系顯示而已,因此只需要減去兩個坐標(biāo)系原點(diǎn)的x,y差值即可)。看看代碼

_drawImage(x, y, w, h) {
  this._clearCanvas();
  this.imgX = parseInt(x);
  this.imgY = parseInt(y);
  this.imgCurrentWidth = parseInt(w);
  this.imgCurrentHeight = parseInt(h);
  //更新canvas
  this.ctx.drawImage(this.$img, this._ratio(x), this._ratio(y), this._ratio(w), this._ratio(h));
  //更新pCanvas,只需要減去兩個canvas坐標(biāo)原點(diǎn)對應(yīng)的差值即可
  this.pCtx.drawImage(this.$img, this._ratio(x - this.originXDiff), this._ratio(y - this.originYDiff), this._ratio(w), this._ratio(h));
},
_clearCanvas() {
  let $canvas = this.$refs.canvas,
    $pCanvas = this.$refs.pCanvas;
  $canvas.width = $canvas.width;
  $canvas.height = $canvas.height;
  $pCanvas.width = $pCanvas.width;
  $pCanvas.height = $pCanvas.height;
}

   六、移動圖片

  移動圖片實(shí)現(xiàn)非常簡單,首先給gesture-mask綁定touchstart,touchmove,touchend事件,下面分別介紹這三個事件的內(nèi)容

  首先定義四個變量scx, scy(手指的起始坐標(biāo)),iX,iY(圖片目前的坐標(biāo),相對于cCanvas)。

  1、touchstart

    方法很簡單,就是獲取touches[0]的pageX,pageY來更新scx與scy以及更新iX與iY

  2、touchmove

    獲取touches[0]的pageX,聲明變量f1x存放,移動后的x坐標(biāo)等于iX + f1x - scx,y坐標(biāo)同理,最后調(diào)用_drawImage來更新圖片。

  看看代碼吧

_initEvent() {
  let $gesture = this.$refs.gesture,
    scx = 0,
    scy = 0;
  let iX = this.imgX,
    iY = this.imgY;
  $gesture.addEventListener(&#39;touchstart&#39;, e => {
    if (!this.imgLoaded) {
      return;
    }
    let finger = e.touches[0];
      scx = finger.pageX;
      scy = finger.pageY;
      iX = this.imgX;
      iY = this.imgY;  
  }, false);
  $gesture.addEventListener(&#39;touchmove&#39;, e => {
    e.preventDefault();
    if (!this.imgLoaded) {
      return;
    }
    let f1x = e.touches[0].pageX,
      f1y = e.touches[0].pageY;
      this._drawImage(iX + f1x - scx, iY + f1y - scy, this.imgCurrentWidth, this.imgCurrentHeight);
  }, false);
}

   七、縮放圖片(這里不作特別說明的坐標(biāo)都是相對于cCanvas坐標(biāo)系)

  繪制縮放后的圖片無非需要4個參數(shù),縮放后圖片左上角的坐標(biāo)以及寬高。求寬高相對好辦,寬高等于imgStartWidth * 縮放比率與imgstartHeight * 縮放倍率(imgStartWidth ,imgstartHeight 上文第四節(jié)有提到)。接下來就是求縮放倍率的問題了,首先在touchstart事件上求取兩手指間的距離d1;然后在touchmove事件上繼續(xù)求取兩手指間的距離d2,當(dāng)前縮放倍率= 初始縮放倍率 + (d2-d1) / 步長(例如每60px算0.1),touchend事件上讓初始縮放倍率=當(dāng)前縮放倍率。

  至于如何求取縮放后圖片左上角的坐標(biāo)值,在草稿紙上畫來畫去,畫了很久......終于有點(diǎn)眉目。首先要找到一個縮放中心(這里做法是取雙指的中點(diǎn)坐標(biāo),但是這個坐標(biāo)必須要位于圖片上,如果不在圖片上,則取圖片上離該中點(diǎn)坐標(biāo)最近的點(diǎn)),然后存在下面這個等式

  (縮放中心x坐標(biāo) - 縮放后圖片左上角x坐標(biāo))/ 縮放后圖片的寬度 = (縮放中心x坐標(biāo) - 縮放前圖片左上角x坐標(biāo))/ 縮放前圖片的寬度;(y坐標(biāo)同理)

  接下來看看下面這個例子(在visio找了很久都沒有畫坐標(biāo)系的功能,所以只能手工畫了)

  

  綠色框是一張10*5的圖片,藍(lán)色框是寬高放大兩倍后的圖片20*10,根據(jù)上面的公式推算的x2 = sx - w2(sx - x1) / w1,y2 = sy - h2(sy - y1) / h1。

  堅(jiān)持...繼續(xù)看看代碼吧

_initEvent() {
  let $gesture = this.$refs.gesture,
    cClientRect = this.$refs.canvas.getBoundingClientRect(),
    scx = 0, //對于單手操作是移動的起點(diǎn)坐標(biāo),對于縮放是圖片距離兩手指的中點(diǎn)最近的圖標(biāo)。
    scy = 0,
    fingers = {}; //記錄當(dāng)前有多少只手指在觸控屏幕
  //one finger
  let iX = this.imgX,
    iY = this.imgY;
  //two finger
  let figureDistance = 0,
    pinchScale = this.imgScale;
  $gesture.addEventListener(&#39;touchstart&#39;, e => {
    if (!this.imgLoaded) {
      return;
    }
    if (e.touches.length === 1) {
      let finger = e.touches[0];
      scx = finger.pageX;
      scy = finger.pageY;
      iX = this.imgX;
      iY = this.imgY;
      fingers[finger.identifier] = finger;
    } else if (e.touches.length === 2) {
      let finger1 = e.touches[0],
        finger2 = e.touches[1],
        f1x = finger1.pageX - cClientRect.left,
        f1y = finger1.pageY - cClientRect.top,
        f2x = finger2.pageX - cClientRect.left,
        f2y = finger2.pageY - cClientRect.top;
      scx = parseInt((f1x + f2x) / 2);
      scy = parseInt((f1y + f2y) / 2);
      figureDistance = this._pointDistance(f1x, f1y, f2x, f2y);
      fingers[finger1.identifier] = finger1;
      fingers[finger2.identifier] = finger2;
      //判斷變換中點(diǎn)是否在圖片中,如果不是則去離圖片最近的點(diǎn)
      if (scx < this.imgX) {
        scx = this.imgX;
      }
      if (scx > this.imgX + this.imgCurrentWidth) {
        scx = this.imgX + this.imgCurrentHeight;
      }
      if (scy < this.imgY) {
        scy = this.imgY;
      }
      if (scy > this.imgY + this.imgCurrentHeight) {
        scy = this.imgY + this.imgCurrentHeight;
      }
    }
  }, false);
  $gesture.addEventListener(&#39;touchmove&#39;, e => {
    e.preventDefault();
    if (!this.imgLoaded) {
      return;
    }
    this.maskShowTimer && clearTimeout(this.maskShowTimer);
    this.maskShow = false;
    if (e.touches.length === 1) {
      let f1x = e.touches[0].pageX,
        f1y = e.touches[0].pageY;
      this._drawImage(iX + f1x - scx, iY + f1y - scy, this.imgCurrentWidth, this.imgCurrentHeight);
    } else if (e.touches.length === 2) {
      let finger1 = e.touches[0],
        finger2 = e.touches[1],
        f1x = finger1.pageX - cClientRect.left,
        f1y = finger1.pageY - cClientRect.top,
        f2x = finger2.pageX - cClientRect.left,
        f2y = finger2.pageY - cClientRect.top,
        newFigureDistance = this._pointDistance(f1x, f1y, f2x, f2y),
        scale = this.imgScale + parseFloat(((newFigureDistance - figureDistance) / this.imgScaleStep).toFixed(1));
      fingers[finger1.identifier] = finger1;
      fingers[finger2.identifier] = finger2;
      if (scale !== pinchScale) {
        //目前縮放的最小比例是1,最大是5
        if (scale < this.imgMinScale) {
          scale = this.imgMinScale;
        } else if (scale > this.imgMaxScale) {
          scale = this.imgMaxScale;
        }
        pinchScale = scale;
        this._scale(scx, scy, scale);
      }
    }
  }, false);
  $gesture.addEventListener(&#39;touchend&#39;, e => {
    if (!this.imgLoaded) {
      return;
    }
    this.imgScale = pinchScale;
    //從finger刪除已經(jīng)離開的手指
    let touches = Array.prototype.slice.call(e.changedTouches, 0);
    touches.forEach(item => {
      delete fingers[item.identifier];
    });
    //迭代fingers,如果存在finger則更新scx,scy,iX,iY,因?yàn)榭赡芸s放后立即單指拖動
    let i,
      fingerArr = [];
    for(i in fingers) {
      if (fingers.hasOwnProperty(i)) {
        fingerArr.push(fingers[i]);
      }
    }
    if (fingerArr.length > 0) {
      scx = fingerArr[0].pageX;
      scy = fingerArr[0].pageY;
      iX = this.imgX;
      iY = this.imgY;
    } else {
      this.maskShowTimer = setTimeout(() => {
        this.maskShow = true;
      }, 300);
    }
    //做邊界值檢測
    let x = this.imgX,
      y = this.imgY,
      pClientRect = this.$refs.pCanvas.getBoundingClientRect();
    if (x > pClientRect.left + pClientRect.width) {
      x = pClientRect.left
    } else if (x + this.imgCurrentWidth < pClientRect.left) {
      x = pClientRect.left + pClientRect.width - this.imgCurrentWidth;
    }
    if (y > pClientRect.top + pClientRect.height) {
      y = pClientRect.top;
    } else if (y + this.imgCurrentHeight < pClientRect.top) {
      y = pClientRect.top + pClientRect.height - this.imgCurrentHeight;
    }
    if (this.imgX !== x || this.imgY !== y) {
      this._drawImage(x, y, this.imgCurrentWidth, this.imgCurrentHeight);
    }
  });
},
_scale(x, y, scale) {
  let newPicWidth = parseInt(this.imgStartWidth * scale),
    newPicHeight = parseInt(this.imgStartHeight * scale),
    newIX = parseInt(x - newPicWidth * (x - this.imgX) / this.imgCurrentWidth),
    newIY = parseInt(y - newPicHeight * (y - this.imgY) / this.imgCurrentHeight);
  this._drawImage(newIX, newIY, newPicWidth, newPicHeight);
},
_pointDistance(x1, y1, x2, y2) {
  return parseInt(Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)));
}

  說明一下fingers是干嘛的,是用來記錄當(dāng)前有多少只手指在屏幕上觸摸??赡軙霈F(xiàn)這種情況,雙指縮放后,其中一只手指移出顯示屏,而另外一個手指在顯示屏上移動。針對這種情況,要在touchend事件上根據(jù)e.changedTouches來移除fingers里已經(jīng)離開顯示屏的finger,如果此時fingers里只剩下一個finger,則更新scx,scy,iX,iY為移動圖片做初始化準(zhǔn)備。

  八、裁剪圖片

  這里很簡單,就調(diào)用pCanvas的toDataURL方法就可以了

_clipper() {
  let imgData = null;
  try {
    imgData = this.$refs.pCanvas.toDataURL();
  } catch (e) {
    console.error(&#39;請?jiān)趓esponse header加上Access-Control-Allow-Origin,否則canvas無法裁剪未經(jīng)許可的跨域圖片&#39;);
  }
  this.$emit(&#39;sure&#39;, imgData);
}

上面是我整理給大家的,希望今后會對大家有幫助。

相關(guān)文章:

在Bootstrap框架里使用treeview如何實(shí)現(xiàn)動態(tài)加載數(shù)據(jù)

在Nginx中如何配置多站點(diǎn)vhost

在vue中如何實(shí)現(xiàn)跳轉(zhuǎn)到之前頁面

在express+mockjs中如何實(shí)現(xiàn)后臺數(shù)據(jù)發(fā)送

以上是使用Vue移動端如何實(shí)現(xiàn)圖片裁剪組件的詳細(xì)內(nèi)容。更多信息請關(guān)注PHP中文網(wǎng)其他相關(guān)文章!

本站聲明
本文內(nèi)容由網(wǎng)友自發(fā)貢獻(xiàn),版權(quán)歸原作者所有,本站不承擔(dān)相應(yīng)法律責(zé)任。如您發(fā)現(xiàn)有涉嫌抄襲侵權(quán)的內(nèi)容,請聯(lián)系admin@php.cn

熱AI工具

Undress AI Tool

Undress AI Tool

免費(fèi)脫衣服圖片

Undresser.AI Undress

Undresser.AI Undress

人工智能驅(qū)動的應(yīng)用程序,用于創(chuàng)建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用于從照片中去除衣服的在線人工智能工具。

Clothoff.io

Clothoff.io

AI脫衣機(jī)

Video Face Swap

Video Face Swap

使用我們完全免費(fèi)的人工智能換臉工具輕松在任何視頻中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費(fèi)的代碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

功能強(qiáng)大的PHP集成開發(fā)環(huán)境

Dreamweaver CS6

Dreamweaver CS6

視覺化網(wǎng)頁開發(fā)工具

SublimeText3 Mac版

SublimeText3 Mac版

神級代碼編輯軟件(SublimeText3)

熱門話題

Laravel 教程
1601
29
PHP教程
1502
276
怎樣開發(fā)一個完整的PythonWeb應(yīng)用程序? 怎樣開發(fā)一個完整的PythonWeb應(yīng)用程序? May 23, 2025 pm 10:39 PM

要開發(fā)一個完整的PythonWeb應(yīng)用程序,應(yīng)遵循以下步驟:1.選擇合適的框架,如Django或Flask。2.集成數(shù)據(jù)庫,使用ORM如SQLAlchemy。3.設(shè)計前端,使用Vue或React。4.進(jìn)行測試,使用pytest或unittest。5.部署應(yīng)用,使用Docker和平臺如Heroku或AWS。通過這些步驟,可以構(gòu)建出功能強(qiáng)大且高效的Web應(yīng)用。

前端路由(Vue Router、React Router)的工作原理及配置方法? 前端路由(Vue Router、React Router)的工作原理及配置方法? May 20, 2025 pm 07:18 PM

前端路由系統(tǒng)的核心是將URL映射到組件,VueRouter和ReactRouter通過監(jiān)聽URL變化并加載相應(yīng)組件實(shí)現(xiàn)無刷新頁面切換。配置方法包括:1.嵌套路由,允許在父組件中嵌套子組件;2.動態(tài)路由,根據(jù)URL參數(shù)加載不同組件;3.路由守衛(wèi),在路由切換前后執(zhí)行邏輯如權(quán)限檢查。

Vue的反應(yīng)性轉(zhuǎn)換(實(shí)驗(yàn),然后被刪除)的意義是什么? Vue的反應(yīng)性轉(zhuǎn)換(實(shí)驗(yàn),然后被刪除)的意義是什么? Jun 20, 2025 am 01:01 AM

ReactivitytransforminVue3aimedtosimplifyhandlingreactivedatabyautomaticallytrackingandmanagingreactivitywithoutrequiringmanualref()or.valueusage.Itsoughttoreduceboilerplateandimprovecodereadabilitybytreatingvariableslikeletandconstasautomaticallyreac

Vue.js 與 React 在組件化開發(fā)中的核心差異是什么? Vue.js 與 React 在組件化開發(fā)中的核心差異是什么? May 21, 2025 pm 08:39 PM

Vue.js和React在組件化開發(fā)中的核心差異在于:1)Vue.js使用模板語法和選項(xiàng)式API,而React使用JSX和函數(shù)式組件;2)Vue.js采用響應(yīng)式系統(tǒng),React則使用不可變數(shù)據(jù)和虛擬DOM;3)Vue.js提供多個生命周期鉤子,React則更多使用useEffect鉤子。

如何在VUE應(yīng)用程序中實(shí)施國際化(I18N)和本地化(L10N)? 如何在VUE應(yīng)用程序中實(shí)施國際化(I18N)和本地化(L10N)? Jun 20, 2025 am 01:00 AM

國際化和傾斜度invueAppsareprimandermedusingthevuei18nplugin.1.installvue-i18nvianpmoryarn.2.createlo calejsonfiles(例如,en.json,es.json)fortranslationMessages.3.setupthei18ninstanceinmain.jswithlocaleconfigurationandmessagefil

Vue 響應(yīng)式原理及在數(shù)組更新時不觸發(fā)視圖更新的解決方案? Vue 響應(yīng)式原理及在數(shù)組更新時不觸發(fā)視圖更新的解決方案? May 20, 2025 pm 06:54 PM

Vue.js處理數(shù)組更新時,視圖未更新是因?yàn)镺bject.defineProperty無法直接監(jiān)聽到數(shù)組變化。解決方法包括:1.使用Vue.set方法修改數(shù)組索引;2.重新賦值整個數(shù)組;3.使用Vue重寫過的變異方法操作數(shù)組。

使用VUE中的V-For指令使用關(guān)鍵屬性(:key)的好處是什么? 使用VUE中的V-For指令使用關(guān)鍵屬性(:key)的好處是什么? Jun 08, 2025 am 12:14 AM

Usingthe:keyattributewithv-forinVueisessentialforperformanceandcorrectbehavior.First,ithelpsVuetrackeachelementefficientlybyenablingthevirtualDOMdiffingalgorithmtoidentifyandupdateonlywhat’snecessary.Second,itpreservescomponentstateinsideloops,ensuri

您如何優(yōu)化VUE中大型列表或復(fù)雜組件的重新渲染? 您如何優(yōu)化VUE中大型列表或復(fù)雜組件的重新渲染? Jun 07, 2025 am 12:14 AM

優(yōu)化Vue中大型列表和復(fù)雜組件性能的方法包括:1.使用v-once指令處理靜態(tài)內(nèi)容,減少不必要的更新;2.實(shí)現(xiàn)虛擬滾動,僅渲染可視區(qū)域的內(nèi)容,如使用vue-virtual-scroller庫;3.通過keep-alive或v-once緩存組件,避免重復(fù)掛載;4.利用計算屬性和偵聽器優(yōu)化響應(yīng)式邏輯,減少重渲染范圍;5.遵循最佳實(shí)踐,如在v-for中使用唯一key、避免模板中的內(nèi)聯(lián)函數(shù),并使用性能分析工具定位瓶頸。這些策略能有效提升應(yīng)用流暢度。

See all articles