VUE 超级详细教程

16 篇文章 5 订阅
订阅专栏

From:https://blog.csdn.net/weixin_42371679/article/details/112408800

vue 源码阅读解析: https://zhuanlan.zhihu.com/p/419896443

深入理解vue底层原理: https://blog.csdn.net/dream2222222222/article/details/103256281

Vue 源码解读 ( 系列 ): https://juejin.cn/user/1028798616461326/posts

视频: https://search.bilibili.com/all?keyword=Vue.js源码全方位深入解析

一、安装

​​vue 爱好者: https://vue3js.cn/
vue 官网、文档、指南、教程

  • vue2 : https://v2.cn.vuejs.org/
  • vue3 : https://cn.vuejs.org/

二、基础练习

1)引入vue.js

解释: 

注意:被挂载的 div 要放在 vue 的上面,否则 vue 管不到

2)v-for

3)做一个计数器(v-on:click)

方法一:直接在标签里实现

    <div id="app">
       <h2>当前计数: {{count}}</h2>
       <button v-on:click="count++">+</button>
       <button v-on:click="count--">-</button>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        const bpp=new Vue({
            el: "#app",
            data : {
                count: 0,
                movices: ['one','two','three']
            }
        })
    </script>

方法二:采用函数(如果代码太多的话)

三、vue 中的 mvvm

四、vue的生命周期

五、各种标签

1)插值操作

mustache 语法(双大括号语法)

2)v-once

加了 v-once 后,值就不会改变了

 运行结果:

3)v-html

会将传递过来的html进行解析

运行结果:

4)v-pre 不让 {{}} 被 vue 解析

5)v-cloak

在 div 中加入 v-cloak 属性,可以让 div 在 vue 没解析之前不显示。v-cloak 在 vue 解析完之后就会消失

6)v-bind

绑定 url

​可以将 "vue 中的属性" 挂载到 "标签的属性" ​

绑定 class

动态绑定 class:可以绑定是否将class属性添加到标签中

另一种比较简洁的写法

绑定 style

绑定 disable

<!--当item为true时,button不起作用-->
<button :disable="item">按钮</button>

7)v-on 用于进行事件监听

v-on 的简单使用

<body>
    <div id="app">
       <h2>当前计数: {{count}}</h2>
       <button v-on:click="add">+</button>
       <button v-on:click="mid">-</button>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        const bpp=new Vue({
            el: "#app",
            data : {
                count: 0,
                movices: ['one','two','three']
            },
            methods: {
                add: function () {
                    console.log("add被执行");
                    this.count++
                },
                mid: function () {
                    console.log("mid被执行");
                    this.count--
                }
            }
        })
    </script>
</body>

v-on 的语法糖

<button @cick="add">+</button>
<button @cick="incr">-</button>

v-on 的参数问题

<body>
    <div id="app">
       <button @click="print('hello')">按钮</button>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        const bpp=new Vue({
            el: "#app",
            data : {
                count: 0,
                movices: ['one','two','three']
            },
            methods: {
                print(name){
                    console.log(name)
                }
            }
        })
    </script>
</body>

如果函数不是写在{{}}里面或者函数没有参数,则()可以省略

<button @click="print">按钮</button>

如果函数中有参数,但是没有传入参数的话,那么就将undefined传进去

 <button @click="print()">按钮</button>

如果函数中有参数,但是没有写()那么将点击事件传进去

 <button @click="print">按钮</button>

如果既要传递参数,又要获得event

<body>
    <div id="app">
       <button @click="print('hello',$event)">按钮</button>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        const bpp=new Vue({
            el: "#app",
            data : {
                count: 0,
                movices: ['one','two','three']
            },
            methods: {
                print(name,event){
                    console.log(name+'-----'+event)
                }
            }
        })
    </script>
</body>

v-on 的修饰符问题

.stop 停止该按钮的作用。停止某个事件的作用,如果不加 stop 修饰的话,点击按钮那某 divClick 也会起作用,这不是想要的,所以可以加上 stop 就阻止了

.prevent 阻止默认事件的发生。该例子阻止了表单的提交

监听某个键帽的作用。当按下回车的时候,才让函数起作用

 .once。让点击事件只起一次作用

8) v-if、v-else-if、v-else

9)v-show 和 v-if

<body>
    <div id="app">
        <h2 v-if="isShow">你好呀</h2>
        <h2 v-show="isShow">你好呀</h2>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        const app=new Vue({
            el:"#app",
            data:{
                isShow:true
            }
        })
    </script>
</body>

当 isShow 为 false 时,v-if 是直接被清除了,
而 v-show 则是多了个style=“display:none”

10)v-for 

遍历数组

<body>
    <div id="app">
        <ul>
            <li v-for="item in movices">{{item}}</li>
        </ul>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        const app=new Vue({
            el:"#app",
            data:{
                movices:['喜羊羊与灰太狼','熊出没','海贼王']
            }
        })
    </script>
</body>

遍历对象

<body>
    <div id="app">
        <ul>
            <li v-for="(value,key) in info">{{value}}-{{key}}</li>
        </ul>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        const app=new Vue({
            el:"#app",
            data:{
                movices:['喜羊羊与灰太狼','熊出没','海贼王'],
                info:{
                    name:"张三",
                    sex:"男",
                    age:180
                }
            }
        })
    </script>
</body>

v-for 绑定 和 非绑定key的区别

<div id="app">
    <ul>
        <li v-for="item in movices" key="item">{{item}}</li>
    </ul>
</div>

示例:

将数组遍历到页面上,然后点击

11)v-model

双向绑定

双向绑定:就是对属性值进行改变时,页面中展示的值跟着改变,对页面展示的值进行改变时,属性值也跟着改变。也就是:数据变化更新视图,视图变化更新数据

v-model 绑定各种类型

原理:v-model 其实就是一个语法糖,它的背后本质上是包含两个操作:

  • 1、v-bind 绑定一个value属性
  • 2、v-on 指令给当前元素绑定input事件

绑定 text 类型:

<body>
    <div id="app">
        <input type="text" :value="message" @input="btnClick">
        {{message}}
    </div>
    <script src="../js/vue.js"></script>
    <script>
        const app=new Vue({
            el:"#app",
            data:{
                message:"你好啊"
            },
            methods:{
                btnClick(event){
                    this.message=event.target.value
                }
            }
        })
    </script>
</body>

v-model 绑定 radio 类型:

<body>
    <div id="app">
        <input type="radio" v-model="sex" id="sex" value="男">男
        <input type="radio" v-model="sex" id="sex" value="女">女<br/>
        <h2>您选择的性别是:{{sex}}</h2>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        const app=new Vue({
            el:"#app",
            data:{
                message:"你好啊",
                sex:''
            }
        })
    </script>
</body>

绑定 checkbox:

<body>
    <div id="app">
        <h1>单选框</h1>
        <input type="checkbox" v-model="agree">同一协议<br/>
        <h2>您的选择是{{agree}}</h2>
        <button :disable="!agree">下一步</button>
        <h1>多选框</h1>
        <input type="checkbox" value="篮球" v-model="hobbies">篮球<br/>
        <input type="checkbox" value="足球" v-model="hobbies">足球<br/>
        <input type="checkbox" value="羽毛球" v-model="hobbies">羽毛球<br/>
        <input type="checkbox" value="乒乓球" v-model="hobbies">乒乓球<br/>
        <h2>您的选择是:{{hobbies}}</h2>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        const app=new Vue({
            el:"#app",
            data:{
                agree:false,
                hobbies:[]
            }
        })
    </script>
</body>

绑定 select:

<body>
    <div id="app">
        <select v-model="fruit">
            <option value="苹果">苹果</option>
            <option value="香蕉">香蕉</option>
            <option value="菠萝">菠萝</option>
            <option value="橘子">橘子</option>
        </select>
        <h2>您的选择是:{{fruit}}</h2>
        <select v-model="fruits" multiple>
            <option value="苹果">苹果</option>
            <option value="香蕉">香蕉</option>
            <option value="菠萝">菠萝</option>
            <option value="橘子">橘子</option>
        </select>
        <h2>您的选择是:{{fruits}}</h2>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        const app=new Vue({
            el:"#app",
            data:{
                fruit:"香蕉",
                fruits:[]
            }
        })
    </script>
