最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

vue.js 實(shí)現(xiàn)v-model與{{}}指令方法

 更新時(shí)間:2018年10月30日 15:02:54   作者:peakedness丶  
這篇文章主要介紹了vue.js 實(shí)現(xiàn)v-model與{{}}指令方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

上次我們已經(jīng)分析了vue.js是通過Object.defineProperty以及發(fā)布訂閱模式來進(jìn)行數(shù)據(jù)劫持和監(jiān)聽,并且實(shí)現(xiàn)了一個簡單的demo。今天,我們就基于上一節(jié)的代碼,來實(shí)現(xiàn)一個MVVM類,將其與html結(jié)合在一起,并且實(shí)現(xiàn)v-model以及{{}}語法。

tips:本節(jié)新增代碼(去除注釋)在一百行左右。使用的Observer和Watcher都是延用上一節(jié)的代碼,沒有修改。

接下來,讓我們一步步來,實(shí)現(xiàn)一個MVVM類。

構(gòu)造函數(shù)

首先,一個MVVM的構(gòu)造函數(shù)如下(和vue.js的構(gòu)造函數(shù)一樣):

class MVVM {
 constructor({ data, el }) {
  this.data = data;
  this.el = el;
  this.init();
  this.initDom();
 }
}

和vue.js一樣,有它的data屬性以及el元素。

初始化操作

vue.js可以通過this.xxx的方法來直接訪問this.data.xxx的屬性,這一點(diǎn)是怎么做到的呢?其實(shí)答案很簡單,它是通過Object.defineProperty來做手腳,當(dāng)你訪問this.xxx的時(shí)候,它返回的其實(shí)是this.data.xxx。當(dāng)你修改this.xxx值的時(shí)候,其實(shí)修改的是this.data.xxx的值。具體可以看如下代碼:

class MVVM {
 constructor({ data, el }) {
  this.data = data;
  this.el = el;
  this.init();
  this.initDom();
 }
 // 初始化
 init() {
  // 對this.data進(jìn)行數(shù)據(jù)劫持
  new Observer(this.data);
  // 傳入的el可以是selector,也可以是元素,因此我們要在這里做一層處理,保證this.$el的值是一個元素節(jié)點(diǎn)
  this.$el = this.isElementNode(this.el) ? this.el : document.querySelector(this.el);
  // 將this.data的屬性都綁定到this上,這樣用戶就可以直接通過this.xxx來訪問this.data.xxx的值
  for (let key in this.data) {
   this.defineReactive(key);
  }
 }

 defineReactive(key) {
  Object.defineProperty(this, key, {
   get() {
    return this.data[key];
   },
   set(newVal) {
    this.data[key] = newVal;
   } //前端全棧學(xué)習(xí)交流圈:866109386
  })//面向1-3年前端開發(fā)人員
 }//幫助突破技術(shù)瓶頸,提升思維能力。
 // 是否是屬性節(jié)點(diǎn)
 isElementNode(node) {
  return node.nodeType === 1;
 }
}

在完成初始化操作后,我們需要對this.$el的節(jié)點(diǎn)進(jìn)行編譯。目前我們要實(shí)現(xiàn)的語法有v-model和{{}}語法,v-model這個屬性只可能會出現(xiàn)在元素節(jié)點(diǎn)的attributes里,而{{}}語法則是出現(xiàn)在文本節(jié)點(diǎn)里。

fragment

在對節(jié)點(diǎn)進(jìn)行編譯之前,我們先考慮一個現(xiàn)實(shí)問題:如果我們在編譯過程中直接操作DOM節(jié)點(diǎn)的話,每一次修改DOM都會導(dǎo)致DOM的回流或重繪,而這一部分性能損耗是很沒有必要的。因此,我們可以利用fragment,將節(jié)點(diǎn)轉(zhuǎn)化為fragment,然后在fragment里編譯完成后,再將其放回到頁面上。

class MVVM {
 constructor({ data, el }) {
  this.data = data;
  this.el = el;//前端全棧交流學(xué)習(xí)圈:866109386
  this.init();//針對1-3年前端開發(fā)人員
  this.initDom();//幫助突破技術(shù)瓶頸,提升思維能力。
 }

