JS与Vue笔记

·
日常 no tag May 5, 2022

Vue Note

交互方法

  • v-bind:attr 绑定属性,例如<div v-bind:class="className" ></div> ,data中className就赋值。
  • v-if="xxx" 显示
  • v-for="a in b" 循环当前dom
  • v-on:attr="xxx" 用户输入,例如监测点击 v-on:click="click" ,需要定义方法:

    var app5 = new Vue({
      el: '#app-5',
      data: {
        message: 'Hello Vue.js!'
      },
      methods: {
        click: function () {
          method...
        }
      }
    })
  • v-model 表单与应用状态双向绑定,例如在p中显示input的值:

    <div id="app-6">
      <p>{{ message }}</p>
      <input v-model="message">
    </div>
    var app6 = new Vue({
      el: '#app-6',
      data: {
        message: 'Hello Vue!'
      }
    })

组件

在 Vue 里,一个组件本质上是一个拥有预定义选项的一个 Vue 实例。在 Vue 中注册组件很简单:

// 定义名为 todo-item 的新组件
Vue.component('todo-item', {
  template: '<li>这是个待办项</li>'
})

var app = new Vue(...)

现在你可以用它构建另一个组件模板:

<ol>
  <!-- 创建一个 todo-item 组件的实例 -->
  <todo-item></todo-item>
</ol>

用prop定义属性,在组件内使用v-bind 传参:

<div id="app-7">
  <ol>
    <!--
      现在我们为每个 todo-item 提供 todo 对象
      todo 对象是变量,即其内容可以是动态的。
      我们也需要为每个组件提供一个“key”,稍后再
      作详细解释。
    -->
    <todo-item
      v-for="item in groceryList"
      v-bind:todo="item"
      v-bind:key="item.id"
    ></todo-item>
  </ol>
</div>
Vue.component('todo-item', {
  props: ['todo'],
  template: '<li>{{ todo.text }}</li>'
})

var app7 = new Vue({
  el: '#app-7',
  data: {
    groceryList: [
      { id: 0, text: '蔬菜' },
      { id: 1, text: '奶酪' },
      { id: 2, text: '随便其它什么人吃的东西' }
    ]
  }
})

生命周期钩子

实例中运行的函数,例如created 会在示例创建时调用, this指向vue实例,不要用箭头函数,会指向上一级:

new Vue({
  data: {
    a: 1
  },
  created: function () {
    // `this` 指向 vm 实例
    console.log('a is: ' + this.a)
  }
})
// => "a is: 1"

Vue 实例生命周期

模板语法

双大括号会将数据解释为普通文本,而非 HTML 代码。为了输出真正的 HTML,你需要使用v-html

<p>Using v-html directive: <span v-html="rawHtml"></span></p>

这个span的值会替换为rawHtml的值(例如为<span>something</span>),双大括号不用用在html元素属性上,应该用v-bind,双大括号中可以用JavaScript表达式

动态参数:2.6.0新增,<a v-bind:[attributeName]="url"> ... </a> attributeName在data里值为'href' ,则绑定了href属性。

在单页面应用程序中,可以缩写:v-bind:href="xxx"可缩写为:href='xxx' ,动态参数则缩写为:[key]='xxx', v-on:click=xxx 缩写为 @click=xxx

计算属性

逻辑复杂的处理放到计算属性中,为计算属性定义方法,在html中可直接引用,计算属性的this指vue实例本身。

<div id="example">
  <p>Original message: "{{ message }}"</p>
  <p>Computed reversed message: "{{ reversedMessage }}"</p>
</div>
var vm = new Vue({
  el: '#example',
  data: {
    message: 'Hello'
  },
  computed: {
    // 计算属性的 getter
    reversedMessage: function () {
      // `this` 指向 vm 实例
      return this.message.split('').reverse().join('')
    }
  }
})

访问reverseMessage会调用前面算到的值,除非message值变化才重新运算。

还有watch属性,用于监听数据变化。计算属性和侦听器 — Vue.js (vuejs.org)

条件渲染