</body>

值绑定:

就是动态地给 value 赋值,可以通过 v-bind 动态地给 value 绑定值

<body>
    <div id="app">
        <label v-for="item in books">
            <input type="checkbox" :value="item"  v-model="books">{{item}}<br/>
        </label>
        <h2>书籍有:{{books}}</h2>  
    </div>
    <script src="../js/vue.js"></script>
    <script>
        const app=new Vue({
            el:"#app",
            data:{
                books:['数据结构与算法','算法导论','编译原理','计算机网络','计算机组成原理']
            }
        })
    </script>
</body>

v-model 修饰符

.lazy  这个修饰符让v-model不用实时绑定,而是等到回车的时候才进行绑定

<input type="text" v-model.lazy="message">{{message}}

.number  这个修饰符让输入框中的值保持是数字,如果没有加这个修饰符那么即使让它的初始化是数字,输入多个数字时它会自动转为string类型

<input type="number" v-model.number="age">{{age}}--{{typeof age}}

.trim  这个修饰符用于去除左右两边的空格

<input type="text" v-model.trim="name">

六、计算属性

计算属性的优点:计算属性是有缓存的
使用它时不需要加(),因为它是当做一个属性来使用的

1)计算属性的简单使用

computed 属性的复杂操作

2)计算属性的 setter 和 getter

计算属性本质上是长这样的

computed:{
   fullName:{
        setter:function () {
            
        },
        getter:function () {

        }
    }
}

但是,一般是不写 setter 方法的,所以只是这样的

computed:{
   fullName:{
        getter:function () {

        }
    }
}

为了简写,所以一般看到的都是这样的

computed:{
   fullName:function () {

        }
    }
}

3)计算属性 和 methods 的比较

  • 计算属性是有缓存的,如果要多次显示计算属性的内容,计算属性只会被调用一次,
  • 而 methods 是没有缓存的,显示多少次,methods 就被调用多少次。

4)var 和 let 的比较

var 是函数作用域,let是块级作用域

var a = 1;
{
    var a = 2;
    //...
}
//...

对于一些开发者来说,希望使用大括号为任意代码块创建一个局部环境,但在JavaScript中,只有函数能够创建新的作用域。在上述代码中,代码块中的变量 a 其实引用的是代码块外部的那个同名变量,实际上,虽然 JavaScript 用于使用大括号创建代码块,但其作用仅限于在 if 语句或循环语句中组织代码体而已。在 ES6 中引出let关键字,就是为了解决这一问题。

var 是函数作用域,let 是块级作用域。比如在 for 循环内,用 var 声明变量,在 for 循环外也可以访问到,但 let 不同,若使用 let 在 for 循环内声明变量,那么在外部是访问不到的。如下:

//使用var声明变量
for (var i = 0; i < 10; i++) { }
console.log("i的值=" + i)
 
//使用let声明变量
for (let j = 0; i < 10; i++) { }
console.log("j的值=" + j)

var 存在变量提升,let 不存在变量提升

顶层对象:在浏览器中指的是 window,在 node 环境中指的是 global 对象。

  • var 声明的变量会被提升到 顶端对象,但是赋值的部分不会提升。( var 声明的变量属于顶层对象window,因此可以通过 window. 变量名 来访问这些变量, )
  • let 声明的变量不属于顶层对象。( let 和 const 声明的变量不能 顶层对象访问。 )

在使用关键字 var 声明变量时是存在的,var 可以先使用再声明,在变量没有被声明的时候,其值为 undefined;但在使用 let 关键字声明变量时,必须先声明再使用,否则会报错。如下:

//var的使用
console.log("还未被定义的a=" + a)
var a = 1;
console.log("已被定义的a=" + a)
 
//let的使用
console.log("还未被定义的b=" + b)
let b = 1;
console.log("已被定义的b=" + b)

var 变量可以重复声明,let 变量不可以重复声明

//var
var a = 1;
var a = 2;
console.log(a)
 
//let
let b = 1;
let b = 2;
console.log(b)  //报错

5)闭包

在《JS高级程序设计-第3版》中对闭包解释是:"闭包是指有权访问另外一个函数作用域中的变量的函数。" 闭包函数可以访问[包裹其的函数]内的各种参数和变量,即便外部函数已经执行完毕

官方对闭包的解释是:一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。

闭包的特点:

  • 1. 作为一个函数变量的一个引用,当函数返回时,其处于激活状态。
  • 2. 一个闭包就是当一个函数返回时,一个没有释放资源的栈区。

简单的说,javascript允许使用内部函数---即函数定义和函数表达式位于另一个函数的函数体内。而且,这些内部函数可以访问它们所在的外部函数中声明的所有局部变量、参数和声明的其他内部函数。当其中一个这样的内部函数在包含它们的外部函数之外被调用时,就会形成闭包。

为什么要闭包

  • 使外部得以访问函数内部的变量;
  • 避免全局变量的使用,防止全局变量污染(匿名函数);
  • 让某些关键变量得以常驻内存,免于被回收销毁(闭包函数);

让某些变量得以常驻内存

JavaScript 是自带垃圾回收机制的,对于函数来说,在其执行完毕后会被垃圾回收机制回收来进行内存释放,函数内部的局部对象 (各种变量之类) 也会被连同销毁,使内存中仅仅保存全局作用域。那么怎么让变量得以常驻内存 ?方法就是:将立即执行函数 与 闭包 结合。

1.原理

"闭包函数" 就是一个嵌套在父函数里面并且有使用父函数变量的子函数,闭包函数 的执行必定依赖于父函数提供的数据,但要是调用闭包函数时父函数已经被销毁,闭包函数怎么执行呢 ?

答案是没法执行,因为闭包函数所依赖的变量也都被销毁,总不能因为要执行闭包函数再把父函数提出来,不太合理。

所以不能就这么回收掉,但是保存整个父函数又有点离谱,所以 JavaScript 垃圾回收机制只会保存闭包函数在父函数中所依赖到的变量,这些被保存起来的变量不会被内存回收器回收,直到确认子函数不会再被调用 ( 子函数被删除或者失去指针 )为止;

类比一下,如果你学过 webpack 的话,应该会知道 webpack 在打包一个文件的时候会把这个文件依赖的所有文件一起打包,就是为了防止使用的时候出问题,垃圾回收机制是在删减的时候留下需要的,weboack 是在打包的时候加上需要的。

2. 为什么是 "立即执行函数" ?

为什么推荐用立即执行函数来配合闭包进行变量保存…

一开始我猜为了在闭包函数保存完需要的变量后父函数能被及时回收释放内存,才采用了匿名立即执行函数来作为闭包函数的父函数。因为立即执行函数自我回调执行完成后会被立即销毁回收,用一次就释放,节约内存 ( 但因为销毁快,外界无法引用其内部的变量 ),后来看到了一个例子,作者将使用了立即执行函数的闭包和没有使用立即执行函数的闭包进行了比较,让我改变了想法:

// 例1 :这个例子中没有使用立即执行函数;
function createFunction() {
    var Array = [];
    for( var i = 0; i<10; i++) {
    //将函数赋值给每个数组元素;
        Array[i] = function() {
            return i;
        };
    }
    return Array;
}

var aa = createFunction();
console.log(aa[0]()); //10
console.log(aa[1]()); //10

​由于作用域链的配置机制,因为每个函数的作用域链中保存的都是 createFunctions() 的活动对象,所以每个函数引用的都是活动对象中的同一个变量 i。
( 活动对象: 在JavaScript中,当一个函数被创建时最后一步便是活动对象推入作用域链,函数中访问一个变量时会从作用域链中搜索具有相应名字的变量,函数执行完后局部活动对象会被销毁,活动对象中包含了参数列表和arguments对象等属性。活动对象包含变量对象所有的属性 )
当 createFunctions() 函数执行结束返回后,变量 i 的值就已经固定为10,而每个函数保存的变量对象里的 i 都出自 createFunctions() 的活动对象,每个函数拿到的 i 都是出自同一个活动对象的,都一样,所以最后不论输出哪个数组元素得到的都是10.。