 initDom() {
  const fragment = this.node2Fragment();
  this.compile(fragment);
  // 將fragment返回到頁面中
  document.body.appendChild(fragment);
 }
 // 將節(jié)點(diǎn)轉(zhuǎn)為fragment,通過fragment來操作DOM,可以獲得更高的效率
 // 因?yàn)槿绻苯硬僮鱀OM節(jié)點(diǎn)的話,每次修改DOM都會導(dǎo)致DOM的回流或重繪,而將其放在fragment里,修改fragment不會導(dǎo)致DOM回流和重繪
 // 當(dāng)在fragment一次性修改完后,在直接放回到DOM節(jié)點(diǎn)中
 node2Fragment() {
  const fragment = document.createDocumentFragment();
  let firstChild;
  while(firstChild = this.$el.firstChild) {
   fragment.appendChild(firstChild);
  }
  return fragment;
 }
}

實(shí)現(xiàn)v-model

在將node節(jié)點(diǎn)轉(zhuǎn)為fragment后,我們來對其中的v-model語法進(jìn)行編譯。

由于v-model語句只可能會出現(xiàn)在元素節(jié)點(diǎn)的attributes里,因此,我們先判斷該節(jié)點(diǎn)是否為元素節(jié)點(diǎn),若為元素節(jié)點(diǎn),則判斷其是否是directive(目前只有v-model),若都滿足的話,則調(diào)用CompileUtils.compileModelAttr來編譯該節(jié)點(diǎn)。

編譯含有v-model的節(jié)點(diǎn)主要有兩步:

  1. 為元素節(jié)點(diǎn)注冊input事件,在input事件觸發(fā)的時(shí)候,更新vm(this.data)上對應(yīng)的屬性值。
  2. 對v-model依賴的屬性注冊一個Watcher函數(shù),當(dāng)依賴的屬性發(fā)生變化,則更新元素節(jié)點(diǎn)的value。
class MVVM {
 constructor({ data, el }) {
  this.data = data;
  this.el = el;
  this.init();
  this.initDom();
 }

 initDom() {
  const fragment = this.node2Fragment();
  this.compile(fragment);
  // 將fragment返回到頁面中
  document.body.appendChild(fragment);
 }

 compile(node) {
  if (this.isElementNode(node)) {
   // 若是元素節(jié)點(diǎn),則遍歷它的屬性,編譯其中的指令
   const attrs = node.attributes;
   Array.prototype.forEach.call(attrs, (attr) => {
    if (this.isDirective(attr)) {
     CompileUtils.compileModelAttr(this.data, node, attr)
    }
   })
  }
  // 若節(jié)點(diǎn)有子節(jié)點(diǎn)的話,則對子節(jié)點(diǎn)進(jìn)行編譯
  if (node.childNodes && node.childNodes.length > 0) {
   Array.prototype.forEach.call(node.childNodes, (child) => {
    this.compile(child);
   })
  }
 }
 // 是否是屬性節(jié)點(diǎn)
 isElementNode(node) {
  return node.nodeType === 1;
 }
 // 檢測屬性是否是指令(vue的指令是v-開頭)
 isDirective(attr) {
  return attr.nodeName.indexOf('v-') >= 0;
 }
}

const CompileUtils = {
 // 編譯v-model屬性,為元素節(jié)點(diǎn)注冊input事件,在input事件觸發(fā)的時(shí)候,更新vm對應(yīng)的值。
 // 同時(shí)也注冊一個Watcher函數(shù),當(dāng)所依賴的值發(fā)生變化的時(shí)候,更新節(jié)點(diǎn)的值
 compileModelAttr(vm, node, attr) {
  const { value: keys, nodeName } = attr;
  node.value = this.getModelValue(vm, keys);
  // 將v-model屬性值從元素節(jié)點(diǎn)上去掉
  node.removeAttribute(nodeName);
  node.addEventListener('input', (e) => {
   this.setModelValue(vm, keys, e.target.value);
  });

  new Watcher(vm, keys, (oldVal, newVal) => {
   node.value = newVal;
  });
 },
 /* 解析keys,比如,用戶可以傳入
 * <input v-model="obj.name" />
 * 這個時(shí)候,我們在取值的時(shí)候,需要將"obj.name"解析為data[obj][name]的形式來獲取目標(biāo)值
 */
 parse(vm, keys) {
  keys = keys.split('.');
  let value = vm;
  keys.forEach(_key => {
   value = value[_key];
  });
  return value;
 },
 // 根據(jù)vm和keys,返回v-model對應(yīng)屬性的值
 getModelValue(vm, keys) {
  return this.parse(vm, keys);
 },
 // 修改v-model對應(yīng)屬性的值
 setModelValue(vm, keys, val) {
  keys = keys.split('.');
  let value = vm;
  for(let i = 0; i < keys.length - 1; i++) {
   value = value[keys[i]];
  }
  value[keys[keys.length - 1]] = val;
 },
}