有if-else:(2.1.0 新增v-else-if)

<h1 v-if="awesome">Vue is awesome!</h1>
<h1 v-else>Oh no 😢</h1>

用template分组渲染

因为 v-if 是一个指令,所以必须将它添加到一个元素上。但是如果想切换多个元素呢?此时可以把一个 <template> 元素当做不可见的包裹元素,并在上面使用 v-if。最终的渲染结果将不包含 <template> 元素。

<template v-if="ok">
  <h1>Title</h1>
  <p>Paragraph 1</p>
  <p>Paragraph 2</p>
</template>

v-show

v-show不是增加减少元素,只是改变style的display,不支持 template 与 else。

v-for 与 v-if 一起使用时, v-for 更高级。

事件处理

使用 v-on 监控事件,输入在method属性里的方法:

示例:

<div id="example-2">
  <!-- `greet` 是在下面定义的方法名 -->
  <button v-on:click="greet">Greet</button>
</div>
var example2 = new Vue({
  el: '#example-2',
  data: {
    name: 'Vue.js'
  },
  // 在 `methods` 对象中定义方法
  methods: {
    greet: function (event) {
      // `this` 在方法里指向当前 Vue 实例
      alert('Hello ' + this.name + '!')
      // `event` 是原生 DOM 事件
      if (event) {
        alert(event.target.tagName)
      }
    }
  }
})

// 也可以用 JavaScript 直接调用方法
example2.greet() // => 'Hello Vue.js!'

表单输入绑定

使用v-model 为表单双向绑定

<input v-model="message" placeholder="edit me">
<p>Message is: {{ message }}</p>

单个复选框,绑定到布尔值;多个复选框,绑定到一数组,数组返回选中复选框的value,单选返回选中的value。

JavaScript

输出显示方法

  • 使用 window.alert() 写入警告框
  • 使用 document.write() 写入 HTML 输出,直接输出纯文本

    <script>
    document.write(5 + 6);
    </script>
  • 使用 innerHTML 写入 HTML 元素
  • 使用 console.log() 写入浏览器控制台

块作用域

let

用 var 关键词声明的变量没有块作用域,在 {} 内使用 let 声明的变量只在 {} 内生效。

若在块外声明,var 与 let 作用相同,都会声明为全局变量(var声明的属于windows对象, let 声明的不属于)。

同一作用域中 let 不能重新声明变量,var 也不能重新声明又 let 声明的变量。不同作用域可使用let 重复声明同一名字变量(实为两个变量)。

用 var 声明的变量会提升到顶端,即可在声明前调用,而 let 不行。

const

在块作用域内使用 const 声明的变量与 let 变量相似。声明变量后不能修改变量,变量值需要在声明时定义。

const PI;
PI = 3.14159265359;  // 错误

const PI = 3.14159265359;  // 正确
PI = PI + 10;  // 错误,const声明变量不能修改

常量的对象属性可修改:

// 您可以创建 const 对象:
const car = {type:"porsche", model:"911", color:"Black"};

// 您可以更改属性:
car.color = "White";

// 您可以添加属性:
car.owner = "Bill";

// 您可以创建常量数组:
const cars = ["Audi", "BMW", "porsche"];

// 您可以更改元素:
cars[0] = "Honda";

// 您可以添加元素:
cars.push("Volvo");

运算符

  • === 等值等型
  • !== 不等值或不等型

例如定义 x=5 若有x == '5' 为真(等值),x === '5' 为假(不等型)

三元运算符

variablename = (条件) ? 为真时的值:为假时的值;
var voteable = (age < 18) ? "太年轻":"足够成熟";

函数

定义:function name(par1, par2){}

直接用函数名引用的是函数对象,加括号则是调用函数结果。

function对象

函数实际上是功能完整的对象,可使用function类直接创建函数:

var function_name = new function(arg1, arg2, ..., argN, function_body)

function_body是函数主体(执行的代码)(参数都是字符串),例如:

function sayHi(sName, sMessage) {
  alert("Hello " + sName + sMessage);
}
// 可以这样定义
var sayHi = new Function("sName", "sMessage", "alert(\"Hello \" + sName + sMessage);");

length 属性声明了函数期望的参数个数:

function doAdd(iNum) {
  alert(iNum + 10);
}

function sayHi() {
  alert("Hi");
}

alert(doAdd.length);    //输出 "1"
alert(sayHi.length);    //输出 "0"

arguments对象

在函数代码中,使用特殊对象 arguments,开发者无需明确指出参数名,就能访问它们。

function sayHi() {
  if (arguments[0] == "bye") {
    return;
  }

  alert(arguments[0]);
}

高级函数

函数声明:

function foo () {

}

函数表达式:

var foo = function () {

}

函数声明与函数表达式的区别

  • 函数声明必须有名字
  • 函数声明会函数提升,在预解析阶段就已创建,声明前后都可以调用
  • 函数表达式类似于变量赋值
  • 函数表达式可以没有名字,例如匿名函数
  • 函数表达式没有变量提升,在执行阶段创建,必须在表达式执行之后才可以调用

函数内 this 指向的不同场景

函数的调用方式决定了 this 指向的不同:

调用方式this指向
普通函数调用window
构造函数调用实例对象
对象方法调用该方法所属对象
事件绑定方法绑定事件对象
定时器函数window

若想改变this,可以使用以下函数:

  • call() 方法调用一个函数, 其具有一个指定的 this 值和分别地提供的参数(参数的列表)。
fun.call(指定的this值, 多个原函数的参数...)
  • apply() 方法调用一个函数, 其具有一个指定的 this 值,以及作为一个数组(或类似数组的对象)提供的参数。

    fun.apply(指定的this值, [原参数1, ... , 原参数N])

两者仅提供参数方法不同。

bind() 函数会创建一个新函数(称为绑定函数),新函数与被调函数(绑定函数的目标函数)具有相同的函数体(在 ECMAScript 5 规范中内置的call属性)。

fun.bind(指定的this值, 多个原函数的参数...)

示例:

this.x = 9; 
var module = {
  x: 81,
  getX: function() { return this.x; }
};
module.getX(); // 返回 81
var retrieveX = module.getX;
retrieveX(); // 返回 9, 在这种情况下,"this"指向全局作用域

// 创建一个新函数,将"this"绑定到module对象
// 新手可能会被全局的x变量和module里的属性x所迷惑
var boundGetX = retrieveX.bind(module);
boundGetX(); // 返回 81

高阶函数

  • 函数可以作为参数
  • 函数可以作为返回值
  • 闭包,函数内可以调用函数外的值,函数内可定义子函数并调用原函数的值。

箭头函数(ES6)

(参数1, 参数2, …, 参数N) => { 函数声明 }

(参数1, 参数2, …, 参数N) => 表达式(单一)
const x = (x, y) => x * y;
// 相当于:(参数1, 参数2, …, 参数N) =>{ return 表达式; }

当只有一个参数时,圆括号是可选的:

(单一参数) => {函数声明}
单一参数 => {函数声明}

没有参数的函数应该写成一对圆括号:

() => {函数声明}

当我们使用箭头函数的时候,箭头函数会默认帮我们绑定外层 this 的值,所以在箭头函数中 this 的值和外层的 this 是一样的。

箭头函数是不能提升的,所以需要在使用之前定义。

使用 const 比使用 var 更安全,因为函数表达式始终是一个常量。

如果函数部分只是一个语句,则可以省略 return 关键字和大括号 {},这样做是一个比较好的习惯:

箭头函数总是函数表达式;并不存在箭头函数声明。

对 => 的关注多数都在于从代码中去掉 function、return 和 { .. } 节省了那些宝贵的盘输入。但是,目前为止我们省略了一个重要的细节。这一节开头提到 => 函数与 this 绑定行为紧密相关。实际上,=> 箭头函数的主要设计目的就是以特定的方式改变 this 的行为特性,解决 this 相关编码的一个特殊而又常见的痛点。