即说明了闭包中所保存的是整个活动对象,而不是某个具体的变量,这种机制并不是我们想要的,我们希望它能把每个变量单独保存下来,所以就有了能解决这个问题的,使用了立即执行函数的例子,即 例2:

function createFunction() {
    var result = new Array();
    for( var i = 0; i<10; i++) {
    
        result[i] = function(num) {
        //每接收一个num就会创建新的一个函数作用域;
            return function() {
            //在每个作用域的内部创建并返回一个返回num的闭包函数
                return num;
            };
        }(i);
     //变量i的当前值会作为实参赋值给上面的形参num;
     
    }
    return result;
}
//在外部使用函数内变量;
var bb = createFunction();
alert(bb[0]()); //0
alert(bb[1]()); //1

闭包函数依赖到了外部立即执行函数的 num,所以 num 会连同闭包函数被保存下来免于销毁,这样 result[ ] 中被赋值进去的每个函数都能返回一个自己的 num,我们的目的就能达到了,完成这一目标的关键就是使用了立即执行函数。

这个闭包函数的父函数函数每接收一个 num 就会创建新的一个函数作用域(见例3),作用域中传入i后,变量 i 的当前值会作为实参赋值给上面的形参 num,而在当前每个作用域的内部,又创建并返回了一个返回 num 的闭包函数。这样一来传入每个函数作用域中闭包函数的 num 就是不同的了。如此类推,被赋值进入 result 数组中的每个函数作用域都有一个自己 num (其实是时 num 副本),可以返回各自不同的数值了。

for(var i = 0; i < 5; i++) {
  abc(i);
};

function abc(i) {
  setTimeout(function() {
     console.log(i);            // 0 1 2 3 4 
  }, 200); 
}
//这里就相当于创建了5个函数作用域;

可见立即执行函数在保存变量时泛用性比普通函数强;

三、让外部得以访问函数内变量

外部访问函数内变量跟立即执行函数没什么必然关系,不使用立即执行函数也可以进行保存,上面说到的结合立即执行函数的写法只是针对某些特殊情况下无法依据需求保存变量的问题,我们不得不承认立即执行函数泛用性好一些。在外部调用父函数即可拿到闭包函数内的变量。

四、立即执行函数

//这两种写法是会报错的;
(function() {
//函数体;
 })(); 

function() {
//函数体;
 }();

JavaScript引 擎先看到了你的 "function" 关键字,然后就开始以函数声明标准规范你后续的代码,最终 JavaScript 引擎发现你用一个小括号结束了你的函数,它觉得这是错的。
我们不能否定它判定的规则,人家认为写了 function 就是要声明函数,那我们就不要上来直接写function了:

var myFunction = function () {
        /* 函数体 */ 
}();
var myObj = {
    myFunction: function () {  /* 函数体 */  }
}();

让 JavaScript 引擎先看到小括号而不是 function 关键字,它就会觉得你在写函数表达式,也就判定为合理了;

总结

闭包会造成内存泄漏。闭包会把一些东西永驻内存,而且前面提到的它所依赖的东西都不会被销毁,自己的局部活动对象和依赖到的活动对象都会被包含到它自己的作用域链里,所以它的体量往往是比普通函数大上老些。

6)ES6字面量增强写法

ES5 中,对象的书写形式

<script>
   const name='hello'
   const age=20
   const height=1.80
   const person={
       name:name,
       age:age,
       heigth:height
   }
   console.log(person)
</script>

ES6 中,对象的书写形式

<script>
  const name='hello'
  const age=20
  const height=1.80
  const person={
      name,
      age,
      height
  }
  console.log(person)
</script>

ES5 中,对象中方法的写法:

const demo={
    run:function () {
        
    }
}

ES6 中,对象中方法的写法:

const demo={
   run(){

   }
}

七、数组中哪些方法是响应式的

响应式就是直接在控制台上对数组中的元素进行增删改查时,页面中的展示会跟着变化。

1)push方法

从最后一位添加元素,可以一次性添加多个值

2)pop()

从最后一位删除元素

3)shift()

从第一位删除元素

4)unshift()

从第一位添加元素,可以一次性传入多个值unshift(…num)

5 )splice()

splice的作用:
删除:
splice(start,删除的元素个数) ,表示从start开始,要删除多少个元素;
splice(start)表示删除start开始后面的元素

替换:
splice(start,end,替换的元素)表示从start开始删除end个元素,然后再插入替换元素,可以替换多个元素

6)sort()

排序

7)reverse()

反转

八、过滤器

可以对内容进行修饰
格式:{{原本的内容 | 过滤器}}
例子:想要对价格的显示进行一些修饰,在前面添加¥符号和让它有两位小数显示

 filters:{
        priceFilter(price){
            return '¥'+price.toFixed(2)
        }
    }

九、JavaScript 高阶函数

1)filter

对数组中的数据进行过滤,满足条件的则放到新数组中

 const nums=[20,40,80,100,111,212,212]
 //filter
  const newNum1=nums.filter(function (n) {
      return n<100
  })

2)map

对数组中的数据进行处理后放到新数组里面

const nums=[20,40,80,100,111,212,212]
//2、map
const newNum2=newNum1.map(function (n) {
    return n*2
})

3)reduce

对数组中的数据进行累加

const nums=[20,40,80,100,111,212,212]
//3、reduce
const newNum3=nums.reduce(function (previousValue,n) {
   return previousValue+n
},0)  //初始值是0

十、组件

组件使用的步骤:

  • 1)创建组件构造器
  • 2)注册组件
  • 3)使用组件

例子:

<body>
    <div id="app">
        <my-cpn></my-cpn>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        //1、注册组件构造器
        const conC=Vue.extend({
            template: `
                <div>
                    <h2>我是标题</h2>
                    <p>我是内容,哈哈哈哈</p>
                    <p>我是内容,呵呵呵呵</p>
                </div>`
        })
        //2、注册组件
        Vue.component('my-cpn',conC)

        const app=new Vue({
            el:"#app",
            data:{

            }
        })
    </script>
</body>

1)全局组件 和 局部组件

它们的区别在于注册的方式

  • 全局组件 :可以被不同的 Vue实例 中的 dom 中使用
  • 局部组件 :只能在注册这个组件的 Vue 实例中的 dom 中使用

全局组件的注册方式

 Vue.component('my-cpn',conC)

局部组件的注册方式

在 vue 实例中注册

const app=new Vue({
            el:"#app",
            data:{
                cpn:conC
            }
        })

2)父组件 和 子组件

子组件在父组件的组件构造器中注册

3)组件注册的语法糖格式

不再需要单独写template,而是将组件构造器里的东西写到注册里面

4)模板抽离

前面注册的时候模板都是写在注册里的,非常难看,我们可以通过标签将模板写在这里面

5)组件中的数据访问

  • 子组件 不能直接访问 Vue实例里面的数据
  • vue组件 应该有自己保存数据的地方
  • 组件中的 data 是 function 格式的

6)组件中 data 只能是函数

因为一个组件一般都是被使用多次的,而使用函数的话它是会返回一个对象的,然后不同函数返回的对象就是不一样的,就不会导致每个组件都是在操作同一个数据,避免了数据的错误。如果它是用对象的话,那么多个组件就是在操作同一个数据,造成数据的错误。

<body>
    <div id="app">
        <cpn></cpn>
        <cpn></cpn>
    </div>
    <template id="cpn">
        <div>
            <h2>当前计数:{{counter}}</h2>
            <button @click="increment">+</button>
            <button @click="decrement">-</button>
        </div>
    </template>
    <script src="../../js/vue.js"></script>
    <script>
        Vue.component('cpn',{
            template:"#cpn",
            data(){
                return{
                    counter:0
                }
            },
            methods:{
                increment(){
                    this.counter++
                },
                decrement(){
                    this.counter--
                }
            }
        })
        const app=new Vue({
            el:"#app"
        })
    </script>