實(shí)現(xiàn){{}}語法

{{}}語法只可能會出現(xiàn)在文本節(jié)點(diǎn)中,因此,我們只需要對文本節(jié)點(diǎn)做處理。如果文本節(jié)點(diǎn)中出現(xiàn){{key}}這種語句的話,我們則對該節(jié)點(diǎn)進(jìn)行編譯。在這里,我們可以通過下面這個正則表達(dá)式來對文本節(jié)點(diǎn)進(jìn)行處理,判斷其是否含有{{}}語法。

const textReg = /\{\{\s*\w+\s*\}\}/gi; // 檢測{{name}}語法
console.log(textReg.test('sss'));
console.log(textReg.test('aaa{{ name }}'));
console.log(textReg.test('aaa{{ name }} {{ text }}'));

若含有{{}}語法,我們則可以對其處理,由于一個文本節(jié)點(diǎn)可能出現(xiàn)多個{{}}語法,因此編譯含有{{}}語法的文本節(jié)點(diǎn)主要有以下兩步:

  1. 找出該文本節(jié)點(diǎn)中所有依賴的屬性,并且保留原始文本信息,根據(jù)原始文本信息還有屬性值,生成最終的文本信息。比如說,原始文本信息是"test {{test}} {{name}}",那么該文本信息依賴的屬性有this.data.test和this.data.name,那么我們可以根據(jù)原本信息和屬性值,生成最終的文本。
  2. 為該文本節(jié)點(diǎn)所有依賴的屬性注冊Watcher函數(shù),當(dāng)依賴的屬性發(fā)生變化的時(shí)候,則更新文本節(jié)點(diǎn)的內(nèi)容。
class MVVM {
 constructor({ data, el }) {
  this.data = data;
  this.el = el;
  this.init();
  this.initDom();
 }

 initDom() {
  const fragment = this.node2Fragment();
  this.compile(fragment);
  // 將fragment返回到頁面中
  document.body.appendChild(fragment);
 }

 compile(node) {
  const textReg = /\{\{\s*\w+\s*\}\}/gi; // 檢測{{name}}語法
  if (this.isTextNode(node)) {
   // 若是文本節(jié)點(diǎn),則判斷是否有{{}}語法,如果有的話,則編譯{{}}語法
   let textContent = node.textContent;
   if (textReg.test(textContent)) {
    // 對于 "test{{test}} {{name}}"這種文本,可能在一個文本節(jié)點(diǎn)會出現(xiàn)多個匹配符,因此得對他們統(tǒng)一進(jìn)行處理
    // 使用 textReg來對文本節(jié)點(diǎn)進(jìn)行匹配,可以得到["{{test}}", "{{name}}"]兩個匹配值
    const matchs = textContent.match(textReg);
    CompileUtils.compileTextNode(this.data, node, matchs);
   }
  }
  // 若節(jié)點(diǎn)有子節(jié)點(diǎn)的話,則對子節(jié)點(diǎn)進(jìn)行編譯
  if (node.childNodes && node.childNodes.length > 0) {
   Array.prototype.forEach.call(node.childNodes, (child) => {
    this.compile(child);
   })
  }
 }
 // 是否是文本節(jié)點(diǎn)
 isTextNode(node) {
  return node.nodeType === 3;
 }
}