var controller = { 
 makeRequest: function(..){ 
 var self = this; 
 btn.addEventListener( "click", function(){ 
 // .. 
 self.makeRequest(..); 
 }, false ); 
 } 
};

我们使用了 var self = this 这一 hack,然后引用 self.makeRequest(..),因为在我们传入 addEventListener(..) 的回调函数内部,this 绑定和 makeRequest(..) 本身的 this 绑定是不同的。换句话说,因为 this 绑定是动态的,我们通过变量 self 依赖于词法作用域的可预测性。

这里我们终于可以看到 => 箭头函数的主要设计特性了。在箭头函数内部,this 绑定不是动态的,而是词法的。在前面的代码中,如果使用箭头函数作为回调,this 则如我们所愿是可预测的。

var controller = { 
 makeRequest: function(..){ 
 btn.addEventListener( "click", () => { 
 // .. 
 this.makeRequest(..); 
 }, false ); 
 } 
}

前面代码的箭头函数回调中的词法 this 现在与封装的函数 makeRequest(..) 指向同样的值。换句话说,=> 是 var self = this 的词法替代形式。

对象

构造函数

相当于定义类:用this, 没有retuen,创建实例要用到new

function Person(name, age){
    this.name = name;
    this.age = age;
    this.sayName = function(){
        console.log(this.name);
    }
}

var p1 = new Person('Jack', 18)
p1.sayName();

在每一个实例对象中同时有一个 constructor 属性,该属性指向创建该实例的构造函数:

p1.constructor === Person // true

prototype

JavaScript 规定,每一个构造函数都有一个 prototype 属性,指向另一个对象。这个对象的所有属性和方法,都会被构造函数的所拥有。
这也就意味着,我们可以把所有对象实例需要共享的属性和方法直接定义在 prototype 对象上。(调高效率)

function Person (name, age) {
  this.name = name
  this.age = age
}

console.log(Person.prototype)

Person.prototype.type = 'human'

Person.prototype.sayName = function () {
  console.log(this.name)
}

var p1 = new Person(...)
var p2 = new Person(...)

console.log(p1.sayName === p2.sayName) // => true

prototype也有属性constructor 只想原函数(Person),复杂的prototype可这样定义,

为了保持 constructor 的指向正确,建议的写法是:

function Person (name, age) {
  this.name = name
  this.age = age
}

Person.prototype = {
  constructor: Person, // => 手动将 constructor 指向正确的构造函数
  type: 'human',
  sayHello: function () {...}
}

字符串模板