</body>

7)父子组件通信

组件之间经常协同工作,通常父子组件会是这样的关系:组件 A 在它的模版中使用了组件 B 。它们之间必然需要相互通信:父组件要给子组件传递数据,子组件需要将它内部发生的事情告知给父组件。

在 Vue.js 中,父子组件的关系可以总结为 props down, events up 。

  • 父组件通过 props 向下传递数据给子组件,
  • 子组件通过 events 给父组件发送消息。

父传子 ( 通过 props )

子传父

8)props 中的驼峰标识问题 

如果组件中的 data 是驼峰标识的,那么 dom 中需要用 来表示,否则会出错。

9)父子组件通信 --- 结合双向绑定

要求:将父组件中的数据传递到子组件中,然后在子组件中对数据进行改变后,可以将改变后的数据传递到父组件中。同时,要求父组件中显示的数据是子组件的2倍。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>父子组件通信-双向绑定</title>
</head>
<body>
    <div id="app">
        <cpn :number1="num1"
             :number2="num2"
             @num1change="num1change"
             @num2change="num2change"></cpn>
    </div>
    <template id="cpn">
        <div>
            <p>data:{{dnumber1}}</p>
            <p>props:{{number1}}</p>
            <input type="text" :value.number="dnumber1" @input="number1input" />
            <p>data:{{dnumber2}}</p>
            <p>props:{{number2}}</p>
            <input type="text" :value.number="dnumber2" @input="number2input" />
        </div>
    </template>
    <script src="../js/vue.js"></script>
    <script>
        const app=new Vue({
            el:"#app",
            data:{
                num1:0,
                num2:1
            },
            components:{
                cpn:{
                    template:"#cpn",
                    props:{
                        number1:Number,
                        number2:Number
                    },
                    data(){
                        return{
                            dnumber1:this.number1,
                            dnumber2:this.number2
                        }
                    },
                    methods:{
                        number1input(event){
                            this.dnumber1=event.target.value;
                            this.$emit('num1change',this.dnumber1);

                            this.dnumber2=this.dnumber1*100;
                            this.$emit('num2change',this.dnumber2)
                        },
                        number2input(event){
                            this.dnumber2=event.target.value;
                            this.$emit('num2change',this.dnumber2);

                            this.dnumber1=this.dnumber2/100;
                            this.$emit('num1change',this.dnumber1)
                        }
                    }
                }
            },
            methods:{
                num1change(value){
                    this.num1=parseFloat(value)
                },
                num2change(value){
                    this.num2=parseFloat(value)
                }
            }
        })
    </script>
</body>
</html>

10)父访问子

有两种方式:

  • 通过 $ children(很少用,一般在获取所有子组件的时候才会使用)
  • 通过 $ refs:

<body>
    <div id="app">
        <cpn></cpn>
        <cpn ref="aaa"></cpn>
        <button @click="btnClick">按钮</button>
    </div>
    <template id="cpn">
        <div>我是子组件</div>
    </template>
    <script src="../../js/vue.js"></script>
    <script>
        const cpn={
            template:"#cpn",
            data(){
              return {
                  name:"我是子组件中的name"
              }
            },
            methods:{
                showmessage(){
                    console.log('showmessage')
                }
            }
        };
        const app=new Vue({
            el:"#app",
            data:{
                message:'你好啊'
            },
            methods:{
                btnClick(){
                    //console.log(this.$children[0].name)
                    console.log(this.$refs.aaa.name)
                }
            },
            components:{
                cpn
            }
        })
    </script>
</body>

十一、插槽

插槽,其实就相当于 打桩,占个位置。

vue 中的插槽就是在组件的<template></template>标签中加入<slot></slot>标签,然后如果需要在这里面加入新的内容就可以直接添加

具名插槽

如果没有对插槽指定具体的名称,那么所有的插槽都会替换

运行结果:

加了名称,就会替换了那些加名称的

运行结果:

替换指定名称的插槽

十二、编译作用域

各种标签,属性的使用都是在本模板内起作用的

十三、插槽作用域

一般在组件中有默认的显示数据的方式。如果父组件调用了子组件,但是父组件并不想要子组件显示数据的方式,而是想要按照自己的方式显示数据,但是在父组件中是不能直接访问子组件中的数据的。所以可以采用插槽的方式来处理。

十四、模块化的 导出、导入

模块化有两个核心:导出和导入

模块 的 导出

module.exports={
    flag:true,
    test(a,b){
        return a+b
    },
    demo(a,b){
        return a*b
    }
}

模块 的 导入

//Commonjs的导入
let{test,demo,flag}=require('moduleA');
//等同于
let _mA=required('moduleA');
let test=_mA.test;
let demo=_mA.demo;
let flag=_mA.flag;

十五、ES6 的导出和导入

可以通过在<script>标签中加入type="module"属性来标志这个一个模块,就不会出现模块间数据冲突的问题

1)变量的导出和导入

2)函数/类的导出和导入

3)export default

一个模块只能有一个 export default,使用这个东西之后在导入时就可以自定义名称

十六、webpack

1)什么是 webpack

webpack是一个前端模块化打包工具
对于有些技术,浏览器是识别不了的,而通过webpack打包之后就可以转化为浏览器可以识别的东西

2)webpack 的安装

node和webpack和npm的关系:
webpack模块化打包;
webpack为了可以正常运行,必须依赖node环境;
node环境为了可以正常的执行化很多代码,必须其中包含各种依赖的包;
npm工具就是用来管理这些包的。

安装 node,node 安装完之后附带安装了 npm

安装 webpack。先安装淘宝镜像,因为 npm 的源在国外,速度很慢
https://blog.csdn.net/qq_38232598/article/details/91346993
可以通过npm get registry来获取npm源

全局安装 webpack:npm install webpack@3.6.0 -g

局部安装 webpack,–save-dev 是开发时依赖,项目打包后不需要继续使用
cd 对应目录,执行命令:npm install webpack@3.6.0 --save-dev

3)webpack 的基本使用

一般创建两个文件夹dist和src,dist放的是打包后的代码,src放的是我们原始代码

进入 src 所在的目录,然后执行以下指令进行打包:webpack ./src/main.js ./dist/bundle.js

4)webpack的配置

对入口和出口进行映射

对 webpack 进行映射

在package.json中可以对指令进行映射,然后执行npm run 映射的名称,如果在这里映射了webpack,那么使用映射后的指令默认优先使用本地安装的webpack,而不是全局的,而只要是使用webpack指令,那么使用的就是全局的。

5)loader

我们除了对js文件进行打包之外,还需要对其他文件进行打包,所以需要将其他文件导入到mian.js中,但是打包其他文件需要一些加载器
https://webpack.docschina.org/loaders/css-loader/

打包 css 文件

注意:安装时指定以下版本,否则可能会出错

安装 css-loadernpm install css-loader@2.0.2 --save-dev

安装 style-loader:npm install style-loader@0.23.1 --save-dev

可以在 package.json 中看到安装的具体版本信息

打包 less 文件

安装less-loader和less,其中less不是一个loader,而是为了将less解析为css

老规矩,指定具体版本:npm install less-loader@4.1.0 less@3.9.0 --save-dev

处理图片文件

安装 url-loader:npm install url-loader@1.1.2 --save-dev

当图片小于limit时,图片会被编译成base64的格式
当图片的大于limit时,需要再下载file-loader

6)将ES6转为ES5

在使用 webpack 进行打包时,还是不能将 ES6 转为 ES5,所以需要使用相应的 loader 对其进行转化。安装 babel-loader,babel-core 和 babel-preset-es2015(es2015也就是es6)

命令:npm install babel-loader@7 babel-core babel-preset-es2015 --save-dev

在webpack.config.js中添加如下配置

{
              test: /\.m?js$/,
              exclude: /(node_modules|bower_components)/,   //排除掉不是自己写的代码 
              use: {
                  loader: 'babel-loader',
                  options: {
                      presets: ['@babel/preset-env']
                  }
              }
          }

打包后的 bundle.js中的相关代码简单介绍

