VUE学习笔记 coderwhy老师(持更)

一、邂逅Vue.js

1.1. 认识Vue.js

  • Vue的读音:(/vju:/,类似于view)
  • Vue的渐进式
    • 渐进式意味着你可能将Vue作为你应用的一部分嵌入其中,带来更丰富的交互体验
    • 或者如果你希望将更多的业务逻辑使用Vue实现,那么Vue的核心库以及其生态系统比如Core+Vue-router+Vuex,也可以满足你各种各样的需求
  • Vue的特点
    • 解耦视图和数据
    • 可复用的组件:一个组件可以在多个页面 里面用
    • 前端路由技术
    • 状态管理
    • 虚拟DOM

1.2. 安装Vue

  • CDN引入
  • 下载引入
  • NPM安装

1.3.Vue初体验

1.3.1 Hello Vue.js

01-HelloVuejs.html




  
  Title

Hello {{message}}

运行结果

在这里插入图片描述

1.3.2 vue列表展示.html

02-vue列表展示.html




  
  Title


  • {{item}}
{{movies}}

运行结果

VUE学习笔记 coderwhy老师(持更)_第1张图片

  • mustache 体验Vue响应式

  • Vue列表展示

    • movies:[‘大话西游’,‘星际穿越’,‘少年派’,‘违背’]

    • v-for

      • {{movies}}
        
        • [ “大话西游”, “星际穿越”, “少年派”, “违背” ]
      • {{item}}
        • 大话西游
        • 星际穿越
        • 少年派
        • 违背
    • 后面的数组追加元素的时候,新的元素也可以在界面上渲染出来,并且是响应式的

      • app.movies.push(‘同心难改’);

1.3.2 Vue计数器小案例

03-vue案例-计数器.html




  
  Title


当前计数: {{counter}}

运行结果
VUE学习笔记 coderwhy老师(持更)_第2张图片

  • 事件监听:v-on:click="" 或者@click
    • 该指令用于监听某个元素的点击事件,并且需要指定当发生点击时,执行的方法,方法通常是methods中定义的方法
  • 语法糖:@click是v-on:click的语法糖

1.4.MVVM

  • Model(JS)+View(DOM) +ViewModel(VUE)

  • View层

    • 视图层
    • 在我们前端开发中,通常就是DOM层
    • 主要的作用是给用户展示各种信息
  • Model层

    • 数据层
    • 数据可能是我们固定的数据,更多的是来自我们服务器,从网络上请求下来的数据
    • 在我们计数器的案例中,就是后面抽取出来的obj,当然,里面的数据可能没有这么简单
  • ViewModel层

    • 视图模型层
    • 视图模型层是view和Model沟通的桥梁
    • 一方面它实现了Data Binding,也就是数据绑定,将Model的改变实时的反应到View中
    • 另一个方面它实现了DOM Listener,也就是DOM监听,当DOM发生一些事件(点击、滚动、touch等)时,可以监听到,并在需要的情况下改变对应的Data

1.5.创建Vue时,options中的要素

  • el:

    document.querySelector(HTMLElement)

    类型:String|HTMLElement

    作用:决定之后Vue实例会管理哪一个DOM

  • data:

    类型:Object|Function(组件中必须是一个函数)

    作用:Vue实例对应的数据对象

  • methods:

    类型:{[key:string]: Function}

    作用:定义属于Vue的一些方法,可以在其他地方调用,也可以在指令中使用

  • 方法和函数

    • 方法:methods,和某一个实例相挂钩的
    • 函数:funcation
  • 生命周期函数

    • 生命周期:事物从诞生到消亡的整个过程
    • git: debug:开发版本 release:发布版本

二、插值语法

  • 插值操作:定义了一个数据,希望把这个数据C插入到DOM里面

2.1 mustache语法

  • mustache语法中不仅仅可以直接写变量,也可以写简单的表达式

    01-Mustache语法.html

    
    
    
      
      Title
    
    
    

    {{ message }}

    {{ message }},李银河

    {{ firstName + lastName }}

    {{ firstName + ' ' + lastName }}

    {{ firstName}} {{lastName}}

    {{ counter * 2}}

运行结果

VUE学习笔记 coderwhy老师(持更)_第3张图片

2.2 v-once

  • 在开发中,有时候只需要第一次的时候去改变,之后在改变

  • 该指令后面不需要跟任何表达式(比如v-for后面是要跟表达式的)

  • 该指令表示元素和组件只渲染一次,不会随着数据的改变而改变

    02- v-once的使用.html

    
    
    
      
      Title
    
    
    

    {{ message }}

    {{ message }}

运行结果

VUE学习笔记 coderwhy老师(持更)_第4张图片

2.3 v-html

  • 某些情况下,我们从服务器请求到的数据本身就是一个HTML代码,如果我们直接通过{{}}来输出,会将HTML代码也一起输出

  • 此时,我们可以使用V-htm指令

    • 该指令后面往往会跟上一个String 类型
    • 会将String的html格式进行解析,并且显示对应的内容

    03-v-html的使用.html

    
    
    
      
      Title
    
    
    

2.4 v-text

  • v-text作用和Mustache比较相似:都是用于将数据显示在页面中

  • v-text通常情况下,接受一个string类型

    04-v-text的使用.html

    
    
    
      
      Title
    
    
    

    {{ message }},李银河

    ,李银河

2.5 v-pre

  • v-pre用于跳过这个元素和它子元素的编译过程,用于显示原本的Mustache语法

    
    
    
      
      Title
    
    
    

    {{ message }}

    {{ message }}

    运行结果

VUE学习笔记 coderwhy老师(持更)_第5张图片

2.6 v-cloak

  • 在某些情况下,我们浏览器可能会直接显示出未编译的Mustache标签

    
    
    
      
      Title
      
    
    
    
    {{ message }}

三、动态绑定属性

3.1 v-bind绑定基本属性

  • 前面学习的指令主要作用是将值插入到我们模板的内容当中

  • 但是,除了内容需要动态来决定外,某些属性我们也希望动态来绑定

    • 比如动态绑定a元素的href属性
    • 比如动态绑定img元素的src属性
  • 这个时候,我们可以使用v-bind指令:

    • 作用:动态绑定属性
  • v-bind用于绑定一个或多个属性值,或者向另一个组件传递props值,在开发中,图片的链接src、网站的链接href,动态绑定的一些类、样式等等

  • v-bind :str

  • v-bind:href可简写为: href

    
    
    
      
      Title
    
    
    
    
    
    
    
    

​ 运行结果
VUE学习笔记 coderwhy老师(持更)_第6张图片

3.2 v-bind动态绑定class

3.2.1 对象语法:Class后面跟的是一个对象

  • 基本绑定

    {{message}}

  • 动态绑定(多此一举)

    {{message}}

  • 后面跟对象(title是固定的,active和line是不固定的)

    {{message}}

    {{message}}

  • 如果过于复杂,可以放在一个methods或者computed中

    {{message}}

    getClasses : function(){ return {active: this.isActive, line :this.isLine}; }

    02-v-bind动态绑定class属性(对象语法).html

    
    
    
      
      Title
      
    
    
    

    {{message}}

    {{message}}