const CompileUtils = {
 reg: /\{\{\s*(\w+)\s*\}\}/, // 匹配 {{ key }}中的key
 // 編譯文本節(jié)點(diǎn),并注冊Watcher函數(shù),當(dāng)文本節(jié)點(diǎn)依賴的屬性發(fā)生變化的時(shí)候,更新文本節(jié)點(diǎn)
 compileTextNode(vm, node, matchs) {
  // 原始文本信息
  const rawTextContent = node.textContent;
  matchs.forEach((match) => {
   const keys = match.match(this.reg)[1];
   console.log(rawTextContent);
   new Watcher(vm, keys, () => this.updateTextNode(vm, node, matchs, rawTextContent));
  });
  this.updateTextNode(vm, node, matchs, rawTextContent);
 },
 // 更新文本節(jié)點(diǎn)信息
 updateTextNode(vm, node, matchs, rawTextContent) {
  let newTextContent = rawTextContent;
  matchs.forEach((match) => {
   const keys = match.match(this.reg)[1];
   const val = this.getModelValue(vm, keys);
   newTextContent = newTextContent.replace(match, val);
  })
  node.textContent = newTextContent;
 }
}

結(jié)語

這樣,一個具有v-model和{{}}功能的MVVM類就已經(jīng)完成了

這里也有一個簡單的樣例(忽略樣式)。

接下來的話,可能會繼續(xù)實(shí)現(xiàn)computed屬性,v-bind方法,以及支持在{{}}里面放表達(dá)式。如果覺得這個文章對你有幫助的話,麻煩點(diǎn)個贊,嘻嘻。

最后,貼上所有的代碼:

class Observer {
 constructor(data) {
  // 如果不是對象,則返回
  if (!data || typeof data !== 'object') {
   return;
  }
  this.data = data;
  this.walk();
 }

 // 對傳入的數(shù)據(jù)進(jìn)行數(shù)據(jù)劫持
 walk() {
  for (let key in this.data) {
   this.defineReactive(this.data, key, this.data[key]);
  }
 }
 // 創(chuàng)建當(dāng)前屬性的一個發(fā)布實(shí)例,使用Object.defineProperty來對當(dāng)前屬性進(jìn)行數(shù)據(jù)劫持。
 defineReactive(obj, key, val) {
  // 創(chuàng)建當(dāng)前屬性的發(fā)布者
  const dep = new Dep();
  /*
  * 遞歸對子屬性的值進(jìn)行數(shù)據(jù)劫持,比如說對以下數(shù)據(jù)
  * let data = {
  *  name: 'cjg',
  *  obj: {
  *   name: 'zht',
  *   age: 22,
  *   obj: {
  *    name: 'cjg',
  *    age: 22,
  *   }
  *  },
  * };
  * 我們先對data最外層的name和obj進(jìn)行數(shù)據(jù)劫持,之后再對obj對象的子屬性obj.name,obj.age, obj.obj進(jìn)行數(shù)據(jù)劫持,層層遞歸下去,直到所有的數(shù)據(jù)都完成了數(shù)據(jù)劫持工作。
  */
  new Observer(val);
  Object.defineProperty(obj, key, {
   get() {
    // 若當(dāng)前有對該屬性的依賴項(xiàng),則將其加入到發(fā)布者的訂閱者隊(duì)列里
    if (Dep.target) {
     dep.addSub(Dep.target);
    }
    return val;
   },
   set(newVal) {
    if (val === newVal) {
     return;
    }
    val = newVal;
    new Observer(newVal);
    dep.notify();
   }
  })
 }
}

// 發(fā)布者,將依賴該屬性的watcher都加入subs數(shù)組,當(dāng)該屬性改變的時(shí)候,則調(diào)用所有依賴該屬性的watcher的更新函數(shù),觸發(fā)更新。
class Dep {
 constructor() {
  this.subs = [];
 }

 addSub(sub) {
  if (this.subs.indexOf(sub) < 0) {
   this.subs.push(sub);
  }
 }

 notify() {
  this.subs.forEach((sub) => {
   sub.update();
  })
 }
}

Dep.target = null;