7)vue 的配置过程

安装 vue

npm install vue@2.5.21 --save-dev

导入vue

使用 runtime-only,使用 template 的问题

这是因为我们使用的是runtime-only版本的,它不允许有template,因为我们引入了vue实例,所以就有template,所以报错。
解决方法:在webpack.config.js中进行配置,让它可以找到compiler可以编译template

8)template 和 el 的区别

template里面的内容会被添加到el挂载的dom里面

十六、vue 的终极解决方案

运行结果:

改进 1

将 App 中的内容抽取之后写在一个js文件里

 export default{
    template: `
        <div>
            <h2>{{message}}</h2>
            <button @click="btnClick">按钮</button>
            <h2>{{name}}</h2>
        </div>  
    `,
    data(){
        return{
            message:"我是message",
            name:"我是name"
        }
    },
    methods:{
        btnClick(){
            console.log(this.message,this.name)
        }
    }
};

改进 2

将app.js文件内容放到App.vue里面(然后就不需要app.js了)

<template>
    <div>
        <h2>{{message}}</h2>
        <button @click="btnClick">按钮</button>
        <h2>{{name}}</h2>
    </div>
</template>

<script>
    export default {
        name: "App" ,
        data(){
            return{
                message:"我是message",
                name:"我是name"
            }
        },
        methods:{
            btnClick(){
                console.log(this.message,this.name)
            }
        }
    }
</script>

<style scoped>

</style>

然后需要加载vue-loadervue-template-compiler

因为版本太大的vue-loader需要安装相应的vue-loader应该低一点

npm install vue-loader@13.0.0 vue-template-compiler@2.5.21 --save-dev

在 webpack.config.js 中进行相应的配置

十七、plugin

1)什么是plugin

  • plugin 是插件的意思,通常是用于对某个现有的架构进行扩展。
  • webpack中的插件,就是对webpack现有功能的各种扩展,比如打包优化,文件压缩等。

2)loader 和 plugin 的区别

  • loade主要用于转换某些类型的模块,它是一个转换器
  • plugin是插件,它是对 webpack 本身的扩展,是一个扩展器

3)plugin 的使用过程

步骤一:通过npm安装需要使用的plugins(某些webpack已经内置的插件不需要安装)
步骤二:在webpack.config.js中的plugins中配置插件

例子:

3.1)横幅 plugin 的使用

这个是 webpack 自带的 plugin,所以直接引入就行了,不需要安装
在webpack.config.js中进行配置

在 bundle.js 中就多了这个东西

htmlwebpackplugin插件

在使用webpack打包后,html并不会打包进去,但是这个html确是我们需要使用的,所以就用到了htmlwebpackplugin插件

安装:npm install html-webpack-plugin@3.2.0 --save-dev

在 webpage.config.js 中进行相应的配置

问题:没有<div id="app"></div>这个模板
解决:在new htmlwebpackplugin()添加一个模板
更改index.html

在webpack.config.js中导入template

然后就能生成我们想要的 index.html了

压缩js的plugin

安装 uglifyjs-webpack-plugin:npm install uglifyjs-webpack-plugin@1.1.1 --save-dev

在webpack.config.js中进行相应的配置

十八、配置文件的抽离

将配置文件分为公共、开发和运行配置文件

需要安装webpack-merge:npm install webpack-merge@4.1.5 --save-dev

base.config.js

const path = require('path');   //动态地获取路径
const webpack=require('webpack');
const htmlwebpackplugin=require('html-webpack-plugin');
module.exports = {
    entry: './src/main.js',
    output: {
        path: path.resolve(__dirname, '../dist'),  //__dirname是一个全局变量,是node里面的东西
        filename: 'bundle.js'
    },
    module: {
        rules: [
            {
                test: /\.css$/i,
                use: ["style-loader","css-loader"],
            },
            {
                test: /\.less$/,
                use: [{
                    loader: "style-loader", // creates style nodes from JS strings
                }, {
                    loader: "css-loader" // translates CSS into CommonJS
                }, {
                    loader: "less-loader", // compiles Less to CSS
                }]
            },
            {
                test: /\.(png|jpg|gif)$/i,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            limit: 13000,
                        },
                    },
                ],
            },
            {
                test: /\.(png|jpe?g|gif)$/i,
                use: [
                    {
                        loader: 'file-loader',
                    },
                ],
            },
            {
                test: /\.m?js$/,
                exclude: /(node_modules|bower_components)/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        presets: ['es2015'],
                    }
                }
            }
        ],
    },
    resolve:{
        alias:{  //配置别名
            'vue$': 'vue/dist/vue.esm.js'  //让它可以去这个路径中找到compiler编译template
        }
    },
    plugins:[
        new webpack.BannerPlugin('最终版权归aaa所有!'),
        new htmlwebpackplugin({
            template:'index.html'
        })
    ]
};

prod.config.js

const UglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin')
const webpackMerge = require('webpack-merge')
const baseConfig = require('./base.config')

module.exports = webpackMerge(baseConfig, {
    plugins: [
        new UglifyjsWebpackPlugin()
    ]
})

然后在 package.json 中配置路径

十九、脚手架 ( 就是 命令行 )

1)脚手架的安装

CLI是什么意思:

  • CLI是command-Line Interface,翻译为命令行界面,但是俗称脚手架。
  • Vue Cli是一个官方发布vue.js项目脚手架。
  • 使用vue-cli可以快速搭建Vue开发环境以及webpack配置。

脚手架的前提:node
安装脚手架 vue cli,全局安装:cnpm install -g @vue/cli@3.2.1
查看版本:vue --version
如果想要使用vue2 的 脚手架,可以拉取脚手架2:npm install -g @vue/cli-init
Vue CLI2 初始化项目:vue init webpack my-project
Vue CLI3 初始化项目:vue create my-project

2)安装某个项目的脚手架

使用 cli2 初始化项目:vue init webpack my-project

cli 目录解析

运行vue cli2:npm run dev

vue cli2 和 vue cli3 的区别

使用 vue cli3 创建项目 命令:vue create vuecli3

生成的目录结构 

vue cli3 目录结构

运行 vue cli3

命令:npm run serve

输入以下网址就可以在网页上显示

3)runtime-compile 和 runtime-only 的区别

使用 runtime-compile 和 runtime-only 执行后的 mian.js 的区别:

runtime-compile的执行过程:template->ast->render->vdom->ui

runtime-only的执行过程:render->vdom->ui

区别:

  • 1)runtime-only的性能更高
  • 2)runtime-only的代码量更少

4)配置文件的查看和修改(使用vue ui管理)

配置文件的查看

启动配置服务器(在哪个目录启动都可以):vue ui

导入一个项目,进入到管理页面

看vue真实的版本要去打包之后的文件中看,而不是看源码里面的,可以在以下两个文件中查看

配置文件的修改

创建 vue.config.js(只能是这个名称)

二十、箭头函数

是ES6中一种定义函数的方式

1)参数问题

两个参数 写法:

const sum=(num1,num2)=>{
    return num1+num2;
}
console.log(sum(2,3));

一个参数 写法:

const power2 = num => { num*num;}

没有参数

const demo = ()=> {console.log("没有参数");}

2)this 指向的问题

在箭头函数中,this是向外层作用域中,一层一层向外找,直到有this

const obj={
    aaa(){
        setTimeout(function () {
            console.log(this);
        },1000);

        setTimeout(()=>console.log(this),1000);
    }
};
obj.aaa();

 const obj={
   aaa(){
       setTimeout(function () {
           setTimeout(function () {
               console.log(this);
           });
           setTimeout(()=>{
               console.log(this);
           });
       });
       setTimeout(()=>{
            setTimeout(function () {
                console.log(this);
            });
            setTimeout(()=>{
                console.log(this);
            });
       });
   }
};
obj.aaa();

二十一、html5 的 history 模式

1)pushstate()

history.push({},title,url)

它可以改变url,类似于栈,浏览器中地址栏显示的总是栈顶url

2)back()

history.back()

它类似于出栈操作,每次执行这个函数,都相当于执行浏览器中的返回操作