3.2.2 数组语法:Class后面跟的是一个数组

  • 可以传入多个值

    {{ message }}

  • 如果过于复杂,可以放在一个methods或者computed中

    {{ message }}

    methods: { getClasses: function () { return [this.active, this.line]; } }

    03-v-bind动态绑定class属性(数组语法).html

    
    
    
      
      Title
      
    
    
    

    {{message}}

    {{message}}

3.3 v-bind动态绑定style

3.3.1 对象语法

  • style后面跟的是一个对象类型,对象的key四CSS属性名称;对象的value是具体赋的值,值可以来自于data中的属性



  
  Title


{{ message }}

{{ message }}

运行结果

VUE学习笔记 coderwhy老师(持更)_第7张图片

3.3.2 数组语法

  • style后面跟的是一个数组类型,多个值以","分割即可

    {{ message }}

    data:{ message: '你好!', baseStyle: { backgroundColor: 'red'}, baseStyle1: {fontSize : '100px'} }

    06-v-bind动态绑定style(数组语法).html

    
    
    
      
      Title
    
    
    

    {{ message }}

    {{ message }}

四、计算属性

4.1 计算属性的基本属性

  • 在模板中可以直接通过插值语法显示一些data中的数据,但是在某些情况下,我们可能需要对数据进行一些转化后再显示,或者需要将多个数据结合起来进行显示,比如我们有firstName和lastName两个变量,我们需要显示完整的名称,但是如果多个地方都需要显示完整的名称,我们就需要写多个{{firstName}}{{lastName}},此时,我们便可以使用计算属性

    01-计算属性的基本使用.html

    
    
    
      
      Title
    
    
    

    {{ firstName + ' ' +lastName }}

    {{ firstName}} {{ lastName }}

    {{ getFullName() }}

    {{ fullName }}

    运行结果
    VUE学习笔记 coderwhy老师(持更)_第8张图片

4.2 计算属性的复杂操作

02-计算属性的复杂操作.html




  
  Title


{{ totalPrice }}

运行结果

在这里插入图片描述

  • 补充ES6

    for (let i  in this.books)
    for (let book of  this.books)
    

4.3 计算属性的getter和setter

  • 每一个计算属性都包含一个getter和setter

    03-计算属性的setter和getter.html

    
    
    
      
      Title
    
    
    
    {{ fullName }}

运行结果

在这里插入图片描述

4.2 计算属性和methods对比

  • 计算属性在多次使用时,只会调一次,它是有缓存的,methods在多次使用时,会调用多次,是没有缓存的,性能较低

    04-计算属性和methods的对比.html

    
    
    
      
      Title
    
    
    

    {{ firstName }} {{lastName}}

    {{ getFullName() }}

    {{ getFullName() }}

    {{ getFullName() }}

    {{ getFullName() }}

    {{ fullName }}

    {{ fullName }}

    {{ fullName }}

    {{ fullName }}

    运行结果

VUE学习笔记 coderwhy老师(持更)_第9张图片

五、ES6补充

5.1 let/var

  • ES5中的var是没有作用域的,ES6中的var是有块级作用域的
  • ES5之前因为if和for都没有块级作用域的概念,所以在很多时候,我们必须借助于funcation的作用域来解决应用外面变量的问题,ES6中,加入了let,他是有if和for的块级作用域的

5.2 Const

  • 一旦给const修饰的标识符被赋值后,不能修改

  • 在使用const定义标识符,必须进行赋值

    const name;//×
    
  • 常量的含义是指向的对象不能修改,但是可以改变对象内部的属性

    const obj = {
       name : 'Kobe',
       age : 18,
       height :1.88
    }
    
    console.log(obj);
    
    obj.name ='Kobe';
    obj.age = 10,
    obj.height='1.88'
    

5.3 对象字面量的增强写法

  • 属性的增强写法

      const name = 'why';
      const age = '18';
      const height = '1.88';
    
     //ES5 的写法
      const obj = {
        name : name,
        age : age ,
        height : height
      }
      //ES6的写法
      const obj = {
         name,
         age ,
        height
      }
      console.log(obj);
    
  • 函数的增强写法

    //ES5的增强写法
      const obj = {
        run : function () {
          console .log ('在本派');
        },
        eat : function () {
          console.log ("在吃东西");
        }
      }
      
      //ES6的增强写法
    
      const obj = {
        run () {
    
        },
        eat () {
    
        }
    

六、事件监听

6.1 v-on的基本使用

  • v-on介绍

    • 作用:绑定事件监听器
    • 缩写:@
    • 预期:Function|Inline Statement|Object
    • 参数:event

    01-v-on的基本使用.html

    
    
    
      
      Title
    
    
    
    {{ counter }}

    运行结果

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ndZ5Hz8H-1644828620582)(C:\Users\JMS\AppData\Roaming\Typora\typora-user-images\image-20220214110659841.png)]

6.2 v-on的参数问题

02-v-on的参数问题.html




  
  Title



  • 事件调用的方法没有参数参数传递进去

    • 如果该方法不需要额外参数,那么方法后的()可以不添加,如果方法本身有一个参数,那么会默认将原生事件event传递进去
    
    
    
  • 事件调用的方法有event事件参数

    
    
    
    
    
  • 事件调用的方法有event对象和其他参数

    
    
    
    

6.3 v-on修饰符

  • stop:阻止冒泡

  • prevent:阻止默认行为

  • enter:监听键盘的键帽的点击

  • once:只触发一次回调

  • native:监听组件根元素的原生事件

    03-v-on修饰符.html

    
    
    
      
      Title
    
    
    
    aaaaaaaa

七、条件判断

7.1 v-if的使用.html

01-v-if的使用.html




  
  Title


{{ message }}

运行结果

在这里插入图片描述

7.2 v-if和v-else结合使用.html

02-v-if和v-else结合使用.html




  
  Title


abc
abc
abc
abc
abc
{{ message }}

isShow为fasle时,显示

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-97uBjzj2-1644828620584)(C:\Users\JMS\AppData\Roaming\Typora\typora-user-images\image-20220214142438229.png)]

7.12 v-if/v-else-if/v-else的使用

  • Vue的条件指令可以根据表达式的值在DOM中渲染或销毁元素或组件

  • v-if的原理

    • v-if后面的条件的为false时,对应的元素以及其子元素不会渲染,也就是根本没有不会有对应的标签出现在DOM中

    03-v-if和v-else-if和v-else的使用.html

    
    
    
      
      Title
    
    
    

    优秀

    良好

    及格

    不及格

    {{result}}

    运行结果

VUE学习笔记 coderwhy老师(持更)_第10张图片

7.2 登录小案例

  • 如果我们在有输入内容的情况下,切换了类型,我们会发现文字依然显示之前的输入内容

  • 这是因为Vue在进行DOM渲染时,出于性能考虑,会尽可能的复用已经存在的元素,而不是重新创建新的元素

  • 如果我们不希望Vue出现类似重复利用的问题,可以给对应的input添加key,并且我们需要保证Key的不同

    
    
    
      
      Title
    
    
    

    运行结果

VUE学习笔记 coderwhy老师(持更)_第11张图片