模板字面量使用反引号 (`) 而不是引号 ("") 来定义字符串,通过使用模板字面量,您可以在字符串中同时使用单引号和双引号,可以多行,可以用${...}引用变量与表达式:

let text = `Hello World!`;
let text = `He's often called "Johnny"`;

let text =
`The quick
brown fox
jumps over
the lazy dog`;

let firstName = "Bill";
let lastName = "Gates";

let text = `Welcome ${firstName}, ${lastName}!`;
let total = `Total: ${(price * (1 + VAT)).toFixed(2)}`;

IE不支持模板字面量。

异步

回调函数 callback

function myDisplayer(some) {
  document.getElementById("demo").innerHTML = some;
}

function myCalculator(num1, num2, myCallback) {
  let sum = num1 + num2;
  myCallback(sum);
}

myCalculator(5, 5, myDisplayer);

setTimeout(func, 1000) 就是最经典的回调函数与异步函数例子;或者setInterval(func, 1000) 每间隔Nms执行一次

以下是获取html页面并加载的回调

function myDisplayer(some) {
  document.getElementById("demo").innerHTML = some;
}

function getFile(myCallback) {
  let req = new XMLHttpRequest();
  req.open('GET', "mycar.html");
  req.onload = function() {
    if (req.status == 200) {
      myCallback(this.responseText);
    } else {
      myCallback("Error: " + req.status);
    }
  }
  req.send();
}

getFile(myDisplayer);

myDisplayer 是被回调的函数

promise

let myPromise = new Promise(function(myResolve, myReject) {
// "Producing Code"(可能需要一些时间)

  myResolve(); // 成功时
  myReject();  // 出错时
});

// "Consuming Code" (必须等待一个兑现的承诺)
myPromise.then(
  function(value) { /* 成功时的代码 */ },
  function(error) { /* 出错时的代码 */ }
);

在Promise接收一个函数作为采纳数,函数的两个参数是resolve与reject,若成功,调用resolve并将操作结果传出,见下:

function greet(){
    var promise = new Promise(function(resolve,reject){
        var greet = "hello  world";
        resolve(greet);  // 用resolve传出参数
    });
      return promise;
}
greet().then(v=>{
    console.log(v); //输出"hellow world"
})

.then方法是回调,输出还是promise,所以then后面还可以用then来继续异步操作

async/await

asycn与await是Promise的语法糖,async 使函数返回 Promise,await 使函数等待 Promise

async function myFunc() {
    let a = awiat doSomething1();
    let b = awiat doSomething2(); // 等doSomething1执行完后2才会执行,即异步
}

其中doSomething1和2需要是Promise?

DOM

查找 HTML 元素

方法描述
document.getElementById(id)通过元素 id 来查找元素
document.getElementsByTagName(name)通过标签名来查找元素
document.getElementsByClassName(name)通过类名来查找元素

改变 HTML 元素

方法描述
element.innerHTML = new html content改变元素的 inner HTML
element.attribute = new value改变 HTML 元素的属性值
element.setAttribute(attribute, value)改变 HTML 元素的属性值
element.style.property = new style改变 HTML 元素的样式

添加和删除元素

方法描述
document.createElement(element)创建 HTML 元素
document.removeChild(element)删除 HTML 元素
document.appendChild(element)添加 HTML 元素
document.replaceChild(element)替换 HTML 元素
document.write(text)写入 HTML 输出流

添加事件处理程序

方法描述
document.getElementById(id).onclick = function(){code}向 onclick 事件添加事件处理程序

cookie

cookie为保存在本地的名称值对,创建cookie:

document.cookie = "username=Bill Gates";
document.cookie = "username=Bill Gates; expires=Sun, 31 Dec 2017 12:00:00 UTC";
document.cookie = "username=Bill Gates; expires=Sun, 31 Dec 2017 12:00:00 UTC; path=/";

默认情况下,在浏览器关闭时会删除 cookie,通过 path 参数,您可以告诉浏览器 cookie 属于什么路径。默认情况下,cookie 属于当前页。

读取cookie:var x = docment.cookie 会返回所有cookie,可以通过负值直接修改cookie。

删除 cookie 非常简单。删除 cookie 时不必指定 cookie 值:直接把 expires 参数设置为过去的日期即可:

document.cookie = "username=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";

cookie是字符串,读取时用decodeURIComponent(document.cookie).split(';');

获取 cookie 的函数

然后,我们创建一个函数返回指定 cookie 的值:

function getCookie(cname) {
    var name = cname + "=";
    var decodedCookie = decodeURIComponent(document.cookie);
    var ca = decodedCookie.split(';');
    for(var i = 0; i <ca.length; i++) {
        var c = ca[i];
        while (c.charAt(0) == ' ') { //  若c字符串的第0个字符为' '
            c = c.substring(1); // 提取第1个到之后的字符,substring(from, to)为裁剪
         } // 还是用while循环去除字符串前所有空格
        
         if (c.indexOf(name) == 0) {
            return c.substring(name.length, c.length);
         }
     }
    return "";
} 

函数解释:

把 cookie 作为参数(cname)。

创建变量(name)与要搜索的文本(CNAME”=”)。

解码 cookie 字符串,处理带有特殊字符的 cookie,例如 “$”。

用分号把 document.cookie 拆分到名为 ca(decodedCookie.split(';'))的数组中。

遍历 ca 数组(i = 0; i < ca.length; i++),然后读出每个值 c = ca[i]。

如果找到 cookie(c.indexOf(name) == 0),则返回该 cookie 的值(c.substring(name.length, c.length)。

如果未找到 cookie,则返回 ""。

总Vue3

组件

组件的props (不要漏s)里面的属性名,因为html的attribute大小写不敏感,所以用驼峰命名的话,在html里要用横杠隔开,例如:prop:['userName'] 在html里要写<xxx user-name='val'></xxx>

组件内元素要监听事件(例如点击),要在对应元素加@click="$emit('eventname', para)",para是向上传出的参数,非必要。

在父级(写在html里的)元素添加@eventname="someFunction($event)" 来接收事件并处理,$event即传出的参数 para。

v-for与v-if共用

v-if比v-for优先级更高,所以在同一元素内,v-if不能访问v-for内变量,可以将v-for放到外部<template> 标签里面。

<template v-for="todo in todos" :key="todo.name">
  <li v-if="!todo.isComplete">
    {{ todo.name }}
  </li>
</template>

创建应用

Vue.js 的核心是一个允许采用简洁的模板语法来声明式地将数据渲染进 DOM 的系统:

<div id="counter">
  Counter: {{ counter }}
</div>
const Counter = {
  data() {
    return {
      counter: 0
    }
  }
}

Vue.createApp(Counter).mount('#counter')

data必须是函数形式,不能是对象,data() 属于是函数,与小程序很像。

组件化应用构建

在 Vue 中,组件本质上是一个具有预定义选项的实例。在 Vue 中注册组件很简单:如对 app 对象所做的那样创建一个组件对象,并将其定义在父级组件的 components 选项中:

const TodoItem = {
  template: `<li>This is a todo</li>`
}

// 创建 Vue 应用
const app = Vue.createApp({
  components: {
    TodoItem // 注册一个新组件
  },
  ... // 组件的其它 property
})

// 挂载 Vue 应用
app.mount(...)

为组件传参,用props与v-bind。prop为html元素添加属性,然后用v-bind绑定这个属性,例如下面的props:['todo'] ,则<todo-item v-bind:todo="变量名">{{todo}}</todo-item>这样显示的就是变量名对于变量的值。

const TodoItem = {
  props: ['todo'],
  template: `<li>{{ todo.text }}</li>`
}

现在,我们可以使用 v-bind 指令将待办项传到循环输出的每个组件中:

<div id="todo-list-app">
  <ol>
     <!--
      现在我们为每个 todo-item 提供 todo 对象
      todo 对象是变量,即其内容可以是动态的。
      我们也需要为每个组件提供一个“key”,稍后再
      作详细解释。
    -->
    <todo-item
      v-for="item in groceryList"
      v-bind:todo="item"
      v-bind:key="item.id"
    ></todo-item>
  </ol>
</div>
const ComponentsApp = {
  data() {
    return {
      groceryList: [
        { id: 0, text: 'Vegetables' },
        { id: 1, text: 'Cheese' },
        { id: 2, text: 'Whatever else humans are supposed to eat' }
      ]
    }
  }
}

const app = Vue.createApp(ComponentsApp)

app.component('todo-item', {
  props: ['todo'],
  template: `<li>{{ todo.text }}</li>`
})

app.mount('#components-app')
  • KoiCraft 相关文档
  • 前端笔记
取消回复

说点什么?
Title
Vue Note
交互方法
组件
生命周期钩子
模板语法
计算属性
条件渲染
用template分组渲染
v-show
事件处理
表单输入绑定
JavaScript
输出显示方法
块作用域
let
const
运算符
三元运算符
函数
function对象
arguments对象
高级函数
函数内 this 指向的不同场景
高阶函数
箭头函数(ES6)
对象
构造函数
prototype
字符串模板
异步
回调函数 callback
promise
async/await
DOM
查找 HTML 元素
改变 HTML 元素
添加和删除元素
添加事件处理程序
cookie
获取 cookie 的函数
总Vue3
组件
v-for与v-if共用
创建应用
组件化应用构建

© 2023 夜航船 · TOYOHAY Clouds. Using Typecho & Moricolor | 粤ICP备18131337号.