3)go()

history.go(数值)

数值如果是负数,则相当于浏览器中的返回操作,如果是正数,则相当于浏览器中的前进

4)forward()

history.forward()

相当于history.go(1)

5)关系

histrory.back()相当于history.go(-1)
history.forward()相当于history.go(1)

6)replaceState

history.replaceState({},title,url)
会替代上一个url,并且浏览器中不能通过前进或后退来回到之前的url

二十二、路由

1)前端渲染和后端渲染

后端渲染

就是将页面在服务器渲染完之后,将整个渲染好的页面传到浏览器,在浏览器中只能看到 html+css

后端路由

前端渲染

浏览器中显示的网页中的大部分内容,都是由前端写的 js 代码在浏览器中执行,最终渲染出来的网页。

前端路由

管理前端的页面,一个 url 对应一个组件

2)安装和配置 vue-router

搭建vue-router步骤:

(一)安装vue-router

命令:npm install vue-router@3.0.1 --save-dev

(二)在模块化工程中使用它(因为是一个插件, 所以可以通过Vue.use()来安装路由功能)

第一步:导入路由对象,并且调用 Vue.use(VueRouter)
第二步:创建路由实例,并且传入路由映射配置
第三步:在Vue实例中挂载创建的路由实例

index.js

import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'

//通过Vue.use(插件) 来安装插件
Vue.use(Router)

//创建并导出router,vue-router只有挂载到vue实例里面,才能生效
export default new Router({
  routes: [    //在这里面配置相关的映射信息
    {
      path: '/',
      name: 'HelloWorld',
      component: HelloWorld
    }
  ]
})

main.js

import Vue from 'vue'
import App from './App'
import router from './router'  //导入router

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,   //挂载router
  render: h => h(App)
})

3)使用vue-router步骤

第一步: 创建路由组件
第二步: 配置路由映射: 组件和路径映射关系

第三步: 使用路由: 通过<router-link><router-view>
<router-view>用于显示组件中的内容,如果没有<router-view>那么组件中的内容就显示不出来<router-view>写在哪,组件的内容就显示在哪

4)设置默认首页的路径

在index.js中的路由映射中进行配置

5)更改路径为history模式

在index.js中设置如下:

5)<router-link>属性

to 属性

这个用于跳转的,相当于<a></a>

tag 属性

这个用于指定这是个什么标签

replace

这个的作用相当于history.replaceState(),加了这个东西之后浏览器就不能进行前进或后退操作

active-class

<router-link>对应的路由匹配成功时, 会自动给当前元素设置一个router-link-active的class, 设置active-class可以修改默认的名称.
在index.js中进行设置

6)通过代码进行路由跳转

注意:这里不能用history.pushState(),因为它会绕过路由,而我们需要的是进行路由跳转

7)动态路由的使用

也就是在路径中进行传参

1)传值

在index.js的路由映射中配置

然后在App.vue中设置要传递的值

2)获取值

这个 this.$route 是在index.js中的routes[]中配置的其中一个,表示当前活跃的route

8)打包文件的解析

先打包项目:npm run build

9)路由懒加载

打包后的js,应用程序的代码全部都放在app.801c2ae2e69a05c33dfc65f8.js里面

使用懒加载之后

注册组件时,采用这种方式

打包后,每一个路由一个文件

10)路由嵌套

在一个组件中通过路由嵌套访问另一个组件的内容

使用步骤:

(一)创建被嵌套的组件

homeMessage.vue

<template>
  <div>
    <ul>
      <li>message1</li>
      <li>message2</li>
      <li>message3</li>
      <li>message4</li>
      <li>message5</li>
    </ul>
  </div>
</template>
<script>
  export default {
    name:'message'
  }
</script>

homeNew.vue

<template>
  <div>
    <ul>
      <li>new1</li>
      <li>new2</li>
      <li>new3</li>
      <li>new4</li>
      <li>new5</li>
    </ul>
  </div>
</template>
<script>
  export default {
    name:'new'
  }
</script>

(二)在 index.js 中进行路由映射配置

(三)使用路由: 通过<router-link><router-view><router-view>用于显示组件中的内容,如果没有那么组件中的内容就显示不出来写在哪,组件的内容就显示在哪

11)参数传递

主要有两种方式:params和query

params:

  • 配置路由格式: /router/:id
  • 传递的方式: 在path后面跟上对应的值
  • 传递后形成的路径: /router/123, /router/abc

query:

  • 配置路由格式: /router, 也就是普通配置
  • 传递的方式: 对象中使用query的key作为传递方式
  • 传递后形成的路径: /router?id=123, /router?id=abc

12)$route 和 $router 的区别

  • $router 为 VueRouter 实例,想要导航到不同 URL,则使用 $router.push 方法
  • $route 为当前 router 跳转对象里面可以获取 name、path、query、params 等

13)vue-router 的全局导航守卫

几个生命周期的回调函数

为什么要使用导航守卫?

前置守卫

导航钩子的三个参数解析:

  • to: 即将要进入的目标的路由对象.
  • from: 当前导航即将要离开的路由对象.
  • next: 调用该方法后, 才能进入下一个钩子

在index.js的路由映射中添加这个东西

后置钩子

不需要主动调用next()函数

14)vue 的生命周期

**created:**一个 dom 创建并初始化之后就回调这个函数

mounted: 将组件编译并渲染完成后回调这个函数

updated: 对组件有什么更新都会回调这个函数,只要不跳转到其他页面,就会一直循环

destoryed: 如果跳转到其他页面,就会回调这个函数

15)keep-alive

keep-alive可以让组件不被destroy

<keep-alive>
  <router-view/>
</keep-alive>

示例:在home这个页面中有两个组件,如果它现在页面中显示的是消息组件,而如果从home页面跳转到关于页面,那么这个home页面就会被destroy,如果再跳转回home页面,它自然就不会再显示消息组件了,因为它会重新被创建,而且它默认不是显示到消息组件的。而如果是不被destory,并且它被够在跳转回home页面时,记住home页面中的那个最后记录的地址,自然就能跳转回home页面跳转到其他页面前的最后的模样。

keep-alive的属性:

exclude属性:可以排除掉不想一直被保留的组件 

二十三、tabbar

1)tabbar 的实现思路

2)创建一个简单的 tabbar

App.vue

<template>
  <div id="app">
    <tab-bar>
      <tab-bar-item>
        <img slot="item-icon" src="./assets/img/tabbar/home.svg" alt="图片不见了"/>
        <div slot="item-text">首页</div>
      </tab-bar-item>
      <tab-bar-item>
        <img slot="item-icon" src="./assets/img/tabbar/category.svg" alt="图片不见了"/>
        <div slot="item-text">分类</div>
      </tab-bar-item>
      <tab-bar-item>
        <img slot="item-icon" src="./assets/img/tabbar/shopcart.svg" alt="图片不见了"/>
        <div slot="item-text">购物车</div>
      </tab-bar-item>
      <tab-bar-item>
        <img slot="item-icon" src="./assets/img/tabbar/profile.svg" alt="图片不见了"/>
        <div slot="item-text">我的</div>
      </tab-bar-item>
    </tab-bar>
  </div>
</template>

<script>
import TabBar from './components/tabbar/TabBar';
import TabBarItem from './components/tabbar/TabBarItem';
export default {
  name: 'App',
  components:{
    TabBar,
    TabBarItem
  }
}
</script>

<style>
  @import "./assets/css/base.css";

</style>

TabBar.vue

<template>
  <div id="tab-bar">
    <slot></slot>
  </div>
</template>

<script>
    export default {
        name: "TabBar"
    }
</script>

<style scoped>
  #tab-bar{
    display: flex;
    background-color: #f6f6f6;
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    box-shadow: 0 -1px 1px rgba(100,100,100,.08);
  }

</style>

TabBarIItem

<template>
  <div class="tab-bar-item">
    <slot name="item-icon"></slot>
    <slot name="item-text"></slot>
  </div>
</template>

<script>
    export default {
        name: "TabBarItem"
    }
</script>