7.3 v-show的使用

  • v-show和v-if 的区别

    • v-if当条件为false时,压根不会有对应的元素在DOM中
    • v-show当条件为false时,仅仅是将元素的display属性设置为none而已
    • 当需要在显示和隐藏之间切换很频繁时,使用v-show,当只切换一次时,通过使用v-if

    06-v-show的使用.html

    
    
    
      
      Title
    
    
    

    {{ message }}

    {{ message }}

    运行结果

VUE学习笔记 coderwhy老师(持更)_第12张图片

八、循环遍历

8.1 v-for遍历数组

  • v-for的语法类似于JavaScript中的for循环,格式:item in items的形式

  • 如果在遍历的过程中不需要使用索引值

    • v-for =“movie in movies”,依次从movies中取出movie,并且在元素的内容中,我们可以使用Mustache语法,来使用movies
  • 如果在遍历的过程中,我们需要拿到元素在数组的索引

    • v-for=(item,index) in items,其中index就代表了取出的item在原数组的索引值

    01-v-for遍历数组.html

    
    
    
      
      Title
    
    
    
    
    • {{item}}
    • {{index+1}}.{{item}}

​ 运行结果

VUE学习笔记 coderwhy老师(持更)_第13张图片

8.2 v-for遍历对象

  • 在遍历对象的过程中,如果只是获取一个值,那么获取的是value

    • {{item}}
  • 获取key和value,格式:(value,key)

    • {{value}}-{{key}}
  • 获取key、value和index,格式:(value, key, index)

    • {{value}}-{{key}}-{{index}}

02-v-for遍历对象.html




  
  Title


  • {{item}}
  • {{value}}-{{key}}
  • {{value}}-{{key}}-{{index}}

运行结果

VUE学习笔记 coderwhy老师(持更)_第14张图片

8.3 数组的方法是响应式的

  • 通过索引值修改数组的元素不是响应式的

  • push():数组最后添加元素

    this.letters.push('aaa')*/
    this.letters.push('aaa','bbb','vvv')
    
  • pop():删除数组中的最后一个元素

    this.letters.pop();
    
  • shift():删除数组中的第一个元素

    this.letters.shift();
    
  • unshift():给数组最前面添加元素

    //this.letters.unshift('aaa');
    //this.letters.unshift('aaa','bbb','vvv')
    
  • splice()

    • 删除元素:第二个参数传入你要删除几个元素(如果没有传,就删除所有的元素)
    • 替换元素:第二个参数,表示我们要替换几个元素,后面是用于替换前面的元素
    • 插入元素:第二个参数,传入0,并且要跟上插入的元素
  • sort():排序

    this.letters.sort();
    
  • reverse():反转

    this.letters.reverse();
    

九、书籍购物车案例

index.html




  
  Title
  


书籍名称 出版日期 价格 购买数量 操作
{{item.id}} {{item.name}} {{item.data}} {{item.price| showPrice}} {{item.count}}

总价格:{{totalPrice | showPrice}}

购物车为空

main.js