// 觀察者
class Watcher {
 /**
  *Creates an instance of Watcher.
  * @param {*} vm
  * @param {*} keys
  * @param {*} updateCb
  * @memberof Watcher
  */
 constructor(vm, keys, updateCb) {
  this.vm = vm;
  this.keys = keys;
  this.updateCb = updateCb;
  this.value = null;
  this.get();
 }

 // 根據(jù)vm和keys獲取到最新的觀察值
 get() {
  // 將Dep的依賴項(xiàng)設(shè)置為當(dāng)前的watcher,并且根據(jù)傳入的keys遍歷獲取到最新值。
  // 在這個過程中,由于會調(diào)用observer對象屬性的getter方法,因此在遍歷過程中這些對象屬性的發(fā)布者就將watcher添加到訂閱者隊(duì)列里。
  // 因此,當(dāng)這一過程中的某一對象屬性發(fā)生變化的時(shí)候,則會觸發(fā)watcher的update方法
  Dep.target = this;
  this.value = CompileUtils.parse(this.vm, this.keys);
  Dep.target = null;
  return this.value;
 }

 update() {
  const oldValue = this.value;
  const newValue = this.get();
  if (oldValue !== newValue) {
   this.updateCb(oldValue, newValue);
  }
 }
}

class MVVM {
 constructor({ data, el }) {
  this.data = data;
  this.el = el;
  this.init();
  this.initDom();
 }

 // 初始化
 init() {
  // 對this.data進(jìn)行數(shù)據(jù)劫持
  new Observer(this.data);
  // 傳入的el可以是selector,也可以是元素,因此我們要在這里做一層處理,保證this.$el的值是一個元素節(jié)點(diǎn)
  this.$el = this.isElementNode(this.el) ? this.el : document.querySelector(this.el);
  // 將this.data的屬性都綁定到this上,這樣用戶就可以直接通過this.xxx來訪問this.data.xxx的值
  for (let key in this.data) {
   this.defineReactive(key);
  }
 }

 initDom() {
  const fragment = this.node2Fragment();
  this.compile(fragment);
  document.body.appendChild(fragment);
 }
 // 將節(jié)點(diǎn)轉(zhuǎn)為fragment,通過fragment來操作DOM,可以獲得更高的效率
 // 因?yàn)槿绻苯硬僮鱀OM節(jié)點(diǎn)的話,每次修改DOM都會導(dǎo)致DOM的回流或重繪,而將其放在fragment里,修改fragment不會導(dǎo)致DOM回流和重繪
 // 當(dāng)在fragment一次性修改完后,在直接放回到DOM節(jié)點(diǎn)中
 node2Fragment() {
  const fragment = document.createDocumentFragment();
  let firstChild;
  while(firstChild = this.$el.firstChild) {
   fragment.appendChild(firstChild);
  }
  return fragment;
 }

 defineReactive(key) {
  Object.defineProperty(this, key, {
   get() {
    return this.data[key];
   },
   set(newVal) {
    this.data[key] = newVal;
   }
  })
 }

 compile(node) {
  const textReg = /\{\{\s*\w+\s*\}\}/gi; // 檢測{{name}}語法
  if (this.isElementNode(node)) {
   // 若是元素節(jié)點(diǎn),則遍歷它的屬性,編譯其中的指令
   const attrs = node.attributes;
   Array.prototype.forEach.call(attrs, (attr) => {
    if (this.isDirective(attr)) {
     CompileUtils.compileModelAttr(this.data, node, attr)
    }
   })
  } else if (this.isTextNode(node)) {
   // 若是文本節(jié)點(diǎn),則判斷是否有{{}}語法,如果有的話,則編譯{{}}語法
   let textContent = node.textContent;
   if (textReg.test(textContent)) {
    // 對于 "test{{test}} {{name}}"這種文本,可能在一個文本節(jié)點(diǎn)會出現(xiàn)多個匹配符,因此得對他們統(tǒng)一進(jìn)行處理
    // 使用 textReg來對文本節(jié)點(diǎn)進(jìn)行匹配,可以得到["{{test}}", "{{name}}"]兩個匹配值
    const matchs = textContent.match(textReg);
    CompileUtils.compileTextNode(this.data, node, matchs);
   }
  }
  // 若節(jié)點(diǎn)有子節(jié)點(diǎn)的話,則對子節(jié)點(diǎn)進(jìn)行編譯。
  if (node.childNodes && node.childNodes.length > 0) {
   Array.prototype.forEach.call(node.childNodes, (child) => {
    this.compile(child);
   })
  }
 }