<style scoped>
  .tab-bar-item{
    flex: 1;
    text-align: center;
    height: 49px;
  }

  .tab-bar-item img{
    height: 24px;
    width: 24px;
  }
</style>

3)插槽中设置一些属性

如果直接将属性添加在<slot></slot>上,那么在使用时,这些属性有些是会显示不出的,所以一般把这些属性写在它外面的<div></div>

4)tabbar与路由的配合

1、创建不同 tabbar 要显示的视图

2、将不同的视图在index.js中进行映射配置

import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
const home=()=>import('../view/home/home');
const category=()=>import('../view/category/category');
const profile=()=>import('../view/profile/profile');
const shopcart=()=>import('../view/shopcart/shopcart');
Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      redirect:'/home'
    },
    {
      path:"/home",
      component:home
    },
    {
      path:"/category",
      component: category
    },
    {
      path:"/shopcart",
      component:shopcart
    },
    {
      path:"/profile",
      component:profile
    }
  ]
})

3、在 TabBarItem 中配置配置路径跳转

4、在 App.vue 中传入不同 TabBarItem 对应的 path

二十四、promise

1)基本介绍

是一种异步编程的解决方案

在异步编程中,当网络请求非常复杂时,就会出现回调地狱。

我们来考虑下面的场景 ( 有夸张的成分 ):

  • 我们需要通过一个 url1 从服务器加载一个数据 data1,data1 中包含了下一个请求的 url2
  • 我们需要通过 data1 取出 url2,从服务器加载数据 data2,data2 中包含了下一个请求的 url3
  • 我们需要通过 data2 取出 url3,从服务器加载数据 data3,data3 中包含了下一个请求的 url4
  • 发送网络请求 url4,获取最终的数据 data4

promise 就可以用来解决这个问题

2)promise的简单使用

需求:在控制台上,每隔 1s 进行打印

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>promise的基本使用</title>
</head>
<body>
    <script>
       new Promise((resolve, reject) => {
           //第一次网络请求的代码
           setTimeout(()=>{
               resolve()
           },1000)
       }).then(()=>{
           //第一次拿到结果的处理代码
           console.log('hello world');
           console.log('hello world');
           console.log('hello world');
           console.log('hello world');
           console.log('hello world');
           console.log('hello world');

           return new Promise((resolve, reject) => {
               //第二次网络请求的代码
               setTimeout(()=>{
                   resolve()
               },1000)
           })
       }).then(()=>{
           //第二次处理的代码
           console.log('hello promise');
           console.log('hello promise');
           console.log('hello promise');
           console.log('hello promise');
           console.log('hello promise');
           console.log('hello promise');

           return new Promise((resolve,reject)=>{
               //第三次网络请求的代码
               setTimeout(()=>{
                   resolve()
               },1000)
           })
       }).then(()=>{
           console.log('hello vue');
           console.log('hello vue');
           console.log('hello vue');
           console.log('hello vue');
           console.log('hello vue');
           console.log('hello vue');
       })
    </script>
</body>
</html>

执行结果:

2022年前端面试必须学会的知识点-VUE篇(持续更新中...)
蜗牛的博客
01-13 945
一、对MVVM的理解 双向数据绑定,数据的改变会自动渲染到页面里,视图变化也会更新数据 二、双向数据绑定原理 采用数据劫持和发布订阅方式,通过Object.defineProperty()来劫持对象各个属性的getter/setter,在数据变化时,发布消息给订阅者,触发相应监听回调, 三、vue生命周期 vue的实例从开始创建,初始化数据,模板编译,挂载dom,渲染更新,卸载这一系列过程,会形成一系列事件钩子函数,方便操作 由于vue在初始化实例...
前端基础知识点-每天一个基本知识点(100+个前端小知识,你是否都知道?)
热门推荐
weixin_44181180的博客
02-21 2万+
文章目录前言第一回合一、知识点:cookie(21/09/06)二、知识点:节流和防抖(21/09/07)三、知识点:var和let以及const(21/09/08)四:知识点:深拷贝和浅拷贝(21/09/09)五、知识点:作用域和作用域联(21/09/10)六、知识点:从输入URL到页面展示这中间发生了什么(21/09/11)七、知识点:重排(21/09/12)八、知识点:TCP和UDP(21/09/13)九、知识点:三次握手(21/09/15)十、知识点:绝对和相对定位(21/09/16)十一、知识..
Vue从零开始,手把手教学( 附送250套精选项目源码)
梦之归途的博客
03-29 1286
Vue从零开始,手把手教学( 附送250套精选项目源码)
我的笔记(主要是尚品汇前台项目)
dadajingya的博客
01-05 1604
一、初始化项目 1.vue-cli 脚手架初始化项目、 2.node+ wabpake + 淘宝镜像 3.打开的新建的文件夹,在地址栏输入cmd ,打开小黑窗输入vue create app 初始化项目 二、项目的其他配置 二、项目的其他配置 1、项目运行起来的时候,设置浏览器自动打开(package.js) "scripts": { "serve": "vue-cli-service serve --open", // 设置浏览器自动打开 --open "build": "vue-cl
Vue 视频教程
04-28
Vue 视频教程 ThinkPHP5+Apicoud+vue商城APP实战 Apicloud+Vue开发App专题
vue教程
sslcsq的博客
03-29 3647
vue教程
Vue教程
皇家小骑士
08-05 2062
Vue安装与使用 Vue起步 Vue基本结构 Vue基本指令 Vue绑定样式 Vue循环指令 Vue条件语句 Vue过滤器 Vue按键修饰符 Vue自定义指令 Vue监听属性 Vue计算属性 Vue生命周期 Vue ajax 安装方法 get方法 post方法 axios API config配置 Vue动画 语法格式 过渡的类名 自定义过渡类名 JavaScript 钩子 列表过渡 过渡模式 组件过渡 Vue组件 全局组件注册 局部组件注册 外部定义 组件的数据和方法 父组件向子组件传值和方法 组件切换
Vue入门教程
Zz1366的博客
05-08 5563
Vue快速入门
超级简单的Vue使用typescript教程
最新发布
05-02
使用 Vue 与 TypeScript 可以让你享受到两者的优势,下面是一份超级简单的 Vue 使用 TypeScript 的教程: 1. 环境准备 确保你已经安装了 Node.js 和 npm(或 yarn)。然后安装 Vue CLI: npm install -g @vue/cli ...
一份超级详细Vue-cli3.0使用教程【推荐】
12-04
详细的搭建过程 重点推荐:使用图形化界面创建/管理/运行项目 安装: 卸载旧版本: 如果你事先已经全局安装了旧版本的 vue-cli (1.x 或 2.x),你需要先卸载它: npm uninstall vue-cli -g Node版本要求: 3.x需要在 ...
vue视频教程
08-06
vue视频教程
超级详细教程vue如何引用外部并使用Js文件的方法.docx
12-30
Vue基础,Js
VUE项目实战超级课堂 小码哥手把手带你学VUE开发 VUE提升到项目实战课堂 VUE视频教程
06-07
小码哥手把手带你学VUE开发课程,针对VUE在实际工作中用到的技术和项目进行了经验性的总结教学。课程融合了实战中使用的多种VUE开发技术,主要以项目全程的开发为主,更适合有一定基础和经验的同学们进行深度研习。...
VUE的使用教程
小翁的博客
07-19 1466
Vue.js 教程
u012115562的博客
11-23 388
Vue.js(读音 /vjuː/, 类似于 view) 是一套构建用户界面的渐进式框架。 Vue 只关注视图层, 采用自底向上增量开发的设计。 Vue 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件。 Vue 学习起来非常简单,本教程基于 Vue 2.1.8 版本测试。 Vue.js 安装 1、独立版本 我们可以在 Vue.js 的官网上直接下载 vue.min....
VUE简明教程
weixin_43952174的博客
01-27 7592
一:VUE基础 1: 项目搭建 VUE create 项目名称 1.1 创建步骤 1.2 使用空格键选择相应选项 上面两个选项随便选一个。 2: 运行项目 安装完后 进入项目的根目录,运行npm run serve即可启动项目 访问地址 localhost:8080 2:基本指令 2.1 声明式渲染 Vue.js 的核心是一个允许采用简洁的模板语法来声明式地将数据渲染进 DOM 的系统 。 Mustache {{}} vue在渲染界面时,页面先以{{xxXXX}}的形式加载到页面,然后再用
vue教程
k_shl_2011的博客
03-23 673
1.vue2.0基础入门2.vue环境搭建
Vue全套教程
weixin_44338156的博客
11-26 1929
1、初识Vuejs 1.1、为什么学习Vuejs? 可能你的公司正要用Vue将原项目重构 可能你的公司新项目决定使用Vue技术栈 可能你正在找工作,会发现十个前端八个对Vue有或多或少的要求 当然,最重要的是Vue非常火,很流行 1.2、简单认识Vuejs Vue(读音/vju:/ ,类似于view) Vue是一个渐进式框架 渐进式意味着你可以将Vue作为你应用的一部分嵌入其中,带来更丰富的交互体验 或者如果你希望更多的业务逻辑使用Vue实现,那么Vue的核心库及其生态系统; 比如Core + Vu
django+vue3详细教程
05-18
下面是一个基本的 Django + Vue3 教程: 1. 创建 Django 项目 首先,我们需要创建一个 Django 项目。打开终端并输入以下命令: ``` django-admin startproject myproject cd myproject ``` 这将创建一个名为 `...

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
写文章

热门文章

  • NAT 详解 137087
  • MFC 最详细入门教程 132828
  • tar 命令详解 126684
  • Cheat Engine 教程( 1 - 9 通关 ) 114706
  • Linux 用户、用户组 ( 添加、删除、修改 ) 104182

分类专栏

  • 视频教程 2篇
  • 汇编 17篇
  • ARM 汇编 4篇
  • Windows 编程 4篇
  • OllyDbg 20篇
  • IDA Pro 1篇
  • AirtestIDE 2篇
  • 游戏辅助 3篇
  • Android 7篇
  • Android 逆向 7篇
  • Hook 框架 之 Frida 8篇
  • APK 逆向
  • unidbg 2篇
  • Rust
  • C/C++ 37篇
  • C/C++笔记
  • boost 7篇
  • MFC 5篇
  • freeswitch 3篇
  • Python 41篇
  • Python 进阶 6篇
  • Python Twisted 2篇
  • Python GUI 6篇
  • Python 爬虫 46篇
  • Git 3篇
  • Linux 23篇
  • Shell 36篇
  • Linux 网络编程 2篇
  • Linux shell 命令
  • go 2篇
  • Java 5篇
  • HTML5 2篇
  • Javascript 16篇
  • 爬虫 --- JavaScript 逆向 2篇
  • PHP 3篇
  • Node.js 3篇
  • Dos 7篇
  • SQL 6篇
  • Web 10篇
  • Redis 4篇
  • RabbitMQ 1篇
  • ELK 日志分析 6篇
  • MongoDB 2篇
  • CCIE 2篇
  • Kali 5篇
  • 渗透测试 13篇
  • 正则表达式 2篇
  • 设计模式 8篇
  • 算法与数据结构 3篇
  • 工具 34篇
  • 协议 4篇
  • 搜索引擎 1篇
  • Docker 2篇

最新评论

  • Python 多进程:multiprocessing、aiomultiprocess(异步多进程)

    雕沙: 有个地方可能写错了。在异步多进程的栏目中,异步方法里面的函数体在同步函数前面加了await。 async def async_worker(data): await do_something_async(data) 但是do_something_async(data)是一个同步函数定义。是否应该在这个函数名前面加一个async do_something_async,这样才正确。

  • 安卓逆向_2 --- Androidkiller,apktool、dex2jar、jd-gui、jadx、jeb、gda

    admin:: ak和JADX的区别是什么呢

  • C++ 网络库:libevent、libev、libuv、poco、libhv、asi、ace、QUIC 协议

    yandong634: 这样比较挺清晰的

  • 安装 Kali NetHunter (完整版、精简版、非root版)、实战指南、ARM设备武器化指南、andrax、安卓渗透drozer

    邹业桐: 冒味问一下,andrax怎么安装内核?

  • api 接口测试工具:Postman、Apifox、Apipost、api压测(locust)、locust爬虫

    YDigest: 图片看不清表情包

大家在看

  • Go模块(GO111MODULE=on) 101
  • RK3568平台(camera篇)V4L2查询获取设置设备 624
  • thingsboard物联网平台快速入门教程 292
  • Dubbo源码解读-Dubbo启动、下线过程,以及优雅下线解决方案 1990
  • 本地源码方式部署启动MaxKB知识库问答系统,一篇文章搞定! 1026

最新文章

  • CTF 工具 集合
  • 安装 Kali NetHunter (完整版、精简版、非root版)、实战指南、ARM设备武器化指南、andrax、安卓渗透drozer
  • Qt/PySide6 设计师:designer
2024年12篇
2023年21篇
2022年30篇
2021年27篇
2020年55篇
2019年103篇
2018年40篇
2017年96篇
2016年53篇

目录

目录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值

深圳SEO优化公司乐山网站定制柳州关键词按天计费价格宁德营销网站报价绵阳网站优化软件推荐乐山如何制作网站推荐惠州seo网站优化报价海东百度标王哪家好永新百度网站优化排名公司淮南网络广告推广多少钱伊犁seo网站优化公司随州模板网站建设哪家好铁岭网站推广系统公司杭州seo排名公司东莞SEO按天收费哪家好漯河网站seo优化价格合肥百度网站优化推荐金昌百姓网标王推广价格昌都百搜标王公司泸州百姓网标王推广哪家好益阳百度seo推荐连云港百度竞价推荐绵阳网站推广武汉网站优化按天计费价格东莞网站制作哪家好南昌SEO按效果付费多少钱惠州百度竞价报价辽阳品牌网站设计镇江关键词排名公司乐山网络推广哪家好平顶山百度seo价格歼20紧急升空逼退外机英媒称团队夜以继日筹划王妃复出草木蔓发 春山在望成都发生巨响 当地回应60岁老人炒菠菜未焯水致肾病恶化男子涉嫌走私被判11年却一天牢没坐劳斯莱斯右转逼停直行车网传落水者说“没让你救”系谣言广东通报13岁男孩性侵女童不予立案贵州小伙回应在美国卖三蹦子火了淀粉肠小王子日销售额涨超10倍有个姐真把千机伞做出来了近3万元金手镯仅含足金十克呼北高速交通事故已致14人死亡杨洋拄拐现身医院国产伟哥去年销售近13亿男子给前妻转账 现任妻子起诉要回新基金只募集到26元还是员工自购男孩疑遭霸凌 家长讨说法被踢出群充个话费竟沦为间接洗钱工具新的一天从800个哈欠开始单亲妈妈陷入热恋 14岁儿子报警#春分立蛋大挑战#中国投资客涌入日本东京买房两大学生合买彩票中奖一人不认账新加坡主帅:唯一目标击败中国队月嫂回应掌掴婴儿是在赶虫子19岁小伙救下5人后溺亡 多方发声清明节放假3天调休1天张家界的山上“长”满了韩国人?开封王婆为何火了主播靠辱骂母亲走红被批捕封号代拍被何赛飞拿着魔杖追着打阿根廷将发行1万与2万面值的纸币库克现身上海为江西彩礼“减负”的“试婚人”因自嘲式简历走红的教授更新简介殡仪馆花卉高于市场价3倍还重复用网友称在豆瓣酱里吃出老鼠头315晚会后胖东来又人满为患了网友建议重庆地铁不准乘客携带菜筐特朗普谈“凯特王妃P图照”罗斯否认插足凯特王妃婚姻青海通报栏杆断裂小学生跌落住进ICU恒大被罚41.75亿到底怎么缴湖南一县政协主席疑涉刑案被控制茶百道就改标签日期致歉王树国3次鞠躬告别西交大师生张立群任西安交通大学校长杨倩无缘巴黎奥运

深圳SEO优化公司 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化