const app = new Vue({
  el: '#app',
  data:{
    books:[
      {
        id:1,
        name :'《算法导论》',
        data:'2006-9',
        price:85.00,
        count:1
      },
      {
        id:2,
        name :'《UNIX编程艺术》',
        data:'2006-2',
        price:59.00,
        count:1
      },
      {
        id:3,
        name :'《编程艺术》',
        data:'2008-10',
        price:39.00,
        count:1
      },
      {
        id:4,
        name :'《代码大全》',
        data:'2006-3',
        price:128.00,
        count:1
      },

    ]
  },
  methods:{
    getFinalPrice(price){
      return '¥' + price.toFixed(2)
    },
    increment(index){
      this.books[index].count++
    },
    decrement(index){
      this.books[index].count--
    },
    removeHandle(index){
      this.books.splice(index,1)
    }
    },
  filters:{
    showPrice(price){
      return '¥' + price.toFixed(2)
    }
  },
  computed:{
    totalPrice(){
      //1.普通的for循环
/*      let totalPrice=0;
      for(let i =0;i

style.css

table{
  border : 1px solid #e9e9e9;
  border-collapse: collapse;
  border-spacing: 0;
}
th,td{
  padding:8px 16px;
  border :1px solid #e9e9e9;
  text-align: left;
}
th{
  background-color: #f7f7f7;
  color:#5c6b77;
  font-weight: 600;
}

高阶函数.js

//编程范式 :编程式编程/声明式编程
//编程范式 :面向对象编程(第一公民是对象)/函数式编程(第一公民是函数)
//高阶函数 filer/map/reduce
//filter中的回调函数有一个要求:必须返回一个bollean值
//true:当返回true时,函数内部会自动将这次回调的n加入到新的数组中
//false:当返回false时,函数内部会过滤掉这次的n

const nums = [10,20,111,222,444,40,50]
/* let newNums = nums.filter(function (n){
   return n<100
})
console.log(newNums);

/!*2.map函数的使用*!/
let new2Nums =newNums.map(function (n){
  return n * 2;
})

console.log(new2Nums)

//3.reduce函数的使用
//reduce函数的作用:对数组中所有内容汇总
let total = new2Nums.reduce(function (preValue , n){
  return preValue + n
},0)*/
//第一次 : preValue:0 n:20
//第二次 : preValue:20 n:40
//第三次 : preValue:60 n:80
//第四次 : preValue:140 n:100
//240

/*let total = nums.filter(function (n){
  return n<100
}).map(function (n){
  return n*2
}).reduce(function (prevValue , n){
  return prevValue+n
},0)*/

let total = nums.filter(n => n< 100).map(n =>n * 2).reduce((pre , n) => pre + n);

console.log(total);

/*
//需求:1.取出所有小于100的数字

let newNums =[]
for (let n of nums){
  if(n<100){
    newNums.push(n);
  }
}

//需求:2.将所有小于100的数字进行转化:全部 *2

let new2Nums = []
for (let n of newNums){
  new2Nums.push(n*2)
}

//需求:3.将所有需求new2Nums中的数字相加,得到最终结果

let  total = 0
for (let n of new2Nums){

}*/

运行结果

VUE学习笔记 coderwhy老师(持更)_第15张图片

十、v-model的使用

10.1 v-model 的基本使用

  • 表单控件在实际开发中是非常常见的,特别是对于用户信息的提交,vue中使用v-model指令来实现表单元素和数据的双向绑定

  • 当我们在输入框输入内容时,因为input中的v-model绑定了message,所以会实时将输入的内容传递给message,message 发生改变,当message发生改变时,因为上面使用Mustache语法,将message的值插入到DOM中,所以DOM会发生响应的改变

  • 所以,通过v-model实现了双向的绑定

  • v-model =>v-bind:value v-on: input

  • v-model其实是一个语法糖,它的背后本质是包含两个操作

    • v-bind绑定一个value属性

    • v-on指令给当前元素绑定input事件

      
      
      
      

10.2 v-model和radio/checkbox/select

  • checkbox
    • 单个勾选框
      • v-model即为布尔值,此时input的value并不影响v-model的值
    • 多个复选框
      • 当是多个复选框时,因为可以选中多个,所以对应的data中的属性是一个数组。当选中某一个时,就会将input的value添加到数组中
  • select
    • 单选
      • v-model绑定的是一个值,当我们选中option中的一个时,会将它对应的value赋值到mySelect中
    • 多选
      • v-model绑定的是一个数组,当选中多个值时,就会将选中的option对应的value添加到数组mySelects中

10.3 修饰符

  • lazy

    • 默认情况下,v-model默认是在input事件中同步输入框的数据的。
      也就是说,一旦有数据发生改变对应的data中的数据就会自动发生改变。
      lazy修饰符可以让数据在失去焦点或者回车时才会更新

      
      

      {{message}}

  • number

    • 默认情况下,在输入框中无论我们输入的是字母还是数字,都会被当做字符串类型进行处理。
      但是如果我们希望处理的是数字类型,那么最好直接将内容当做数字处理。
      number修饰符可以让在输入框中输入的内容自动转成数字类型

      
      

      {{age}}--{{typeof(age)}}

  • trim

    • 如果输入的内容首尾有很多空格,通常我们希望将其去除
      trim修饰符可以过滤内容左右两边的空格

    06-v-model修饰符的使用.html

    
    
    
      
      Title
    
    
    
    

    {{message}}

    {{age}}--{{typeof(age)}}

    您输入的名字是:{{name}}

运行结果
VUE学习笔记 coderwhy老师(持更)_第16张图片

十一、组件化开发

11.1 认识组件化

  • 如果我们将一个页面中所有的处理逻辑全部放在一起,处理起来就会变得非常复杂,而且不利于后续的管理以及扩展。但是如果,我们将一个页面拆分成一个个小的功能块,每个功能块完成属于自己这部分独立的功能,那么之后整个页面的管理和维护就变得非常容易了。
  • 组件化提供了一种抽象,让我们可以开发出一个个独立可复用的小组件来构造我们的应用,任何的应用都会被抽象成一棵组件树。
  • 有了组件化的思想,我们在之后的开发中就要充分的利用它,尽可能的将页面拆分成一个个小的,可复用的组件,这样让我们的代码更加方便组织和管理,并且扩展性也很强

11.2 组件的基本使用

  • 注册组件的基本步骤

    • 创建组件构造器
      • 调用Vue.extend()方法创建组件构造器
    • 注册组件
      • 调用Vue.component()方法注册组件
    • 使用组件
      • 在Vue实例的作用范围内使用组件
      
      
    
    //1.创建组件构造器对象
     const cpnC = Vue.extend({
       template :`

    我是标题

    我是内容,哈哈哈哈哈

    我是内容,呵呵呵呵呵

    ` }) //2.注册组件 /*Vue.component('组件的标签名')*/ Vue.component('my-cpn',cpnC) const app = new Vue({ el: '#app', data:{ message: '你好!' } })
  • Vue.extend()

    • 调用Vue.extend()创建的是一个组件构造器,通常在创建组件构造器时,传入template代表我们自定义组件的模板,该模板就是在使用到组件的地方,要显示的HTML代码,事实上,这种写法在Vue2.x的文档中几乎看不到了,他会直接使用语法糖
  • Vue.component()

    • 调用Vue.component()是将刚才的组件的组件构造器注册为一个组件,并且给他起一个组件的标签名称。所以需要传递两个参数:1、注册组件的标签名2、组件构造器
  • 组件必须挂载在某个Vue实例下,否则他不会生效

11.3 全局组件和局部组件

  • 全局组件

    • 意味着可以在多个Vue的实例下面使用

    • 注册方式

      • Vue.component('my-cpn',cpnC)
        
  • 局部组件

    • 意味着只能在该Vue的实例下面使用

    • 注册方式

      • const  app = new Vue({
          el: '#app',
          data:{
            message: '你好!'
          },
          components :{
            //con使用组件时的标签名
            //cpnC组件的构造器
            cpn :cpnC
          }
        })
        

11.4 父组件和子组件

//子组件
const cpnC1 = Vue.extend({
  template :`

我是标题1

我是内容,哈哈哈哈哈

` } ) //父组件 const cpnC2 = Vue.extend({ template :`

我是标题2

我是内容,呵呵呵呵呵

` , components :{ cpn1 : cpnC1, } } ) //root 根组件 const app = new Vue({ el: '#app', data:{ message: '你好!' }, components :{ cpn2: cpnC2 } })

11.5 注册的语法糖

//全局组件的语法糖
Vue.component('cnp1',{
  template :`

我是标题1

我是内容,哈哈哈哈哈

` }) const app = new Vue({ el: '#app', data:{ message: '你好!' }, //局部组件的注册语法糖 components:{ 'cnp2':{ template :`

我是标题2

我是内容,哈哈哈哈哈

` } } })

11.6模板的分类写法

  • script

    
    
    
  • template

    
    

11.7 数据的存放

  • 组件是一个单独功能模块的封装,这个模块有属于自己的HTML模板,也应该有属于自己的数据data

  • 组件不能直接访问Vue实例中的data,而且即使可以访问,如果将所有的数据都放在Vue实例中,Vue实例就会变得非常臃肿

  • 组件数据的存放

    • 组件对象也有一个data属性(也可以有methods等属性),只是这个data属性必须是一个函数,而且这个函数返回一个对象,对象内部保存数据
  • 组件中的data为什么必须是一个函数

      Vue.component('cpn',{
        template:'#cpn',
        //是函数,不会相互影响,每一个组件都用的不同的对象,不会引起连锁反应
        data(){
          return{
            counter :0
          }
        },
    /*    //不是函数,会相互影响,因为每一个组件都用的一个对象,会引起连锁反应
        const obj = {
          counter :0
        }
        data(){
          return obj
        },*/
    

11.8 父子组件的通信

  • 子组件是不能引用父组件或者Vue实例的数据的,但是在开发中,往往一些数据确实需要从上层传递到下层,比如我们从服务器请求到了很多数据,其中一部分数据,并非是我们整个页面的大组件来展示的,而是需要下面的子组件进行展示,这个时候,并不会让子组件再发一个网络请求,而是直接让大组件(父组件)将数据传递给小组件(子组件)

  • 真实的开发中,Vue实例和子组件的通信和父组件和子组件的通信过程是一样的。

  • 父传子 : props

  • 子传父:$emit

    
    
    
      
      Title
    
    
    
    

11.9 项目

  • npm install
  • npm run serve/dev

11.10 父子组件的访问方式

  • 有时候需要父组件直接访问子组件,子组件需要直接访问父组件,或者子组件访问跟组件

    • 父组件访问子组件:使用 c h i l d r e n 或 children或 childrenrefs

    • 子组件访问父组件:使用$parent

十二、组件化高级

12.1 slot插槽

  • 插槽的目的是让我们封装的组件更加具有扩展性

  • 封装插槽的方法:抽取共性,保留不同

  • 插槽的基本使用

  • 插槽的默认值

  • 如果有多个值,同时放入到组件进行替换时,一起作为替换元素

    01-插槽的基本使用.html

    
    
    
        
        Title
    
    
    
    哈哈哈哈哈哈 呵呵呵呵呵

运行结果

VUE学习笔记 coderwhy老师(持更)_第17张图片

12.2 具名插槽

02-具名插槽.html




  
  Title


标题

运行结果

在这里插入图片描述

12.3 编译的作用域

  • 父组件模板的所有东西都会在父级作用域内编译;子组件模板的所有东西都会在子级作用域内编译。

    03-编译的作用域.html

    
    
    
        
        Title
    
    
    

12.4 作用域插槽

  • 父组件替换插槽的标签,但是内容是由子组件来提供的

    04-作用域插槽的案例.html

    
    
    
        
        Title
    
    
    

运行结果

VUE学习笔记 coderwhy老师(持更)_第18张图片

十三、前端模块化

13.1 CommonJS

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

  • CommonJS的导出

    module.exports = {
       flag: true,
       test(a,b){
           return a+b
       },
       demo(a,b){
       return a*b
       }
    }
    
  • CommonJS的导入

    //CommonJS模块
    
    let {test,demo,flag} = require('moduleA');
    
    //等同于
    
    let _mA = required('moduleA');
    let test = _mA.test;
    let demo = _mA.demo;
    let flag = _mA.flag;
    

13.2 export基本使用

  • export指令用于导出变量

    //info.js
    export let name ='why'
    export let age = 18
    export let height = 1.88
    

    上面的代码还有另外一种写法:

    //info.js
    let name ='why'
    let age = 18
    let height = 1.88
    
    export{name,age,height}
    
  • export指令用于导出函数/类

    export function test(content){
      console.log(content)
    }
    export class Person{
      constructor(name,age){
         this.name = name;
         this.age = age;
      }
      run(){
          console.log(this.name +'在奔跑');
      }
    }
    

    上面的代码还有另外一种写法:

    function test(content){
      console.log(content)
    }
    class Person{
      constructor(name,age){
         this.name = name;
         this.age = age;
      }
      run(){
          console.log(this.name +'在奔跑');
      }
    }
    export{test,Person};
    
  • export default

    • 某些情况下,一个模块中包含某个的功能,我们并不希望给这个功能命名,而且让导入者可以自己来命名,这个时候就要用export default

      //导出
      //info.js
      export default function(){
         console.log('default funtion');
      }
      
      导入
      import myFunc form './info.js'
      myFunc()
      

      另外,需要注意:

      export default在同一模块中,不允许同时存在多个

13.3 import使用

  • 首先,我们需要在HTML代码中引入两个js文件,并且类型需要设置为module

    
             
    
  • import指令用于导入模块的内容,比如main.js的代码

    import{name,age,height} from "./info.js"
    console.log(name,age,height);
    
  • 如果我们希望某个模块中所有的信息都导入,一个导入显然麻烦:

    • 通过*可以导入模块中所有的export变量
    • 但是通常情况下我们需要给*起一个别名,方便后续的使用
    import * as info from './info.js'
    console.log(info.name,info,age,info.height,info.friends);         
    

13.4 Webpack

13.4.1 Webpack的定义

  • Webpack是一个现代的JavaScript应用的静态模块打包

  • 前端模块化

    • 目前使用前端模块:AMD、CMD、CommJS、ES6
    • 在ES6之前,我们想要进行模块化开发,就必须借助其他的工具,让我们可以进行模块化开发,并且在通过模块化开发完成了项目后,还需处理模块建的各种依赖,并且将其进行整合打包。
    • 而webpack其中一个核心就是让我们可能进行模块化开发,并且会帮助我们处理模块间的依赖关系,而且不仅仅是JavaScript文件,我们的CSS、图片、json文件等等在webpack都可以被当作模块来使用。

13.4.2 Webpack和grunt/gulp的对比

  • grunt/gulp的核心是Task

    • 我们可以配置一系列的task ,并且定义task要处理的事务(例如ES6、ts转化、图片压缩、scss转化css),之后让grunt/gulp来一次执行这些task,并且让整个流程自动化,所以grunt/gulp也被称为前端自动化任务管理工具。

    • 下面的task就是将src下面的所有js文件转成ES5的语法,并且最终输出到disk文件中

      const gulp = require('gulp');
      const babel = require('gulp-babel');
      
      gulp.task('js',() =>
          gulp.src('src/*js'))
              .pipe(babel({
                 presets :['es2015']
              }))
              .pipe(gulp.dest('dist'))
      );
      
      • 如果你的工程模块依赖非常简单,甚至是没有用到模块化的概念。只需要进行简单的合并、压缩,就用grunt/gulp即可,但是如果整个项目使用了模块化管理,而且相互依赖性非常强,我们就可以使用更加强大的webpack了。
  • grunt/gulp和webpack有什么不同

    • grunt/gulp更加强调的是前端流程的自动化,模块化不是它的核心。
    • webpack更加强调模块化开发管理,而文件压缩合并、预处理等功能,是它附带的功能。

13.4.3 Webpack安装

  • webpack模块化打包,webpack为了可以正常运行,必须依赖node环境,node为了可以正常的执行很多代码,必须其中各种依赖的包

  • npm工具(node packages manager)

  • 安装webpack首先需要安装Node.js

    • 查看自己的node版本:

    node -v

    • 全局安装webpack

      npm install [email protected] -g

    • 局部安装webpack

      • –save-dev 是开发时依赖,项目打包后不需要继续使用的。

      cd 对应目录
      npm install [email protected] --save -dev

  • 为什么全局安装后,还需要局部安装?

    • 在终端直接执行webpack命令,使用的全局安装的webpack
    • 当在package.json中定义了scripts时,其中包含了webpack命令,那么使用的是局部webpack

13.4.4 js文件的打包

  • 现在的js文件中使用了模块化的方式进行开发,他们不可以直接用,因为如果直接在index.html引入这两个js文件,浏览器并不识别其中的模块化代码。另外,在真实项目中当有许多这样的js文件时,我们一个个引用非常麻烦,并且后期非常不方便对他们进行管理。

  • 我们可以使用webpack工具,对多个js文件进行打包,webpack就是一个模块化的打包工具,所以它支持我们代码中写模块化,可以对模块化的代码进行处理。另外,如果在处理完所有模块之间的关系后,将多个js打包到一个js文件中,引入时就变得非常方便了。

  • 打包的命令

    webpack src/main.js dist/bundle.js

  • 使用打包后的文件

    • 打包后会在dist文件下,生成一个bundle.js文件
      • bundle.js文件,是webpack处理了项目直接文件依赖后生成的一个js文件,我们只需要将这个js文件在index.html中引入即可

13.4.5 入口和出口

  • 如果每次使用webpack的命令都需要写上入口和出口作为参数,就非常麻烦,webpack.config.js文件可以将这两个参数写到配置中,在运行时,可以直接读取。

    const path = require('path')
    module.exports = {
      //入口:可以是字符串/数组/对象,这里我们数组只有一个,所以写一个字符串即可
      entry:'./src/main.js',
      //出口:通常是一个对象,里面至少包含两个重要属性,path 和 filename
      output :{
         path : path.resolve(__dirname,'dist'),//注意:path是一个绝对路径
         filename : 'bundle.js'
      }
    }
    
  • package.json中定义启动

    • 在终端执行的都是全局的

    • package.json中的scripts的脚本在执行时,会按照一定的顺序寻找命令对应的位置

      {
        "name": "meetwebpack",
        "version": "1.0.0",
        "description": "index.js",
        "main": "webpack.config.js",
        "scripts": {
          "test": "echo \"Error: no test specified\" && exit 1",
          "build": "webpack"
        },
        "author": "",
        "license": "ISC",
        "devDependencies": {
          "webpack": "^3.6.0"
        }
      }
      
      • 首先,会寻找本地的node_modules/.bin路径中对应的命令。

      • 如果没有找到,会去全局的环境变量中去找

      • 如何执行bulid指令

        npm run bulid

13.4.6 Loader

  • loader是webpack中一个非常核心的概念

  • webpack的作用

    • 我们主要是用webpack来处理我们写的js代码,并且webpack会自动处理js之间相关的依赖,但是,在我们开发中,我们不仅仅有基本的Js代码处理,我们也需要加载css、图片,也包括一些高级的将ES6转成ES5的代码,将TypeScript转成ES5代码,将scss、less转成css,将.jsx、.vue文件转成js文件等等。对于webpack本身的能力来说,对于这些转化是不支持的,这个时候,将webpack扩展对应的loader就可以了。
  • load使用过程:

    • 通过npm安装需要使用的loader
    • 在webpack.config.js中的modules关键字下进行配置
13.4.6.1 css文件处理-准备工作
  • 项目开发过程中,我们必然需要添加很多的样式,而样式我们往往写到一个单独文件中。
    • 在src目录中,创建一个css文件,其中创建一个normal.css文件
    • 我们也可以重新组织文件的目录结构,将零散的js文件放在一个js文件夹中
  • normal.css的代码非常简单,就是将body设置red,但是,这个时候的Normal.css的样式不会生效,我们没有引用他,webpack也不可能找到它,因为我们只有一个入口,webpack会从入口开始查找其他依赖的文件
13.4.6.2 css文件处理-打包报错信息
  • 重新打包,会出现如下错误:

    bundle.js  4.33 kB       0  [emitted]  main
       [0] ./src/main.js 299 bytes {0} [built]
       [1] ./src/js/mathUtils.js 149 bytes {0} [built]
       [2] ./src/js/info.js 81 bytes {0} [built]
       [3] ./src/css/normal.css 623 bytes {0} [built] [failed] [1 error]
    
    ERROR in ./src/css/normal.css
    Module build failed: CssSyntaxError
    
    (1:1) Unknown word
    
    • 此处应该将webpack.config.js文件修改为

      const path = require('path')//用node里面的,通过npm init
      module.exports = {
          entry: './src/main.js',
          output: {
              path : path.resolve(__dirname,'dist'),//绝对路径
              filename:'bundle.js'
          },
          module: {
              rules: [
                  {
                      test: /\.css$/,
                      //css-loader只负责将css文件进行加载
                      //style-loader 负责将样式添加到DOM中
                      //webpack在使用多个loader时,是从右向左的
                      use: ['style-loader','css-loader']
                  }
              ]
          }
      }
      
13.4.6.3 图片文件处理
  • 图片小于8kb

    • 安装url-loader,运行成功,会发现背景图是通过base64显示出来的,这是limit属性的作用,当图片小于8kb时,对图片进行base64编码
  • 图片大于8kb

    • 安装file-loader,运行成功,再次打包,就会发现dist文件夹下多了一个图片文件,这是webpack自动生成的名称,这是一个32位的hash值,目的是防止名称重复,但是,真实开发中,我们可能对打包的图片名字有一个的要求,比如,将所有的图片放在一个文件夹中,跟上图片原来的名称,同时也要防止重复,但是,我们发现图片并没有显示出来,这是因为图片使用的路径不正确,默认情况下,webpack会将生成的路径直接返回给使用者,但是我们整个程序是打包在dist文件夹下的,所以需要在路径下再添加一个dist/

    • 我们可以在options中添加上如下选项

      • img: 文件要打包到的文件夹
      • name:获取图片原来的名字,放在该位置
      • hash8: 为了防止图片名称冲突,依然使用hash,但是我们只保留8位
      • ext:使用图片的扩展名
      const path = require('path')//用node里面的,通过npm init
      module.exports = {
          entry: './src/main.js',
          output: {
              path : path.resolve(__dirname,'dist'),//绝对路径
              filename:'bundle.js',
              publicPath: 'dist/'
          },
          module: {
              rules: [
                  {
                      test: /\.css$/,
                      //css-loader只负责将css文件进行加载
                      //style-loader 负责将样式添加到DOM中
                      //webpack在使用多个loader时,是从右向左的
                      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|jpeg)$/,
                      use: [
                          {
                              loader: 'url-loader',
                              options: {
                                  /*当加载的图片,小于limit时,会将图片编译成base64字符串形式*/
                                  /*当加载的图片,大于limit时,需要使用file-load模块进行加载*/
                                  limit: 73000,
                                  name: 'img/[name].[hash:8].[ext]'
                              }
                          }
                      ]
                  }
              ]
          }
      }
      
13.4.6.4 ES6语法处理
  • Webpack打包的js文件写的ES6语法并没有转成ES5,那么就意味着可能一些对ES6还不支持的浏览器没有办法很好的运行我们的代码

  • 如果希望将ES6的语法转成ES5,那么就需要babel,而在webpack中,我们直接使用babel对应的loader就可以了。

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

    配置webpack.config.js

    {
        test: /\.js$/,
        exclude: /(node_modules|bower_components)/,
        use: {
            loader: 'babel-loader',
            options: {
                presets: ['es2015']
            }
        }
    }
    

    重新打包就可以

13.4.6.5 webpack配置vue
  • 我们希望在项目中使用Vuejs,那么必然需要对其有依赖,所以需要先安装

    注:后续是在实际项目中使用vue,所以并不是开始时依赖

    npm install vue --save

  • Vue构建的两个版本

    • runtime-only

      • 代码中,不可以有任何的template
    • runtime-compiler

      • 代码中,可以有template,因为有compiler可以用于编译template
  • 打包项目-错误信息

    • 修改完成后,重新打包,运行程序,打包过程没有任何错误,但是在运行的时候,没有达到想要的效果,而且浏览器报错

VUE学习笔记 coderwhy老师(持更)_第19张图片

  • 修改webpack的配置

    resolve:{
            alias:{
                'vue$': 'vue/dist/vue.esm.js'
            }
        }
    
  • el和template区别

    • 如果同时有el和template,el会替换template
  • .vue文件封装处理

    • 一个组件以一个js对象的形式进行组织和使用的时候是非常不方便的,一方面编写template模块非常的麻烦,另一方面如果有样式的话不知在哪里写合适,此时,我们以一种全新的方式来组织一个vue组件

      • 安装vue-loader和vue-template-compiler

      • 注:vue-template-compiler的版本必须与所安装的vue版本保持一致

        npm install [email protected] [email protected] --save-dev --force

      • 配置webpack.config.js文件

        {
            test :/\.vue$/,
            use :['vue-loader']
        }
        
13.4.6.6 横幅plugin的使用
  • plugin的定义

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

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

    • 通过npm安装需要使用的plugins(某些webpack已经内置的插件不需要安装)
    • 在webpack.config.js中的plugins配置插件
  • 添加版权的plugin

    • BannerPlugin,属于webpack自带的插件,为打包的文件添加版权声明

    • 修改webpack.config.js文件:

      const path = require('path')
      const webpack = require('webpack')
      
      module.exports = {
        ...
        plugins: [
          new webpack.BannerPlugin('最终版权归aaa所有')
        ]
      }
      
    • 重新打包程序:查看bundle.js文件的头部,可以看到

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xffscHno-1644828620589)(C:\Users\JMS\AppData\Roaming\Typora\typora-user-images\image-20220203152747651.png)]

  • 打包html的plugin

    • 目前,我们index.html存放在项目的根目录下的,我们知道,在真实发布项目时,发布的是dist文件夹中的内容,但是dist文件夹中如果没有index.html文件,那么打包的js等文件也没有意义了,所以我们需要将index.html文件打包到dist文件夹中,这个时候就可以使用HtmlWebpackPlugin插件

    • HtmlWebpackPlugin插件的作用

      • 自动生成一个index.html文件(可以指定模板来生成),将打包的js文件,自动通过script标签插入到body中

      • 安装HtmlWebpackPlugin插件

        npm install [email protected] --save-dev --force

      • 需要删除之前在output中添加的publicPath属性,否则插入的script标签中的src可能会有问题

  • js压缩的Plugin

    • 在项目发布之前,我们必然需要对js等文件进行压缩处理,我们使用一个第三方的插件uglifyjs-webpack-plugin,并且版本号指定1.1.1,和CLI2保持一致

      npm install [email protected] --save-dev

    • 修改webpack.config.js文件

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3nJiRh8B-1644828620589)(C:\Users\JMS\AppData\Roaming\Typora\typora-user-images\image-20220204133632973.png)]

    • 查看bundle.js,已经是被压缩过了的

    13.4.6.7 搭建本地服务器
    • webpack提供了一个可选的本地开发服务器,这个本地服务器基于node.js搭建,内部使用express框架,可以实现我们想要的让浏览器自动刷新显示我们修改后的结果,不过它是一个单独的模块,在webpack中使用之前需要先安装它

      npm install --save-dev [email protected]

    • devserver也是作为webpack中的一个选项,选项本身可以设置如下属性:

      • contentBase;为哪一个文件夹提供本地服务,默认是跟文件夹,我们这里要填写./dist
      • port:端口号,默认8080
      • inline: 页面实时刷新
      • historyApiFallback:在SPA页面中,依赖HTML5的history模式
    • webpack.config.js文件配置修改如下

    • 我们可以再配置另外一个scripts:

      • –open参数表示直接打开浏览器
  • webpack-配置文件的分离

    npm install [email protected] --save-dev

13.5. Vue CLI

13.5.1 简述Vue CLI

  • 如果只是简单写几个Vue的Demo程序,那么你不需要Vue CLI,如果你在开发大型项目,那么你需要,并且必然需要使用Vue CLI

  • 使用Vue.js开发大型应用时,我们需要考虑代码目录结构、项目结构和部署、热加载、代码单元测试等事情。如果每个项目都要手动完成这些工作,那无疑效率比较低效,所以通常我们会使用一些脚手架工具来帮助完成这些事情。

  • CLI的定义

    • CLI是Command-Line Interface,翻译为命令行页面,但是俗称脚手架。
    • Vue CLI是一个官方发布vue.js项目脚手架
    • 使用vue-cli可以快速搭建Vue开发环境以及对应的webpack配置
  • Vue CLI使用前提 -Node,Node环境要求8.9以上或者更高的版本

  • Vue CLI使用前提 -WebPack

    • Vue.js官方脚手架工具就使用了webpack模板
      • 对所有的资源会压缩等优化操作
      • 它在开发过程中提供了一套完整的功能,能够使得我们开发过程中变得高效

13.5.2 Vue CLI的使用

  • 安装Vue脚手架

    npm install -g @vue/cli-init

    注意:安装的是Vue CLI3的版本,如果需要按照Vue CLI2的方式初始化项目需拉取2.x模板

  • Vue CLI2初始化项目

    vue init webpack my-project

  • Vue CLI3初始化项目

    vue create my-project

  • runtime-compiler 和runtime-only的区别

    • 运行过程
      • runtime-compiler
        • template -> ast -> render -> vdom ->UI
      • runtime-only
        • render -> vdom ->UI
        • …vue文件里面的template是由vue-template-compiler来解析的
      • 总结
        • runtime-only性能更多
        • runtime-only代码量更少(轻6kb)
        • 如果在之后的开发中,你依然使用template,就需要选择Runtime-Compiler
        • 如果在之后的开发中,使用的.vur=e文件夹,那么可以选择Runtime-Only
  • createElement的使用

    /*  1.普通用法: createElement('标签',{标签的属性},[''])
        return createElement('h2',
          {class: 'box'},
          ['Hello World', createElement('button', ['按钮'])])
      } */
    // 2.传入组件对象
    return createElement(App)     
    
  • Vue CLI3

    • Vue CLI3和Vue CLI2的区别
      • vue-cli是基于webpack4打造,vue -cli还是webpack3
      • vue-cli的设计原则是"0配置",移除的配置文件根目录下的,build和config等目录
      • vue-cli3提供了vue ui 命令,提供了可视化配置,更加人性化,移除了static文件夹,新增了public文件夹,并且index.html移动到public中

13.6 箭头函数

  • 箭头函数的基本使用

    //箭头函数: 也是一种定义函数的方式
        //1.定义函数的方式: function
        const aaa = function () {
    
        }
        //2.对象字面量中定义函数
        const obj = {
            bbb: function () {
    
            },
            bbb(){
    
            }
        }
        //3.ES6中的箭头函数
    /*    const ccc = (参数列表) =>{
    
        }*/
        //aaa用ccc表示
        const ccc = () =>{
    
        }
    
  • 箭头函数的参数和返回值

    //1.参数问题
        //1.1放入两个参数
        const sum =(num1, num2) =>{
            return num1 + num2
        }
        //1.2放入一个参数
        const power = num =>{
            return num * num
        }
        //2.函数中的
        //2.1函数代码块中有多行代码时
        const test = () =>{
            //1.打印Hello World
            console.log("Hello World");
    
            //2.打印Hello Vuejs
            console.log("Hello Vuejs");
        }
        //2.1函数代码块中只有一行代码时
    /*    const mul = (num1, num2 ) => {
          return num1 * num2
        }*/
        const mul = (num1, num2) => num1 * num2
    
    /*    const demo = () => {
            console.log("Hello Demo");
        }*/
    
        const demo = () => console.log("Hello Demo")
        console.log(demo());
    
  • 箭头函数中this的使用

     //当把一个函数作为参数传到另一个函数中的时候,用箭头参数较多
    /*    setTimeout(function (){
            console.log(this)//window
        },1000)*/
    
        setTimeout(() => {
            console.log(this)//window
        },1000)
    
        //结论: 箭头函数中的this引用的就是向外层作用域,一层层查找this,直到有this的定义
        const obj = {
            aaa() {
                setTimeout(function () {
                    console.log(this);//window
                })
    
                setTimeout(()=>{
                    console.log(this);//obj对象
                })
            }
        }
    
        const obj = {
            aaa() {
                setTimeout(function () {
                    setTimeout(function () {
                        console.log(this);//window
                    })
    
                    setTimeout(() => {
                        console.log(this);//window
                    })
                })
                setTimeout(() => {
                    setTimeout(function () {
                        console.log(this);//window
                    })
                    setTimeout(() => {
                        console.log(this);//obj对象
                    })
                })
            }
        }
    

13.7 路由

13.7.1 路由的定义

  • 路由就是通过互联的网路把信息从源地址传输到目的地址的活动
  • 路由器提供了两种机制:路由和传送,路由是决定数据包从来源到目的地的路径,转送将输入端的数据转移到合适的输出端,路由中有一个非常重要的概念叫路由表,路由表本质上就是一个映射表,决定了数据包的指向。

13.7.2 后端渲染和后端路由阶段

  • 早期的网站开发整个html页面是由服务器来渲染的,服务器直接生成渲染好对应的html页面,返回给客户端进行展示

  • 一个页面有自己对应的网址,也就是url,url会发送到服务器,服务器会通过正则对该URL进行匹配,并且最后交给一个Controller进行处理,Controller进行各种处理,最终生成HTML或者数据,返回给前端,这就完成了一个IO操作

  • 当我们页面中需要请求不同的路径内容时,交给服务器来进行处理,雾浮起渲染好整个页面,并且将页面返回给客户端,这种情况下渲染好的页面,不需要单独加载任何js和css,可以直接交给浏览器展示,这样也有利于SEO的优化。

  • 后端渲染

    • jsp :java server page
  • 后端路由

    • 后端处理url和页面之间的映射关系
  • 后端路由的缺点

    • 整个页面的模块由后端人员来编写和维护的,前端开发人员如果要开发页面,需要通过PHP和Java来编写页面代码,而且通常情况下html代码和数据以及对应的逻辑会混在一起,编写和维护都是非常棘手的。

13.7.3 前后端分离阶段

  • 随着Ajax的出现,有了前后端分离的 开发模式,后端只提供API来返回数据,前端通过Ajax获取数据,并且可以通过JavaScript将数据渲染到页面中,这样做最大的优点就是前后端责任的清晰,后端专注于数据上,前端专注于交互和可视化上。并且当移动端(ios/android)出现后,后端不需要进行任何处理,依然使用之前的一套API即可,目前很多的网站依然采用这种模式开发。

  • 后端只负责提供数据,不负责任何阶段的内容

  • 前端渲染

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

13.7.4 单页面富应用阶段

  • 其实SPA最主要的特点就是在前后端分离的基础上加上了一层前端路由,也就是前端来维护一套路由规则。

  • SPA:simple page web application(单页面富应用),整个网页只有一个html页面

  • 前端路由的核心:改变URL,但是页面不进行整体的刷新

    • 修改url

      location.hash = 'aaa'//修改url的hash值,不会重新请求数据
      history.pushState({},'','home')//利用栈结构push,会保存历史记录
      history.replaceState({},'','home')//只会替换,不会保存历史记录
      history.go(-1) = history.back()//栈中弹出一个元素
      history.go(1) = history.forward()//栈中压入一个元素
      

13.7.5 vue-router

  • 目前流行的三大框架,都有自己的路由实现

    • Angular的ngRouter
    • React的ReactRouter
    • Vue的vue-router
      • vue-router是Vue.js官方的路由插件,它和vue.js是深度集成的,适合用于构建单页面应用。
      • vue-router是基于路由和组件的,路由用于设定访问路径,将路径和组件映射起来,在vue-router的单页面应用中,页面的路径的改变就是组件的切换。
13.7.5.1 安装和使用vue-router
13.7.5.2 动态路由
  • 在某些情况下,一个页面的path路径可能是不确定的,比如我们进入用户界面时,希望是如下路径

    • /user/aaaa或/user/bbbb

    除了有前面的/user之外,后面还跟上了用户的ID,这种path和Component的匹配关系,我们称之为动态路由(也是路由传递数据的一种方式)。

13.7.5.3 路由的懒加载
  • 当打包构建应用时,Javascript包会变得非常大,影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了。

  • 路由中通常会定义很多不同的页面,一般情况下,是放在一个js文件中,但是,页面这么多放在一个js文件中,必然会造成这个页面非常大。如果我们一次性从服务器请求下来这个页面,可能需要花费一定的时间,甚至用户的电脑上还出现了短暂空白的情况,为了避免这种情况,使用路由懒加载。

  • 路由加载的主要作用就是将路由对应的组件打包成一个个js代码块。只有在这个路由被访问到的时候,才加载对应的组件。

  • 懒加载的方式

    • 在ES6中,有更加简单的写法来组织Vue一步组件和Webpack的代码分割

      const Home = () => import('../components/Home.vue')
      
  • 路由嵌套

    • 嵌套路由是一个很常见的功能,比如在home页面中,我们希望通过/home/news和/home/message访问一些内容,一个路径映射了一个组件,访问这两个路径也会分别渲染两个组件。
    • 实现嵌套路由的步骤
      • 创建对应的子组件,并且在路由映射中配置对应的子路由
      • 在组件内部使用标签
  • 传递参数的方式

    • 传递参数主要有两种类型: params和query

    • params的类型

      • 配置路由的格式:/rouer/:id
      • 传递的方式:在path后面跟上对应的值
      • 传递后形成的路径:/router/123,/router/abc
    • query的类型(传递大量数据时使用)

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

      ​ scheme://host:port/path?query#fragment

    13.7.5.4 导航守卫

    index.jsp

    配置meta

    path: '/about',//about 前端路由地址
    component: About,
    meta: {
      title: '关于'
    }
    

    添加beforeEach/afterEach方法

    //全局守卫,除了全局守卫之外,还有路由独享的守卫,组件内的守卫
    //前置守卫(guard)是在跳转前回调的
    router.beforeEach((to, from , next ) => {
      //从from跳到to
      document.title = to.matched[0].meta.title;
      console.log(to);
      next();
    })
    //后置钩子(hook)是在跳转后回调的,不需要调用next()函数
    router.afterEach((to , from ) => {
    })
    

    meta: 描述数据的数据

  • keep-alive

    • keep-alive是Vue内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染

      • include -字符串或正则表达,只有匹配的组件会被缓存

      • exclude-字符串或正则表达式,任何匹配的组件都不会被缓存

        //,前后不能加空格,正如正则表达式也不能随便加空格
        
         
        
        
    • router-view 也是一个组件,如果直接被包在keep-alive里面,所有路径匹配到的视图组件都会被缓存

    • activated和deactived两个生命周期,只有该组件被保持了状态使用了keep-alive时,才是有效的

13.8 TabBar

13.8.1 TabBar实现思路
  • 下方封装一个单独的TabBar组件
    • 自定义TabBar组件,在APP中使用,让TabBar出于底部,并且设置相关的样式
  • TabBar中显示的内容由外界决定
    • 定义插槽,flex布局平分TabBar
  • 自定义TabBarItem,可以传入图片和文字
    • 定义TabBarItem,并且定义两个插槽:图片、文字
    • 给两个插槽外层包装div,用于设置样式
    • 填充插槽,实现底部TabBar的效果

你可能感兴趣的:(vue.js,前端,javascript)