 // 是否是屬性節(jié)點(diǎn)
 isElementNode(node) {
  return node.nodeType === 1;
 }
 // 是否是文本節(jié)點(diǎn)
 isTextNode(node) {
  return node.nodeType === 3;
 }

 isAttrs(node) {
  return node.nodeType === 2;
 }
 // 檢測屬性是否是指令(vue的指令是v-開頭)
 isDirective(attr) {
  return attr.nodeName.indexOf('v-') >= 0;
 }

}

const CompileUtils = {
 reg: /\{\{\s*(\w+)\s*\}\}/, // 匹配 {{ key }}中的key
 // 編譯文本節(jié)點(diǎn),并注冊Watcher函數(shù),當(dāng)文本節(jié)點(diǎn)依賴的屬性發(fā)生變化的時(shí)候,更新文本節(jié)點(diǎn)
 compileTextNode(vm, node, matchs) {
  // 原始文本信息
  const rawTextContent = node.textContent;
  matchs.forEach((match) => {
   const keys = match.match(this.reg)[1];
   console.log(rawTextContent);
   new Watcher(vm, keys, () => this.updateTextNode(vm, node, matchs, rawTextContent));
  });
  this.updateTextNode(vm, node, matchs, rawTextContent);
 },
 // 更新文本節(jié)點(diǎn)信息
 updateTextNode(vm, node, matchs, rawTextContent) {
  let newTextContent = rawTextContent;
  matchs.forEach((match) => {
   const keys = match.match(this.reg)[1];
   const val = this.getModelValue(vm, keys);
   newTextContent = newTextContent.replace(match, val);
  })
  node.textContent = newTextContent;
 },
 // 編譯v-model屬性,為元素節(jié)點(diǎn)注冊input事件,在input事件觸發(fā)的時(shí)候,更新vm對應(yīng)的值。
 // 同時(shí)也注冊一個Watcher函數(shù),當(dāng)所依賴的值發(fā)生變化的時(shí)候,更新節(jié)點(diǎn)的值
 compileModelAttr(vm, node, attr) {
  const { value: keys, nodeName } = attr;
  node.value = this.getModelValue(vm, keys);
  // 將v-model屬性值從元素節(jié)點(diǎn)上去掉
  node.removeAttribute(nodeName);
  new Watcher(vm, keys, (oldVal, newVal) => {
   node.value = newVal;
  });
  node.addEventListener('input', (e) => {
   this.setModelValue(vm, keys, e.target.value);
  });
 },
 /* 解析keys,比如,用戶可以傳入
 * let data = {
 *  name: 'cjg',
 *  obj: {
 *   name: 'zht',
 *  },
 * };
 * new Watcher(data, 'obj.name', (oldValue, newValue) => {
 *  console.log(oldValue, newValue);
 * })
 * 這個時(shí)候,我們需要將keys解析為data[obj][name]的形式來獲取目標(biāo)值
 */
 parse(vm, keys) {
  keys = keys.split('.');
  let value = vm;
  keys.forEach(_key => {
   value = value[_key];
  });
  return value;
 },
 // 根據(jù)vm和keys,返回v-model對應(yīng)屬性的值
 getModelValue(vm, keys) {
  return this.parse(vm, keys);
 },
 // 修改v-model對應(yīng)屬性的值
 setModelValue(vm, keys, val) {
  keys = keys.split('.');
  let value = vm;
  for(let i = 0; i < keys.length - 1; i++) {
   value = value[keys[i]];
  }
  value[keys[keys.length - 1]] = val;
 },
}

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Vue打包上線之后部分CSS不生效問題的解決辦法

    Vue打包上線之后部分CSS不生效問題的解決辦法

    在vue項(xiàng)目中開發(fā)環(huán)境的樣式?jīng)]問題,但是打包上線后,樣式不生效,下面這篇文章主要給大家介紹了關(guān)于Vue打包上線之后部分CSS不生效問題的解決辦法,需要的朋友可以參考下
    2022-12-12
  • vue跳轉(zhuǎn)時(shí)根據(jù)url錨點(diǎn)(#xxx)實(shí)現(xiàn)頁面內(nèi)容定位的方法

    vue跳轉(zhuǎn)時(shí)根據(jù)url錨點(diǎn)(#xxx)實(shí)現(xiàn)頁面內(nèi)容定位的方法

    本前端仔在做頁面跳轉(zhuǎn)的時(shí)候,被要求跳轉(zhuǎn)到頁面時(shí)候,把對應(yīng)部分的內(nèi)容自動滾動到頂部,我一開始想到的就是根據(jù)錨點(diǎn)<a href="#xxid">進(jìn)行處理,但是發(fā)現(xiàn)不太好實(shí)現(xiàn),于是便自己研究了一個比較取巧的方法,需要的朋友可以參考下
    2024-04-04
  • Vue.js 中的 $watch使用方法

    Vue.js 中的 $watch使用方法

    本篇文章中主要介紹了Vue.js 中的 $watch使用方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-05-05
  • Vue.js 的 watch函數(shù)基本用法

    Vue.js 的 watch函數(shù)基本用法

    watch 函數(shù)是 Vue.js 提供的一個強(qiáng)大工具,用于響應(yīng)數(shù)據(jù)變化并執(zhí)行相應(yīng)的回調(diào),通過合理使用 watch 函數(shù),我們可以實(shí)現(xiàn)異步數(shù)據(jù)請求、表單驗(yàn)證、動態(tài)樣式等多種功能,這篇文章主要介紹了Vue.js 的 watch函數(shù),需要的朋友可以參考下
    2024-08-08
  • vue 項(xiàng)目打包時(shí)樣式及背景圖片路徑找不到的解決方式

    vue 項(xiàng)目打包時(shí)樣式及背景圖片路徑找不到的解決方式

    今天小編就為大家分享一篇vue 項(xiàng)目打包時(shí)樣式及背景圖片路徑找不到的解決方式,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-11-11
  • Vue中跨域及打包部署到nginx跨域設(shè)置方法

    Vue中跨域及打包部署到nginx跨域設(shè)置方法

    這篇文章主要介紹了Vue中跨域以及打包部署到nginx跨域設(shè)置方法,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-08-08
  • 從0搭建vue-cli4腳手架

    從0搭建vue-cli4腳手架

    這篇文章主要介紹了從0搭建vue-cli4腳手架,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-06-06
  • vue中使用window.open()參數(shù)示例詳解

    vue中使用window.open()參數(shù)示例詳解

    這篇文章主要介紹了vue中使用window.open()參數(shù)詳解,本文通過示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-04-04
  • 如何使用 Deepseek 寫的uniapp油耗計(jì)算器

    如何使用 Deepseek 寫的uniapp油耗計(jì)算器

    這篇文章主要介紹了如何使用 Deepseek 寫的uniapp油耗計(jì)算器,下面是一個基于 Uniapp 的油耗計(jì)算器實(shí)現(xiàn),包含 Vue 組件和頁面代碼,需要的朋友可以參考下
    2025-04-04
  • vue3.0項(xiàng)目快速搭建的完整步驟記錄

    vue3.0項(xiàng)目快速搭建的完整步驟記錄

    這篇文章主要給大家介紹了關(guān)于vue3.0項(xiàng)目快速搭建的相關(guān)資料,本文通過圖文以及實(shí)例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用vue3.0具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2021-12-12

最新評論

古浪县| 宝应县| 岳阳县| 康平县| 刚察县| 汉源县| 阳新县| 宁海县| 金门县| 禄劝| 稻城县| 社旗县| 拜城县| 太湖县| 类乌齐县| 青神县| 吉隆县| 邢台县| 吉安县| 梅州市| 乐都县| 基隆市| 博兴县| 商洛市| 甘南县| 尉犁县| 于田县| 柳州市| 福贡县| 吐鲁番市| 哈密市| 石屏县| 阿坝县| 湖南省| 山阳县| 临澧县| 大名县| 黄陵县| 德庆县| 剑河县| 南漳县|