前端学习笔记____Vue2+Vue3全家桶

作者主页:仙女不下凡-前端萌新

前言介绍:以下 内容都是我个人对于前端知识的总结,会定期更新欢迎持续关注!

欢迎点赞 收藏 ⭐留言 如有错误敬请指正!


前言

学习视频地址:https://www.bilibili.com/video/BV1Zy4y1K7SH?from=search&seid=16946268743532201801
学习进度:该视频适用于有css、html、JavaScript与前后端交互基础的同学
学习方法总结:https://editor.csdn.net/md/?articleId=116121563

第一章 VUE基础

一、Vue简介

⭐1.Vue是什么?

Vue是一套用于构建用户界面的渐进式JavaScript框架。

⭐2.Vue发展历史

前端学习笔记____Vue2+Vue3全家桶_第1张图片

⭐3.Vue的特点

特点:❶ 采用组件化模式,提高代码复用率且让代码更好维护;❷声明式编码,让编码人员无需直接操作DOM,提高开发效率;❸使用虚拟DOM+由优秀的Diff算法,尽量复用DOM节点
前端学习笔记____Vue2+Vue3全家桶_第2张图片

二、初识Vue

⭐1.Vue模板语法

1.使用vue必须创建一个Vue实例,且要传入一个配置对象

  


  
容器

Vue模板语法两大类 - 插值语法:功能:用于解析标签体内容写法:{{xxx}},xxx是js表达式,可以直接读取data中所有属性
Vue模板语法两大类 - 指令语法:功能:用于解析标签(包括:标签属性,标签体内容,绑定事件......)写法:v-????

⭐2.数据绑定

单向数据绑定v-bind:数据只能从data流向页面,简写:
双向数据绑定v-model:如下代码是错误的,v-model只能应用在表单类元素(输入类元素)

<h2 v-model:x="name">你好啊h2>

⚠️注意⚠️:❶双向数据绑定一般都应用在表单类元素上(如:input、select等);❷v-model:value可以简写为v-model,因为v-model默认收集的就是value的值。

⭐3.el与data的两种写法

el的两种写法

el的第一种写法

<head>
  <script text="text/javascript" src="../js/vue.js">script>
head>
<body>
  <div id="root">容器div>
body>

<script type="text/javascript">
  Vue.config.productionTip = false;  //阻止Vue在启动时生成生产提示

  const vm = new Vue({
    el: '#root', /第一种写法,直接与容器关联/
    data: {},
  })
script>

el的第二种写法

<head>
  <script text="text/javascript" src="../js/vue.js">script>
head>
<body>
  <div id="root">容器div>

  <script type="text/javascript">
    Vue.config.productionTip = false;  //阻止Vue在启动时生成生产提示

    const vm = new Vue({
      //el: '#root', //直接与容器关联
      data: {},
    });
    vm.$mount('#root');  /这就是第二种写法挂载,意义:写法灵活,比如可以加定时器控制执行时间/
  script>
body>

data的两种写法

data第一种写法

<head>
  <script text="text/javascript" src="../js/vue.js">script>
head>
<body>
  <div id="root">容器div>
body>

<script type="text/javascript">
  Vue.config.productionTip = false;  //阻止Vue在启动时生成生产提示

  const vm = new Vue({
    el: '#root',
    data: {},   /data第一种写法,对象式/
  })
script>

data第二种写法

<head>
  <script text="text/javascript" src="../js/vue.js">script>
head>
<body>
  <div id="root">容器div>
body>

<script type="text/javascript">
  Vue.config.productionTip = false;  //阻止Vue在启动时生成生产提示

  const vm = new Vue({
    el: '#root',
    data: function(){  /data第二种写法,函数式,function可以省略,组件必须使用函数式/
      return: 'xxx',
    },
  })
script>

⭐4.MVVM模型

MVVM模型:Vue参考了该模型
M:模型(Model):对应data中的数据
V:视图(View):模板
VM:视图模型(ViewModel):Vue实例对象
前端学习笔记____Vue2+Vue3全家桶_第3张图片
总结发现:❶data中所有的属性,最后都出现在了vm身上;❷另外vm身上所有的属性及Vue原型上所有属性,在Vue模板中都可以直接使用。

⭐5.数据代理

回顾Object.defineproperty方法(ES6):给对象添加属性

let number = 18;
let person = {
  name: '张三',
  sex: '男',
  //age: number,
};

//需求当number改变时可以同步使age改变,这是就是使用到Object.defineproperty方法
Object.defineproperty(person, 'age', {
  /当有人读取person的age属性时,get函数(getter函数)就会被调用,且返回值就是age的值/
  get:function(){  //function可以省略
    return number;
  },
  /当有人修改person的age属性时,set函数(setter函数)就会被调用,且会收到修改的具体值/
  set(value){
    number = value
  }
})

Vue中的数据代理:通过一个对象代理对另一个对象中属性的操作(读/写),示例代码如下:

//简单的数据代理
let obj = { x:200 };
let obj2 = { y:300 };

Object.defineproperty(obj2,'x',{
  get:(){
    return obj.x;
  },
  set(value){
    obj.x = value
  }
})

Vue中数据代理的好处:更加方便的操作data中的数据。
基本原理:❶通过Object.defineproperty()data对象所有属性添加到vm上;❷为每一个添加到vm的属性,都指定一个getter/setter;❸在getter/setter内部去操作(读/写)data中对应的属性。

⭐6.事件处理

⑴ 事件处理v-on

事件的基本使用:❶使用v-on:xxx@xxx绑定事件,其中xxx是事件名;❷事件的回调需要配置的在methods对象中,最终会在vm上;❸methods中配置的函数,不要用箭头函数,否则this就不是vm实例;❹methods中配置的函数,都是被Vue所管理的函数,this指向vm实例或组件实例对象;❺@click="demo"@click="demo($event)"效果一致,但是后者可以传参。

⑵ 事件修饰符

Vue中的事件修饰符:❶prevent阻止默认事件(常用);❷stop阻止事件冒泡(常用);❸once事件只触发一次(常用);❹capture使用事件的捕获模式;❺self只有event.target是当前操作的元素时才触发事件;❻passive事件的默认行为立即执行,无需等待事件回调执行完毕。

⑶ 键盘事件key

Vue中常用的按键别名:

按键 别名
回车 enter
删除 delete(捕获"删除"和"退格"键)
退出 esc
空格 space
换行 tab(特殊,必须配合keydown去使用)
上,下,左,右 up,down,left,right

⚠️注意⚠️:Vue未提供别名的按键,可以使用按键原始的key值去绑定,但注意要转为kebab-case(短横线命名)。
系统修饰键(用法特殊)ctrl、alt、shift、meta。❶配合keyup使用:按下修饰键的同时,再按下其他键,随后释放其他键,事件才被触发;❷配合keydown使用:正常触发事件;❸也可以使用keyCode去指定具体的按键(不推荐)。
Vue.config.keyCode.自定义键名 = 键码:可以定制按键别名。

⭐7.计算属性computed与监视(侦听)属性watch

⑴ 计算属性-computed

对比插值表达式方法methods计算属性,来了解计算属性存在的必要。

1.姓名案例-插值语法实现
<body>
  <div id="root">
    姓:<input type="text" v-model="fristName"><br/>
    名:<input type="text" v-model="lastName"><br/>
    全名:<span>{{fristName}}-{{lastName}}span>
  div>
body>

<script type="text/javascript">
  Vue.config.productionTip = false;  //阻止Vue在启动时生成生产提示

  const vm = new Vue({
    el: '#root',
    data:{
      fristName: '张',
      lastName: '三'
    }
  })
script>
2.姓名案例-methods方法实现
<body>
  <div id="root">
    姓:<input type="text" v-model="fristName"><br/>
    名:<input type="text" v-model="lastName"><br/>
    全名:<span>{{fullName()}}span>
  div>
body>

<script type="text/javascript">
  Vue.config.productionTip = false;  //阻止Vue在启动时生成生产提示

  const vm = new Vue({
    el: '#root',
    data: {
      fristName: '张',
      lastName: '三'
    },
    methods: {
      fullName(){
        return this.fristName + '-' + this.lastName, /问题效率不高/
      }
    }
  })
script>
3.姓名案例-计算属性实现
<body>
  <div id="root">
    姓:<input type="text" v-model="fristName"><br/>
    名:<input type="text" v-model="lastName"><br/>
    全名:<span>{{fullName}}span>
    全名:<span>{{fullName}}span> /只调用了一次fullName中的get(),有缓存,优势/
  div>
body>

<script type="text/javascript">
  Vue.config.productionTip = false;  //阻止Vue在启动时生成生产提示

  const vm = new Vue({
    el: '#root',
    data:{
      fristName: '张',
      lastName: '三'
    },
    computed:{  //计算属性
      //完整写法
      fullName:{
        /get作用:当有人读取fullName时,get就会被调用,且返回值就作为fullName的值/;
        /get什么时候被调用? ❶初次读取fristName时 ❷所依赖的数据发生改变时/
        get(){ return this.fristName + '-' + this.lastName },
        /set什么时候调用? 当fullName被修改时调用./
        set(){}  //不是必须写的
      }
      
      //简写,如果没有定义setter简写形式如下
      fullName(){
        return this.fristName + '-' + this.lastName
      }
    }
  })
script>

定义:要用的属性不存在,要通过已有属性计算得来。
原理:底层借助了Object.defineproperty()提供的getter和setter
get函数什么时候执行❶初次读取时会执行一次❷当依赖的数据发生变化时会被再次调用。
优势:与methods实现相比,内部有缓存机制(复用),效率更高,调试更方便
⚠️备注⚠️:❶计算属性最终出现在vm实例上,直接读取使用即可❷如果计算属性要被修改,那必须写在set函数去响应修改,且set中要引起计算时依赖的数据发生改变`。

⑵ 监视(侦听)属性-watch

通过上述学习的方法实现天气的切换
<head>
  <script text="text/javascript" src="../js/vue.js">script>
head>
<body>
  <div id="root">
    <h2>今天天气很{{info}}h2>
    <button @click="changeWeather">切换天气button> /事件(如click)后的表达式默认在vm上面找属性和方法执行/
  div>
body>

<script type="text/javascript">
  Vue.config.productionTip = false;  //阻止Vue在启动时生成生产提示

  //创建Vue实例
  const vm = new Vue({
    el: '#root',
    data: {
      isHot: true,
    },
    computed: {
     info(){ return this.isHot ? '炎热' : '凉爽' }
    },
    methods: {
      changeWeather(){ this.ihHot = ! this.isHot }
    }
  })
script>
通过该案例理解监视watch方法
<head>
  <script text="text/javascript" src="../js/vue.js">script>
head>
<body>
  <div id="root">
    <h2>今天天气很{{info}}h2>
    <button @click="changeWeather">切换天气button> 
  div>
body>

<script type="text/javascript">
  Vue.config.productionTip = false;  //阻止Vue在启动时生成生产提示

  //创建Vue实例
  const vm = new Vue({
    el: '#root',
    data: {
      isHot: true,
    },
    computed: {
     info(){ return this.isHot ? '炎热' : '凉爽' }
    },
    methods: {
      changeWeather(){ this.ihHot = ! this.isHot }
    }
    watch:{  /第一种监视watch方法/
      isHot:{  /这里isHot是配置对象,也是监视的对象/
        immediate:true,  /初始化时让handler调用一下/
        //handler什么时候调用?当isHot发生改变时调用.
        handler(newValue,oldValue){ console.log(newValue,oldValue) }  /handler也是配置对象/
      }
    }

    /简写,当不需要设置immediate与deep时,第一种可以这样简写/
    watch{
      isHot(newValue,oldValue){ console.log(newValue,oldValue) }
    }
  })

  vm.$watch('isHot', {  /第二种监视watch方法/
    immediate:true,
    handler(newValue,oldValue){ console.log(newValue,oldValue) }
  });

  /简写,当不需要设置immediate与deep时,第二种可以这样简写/
    vm.$watch('isHot', function(newValue,oldValue){ console.log(newValue,oldValue) });
script>

监视属性watch:当监视的属性变化时,回调函数自动调用,进行相关操作,监视属性必须必存在,才能进行监视
监视的两种写法:❶new Vue时传入watch配置❷通过vm.$watch监视。

⑶ 深度监视(侦听)

通过该案例理解深度监视-只检测a的变化
<head>
  <script text="text/javascript" src="../js/vue.js">script>
head>
<body>
  <div id="root">
    <h3>a的值是:{{number.a}}h3>
    <button @click="number.a++">点我让a+1button>
  div>
body>

<script type="text/javascript">
  Vue.config.productionTip = false;

  const vm = new Vue({
    el: '#root',
    data: {
      number: {
        a:1,  //监听a
        b:1
      }
    },
    watch:{ 
      /监视多级结构中某个属性的变化/
      'number.a':{
        handler(newValue,oldValue){
        }
      }
    }
  })
script>
通过该案例理解深度监视-检测a和b的变化
<head>
  <script text="text/javascript" src="../js/vue.js">script>
head>
<body>
  <div id="root">
    <h3>a的值是:{{number.a}}h3>
    <button @click="number.a++">点我让a+1button>
  div>
body>

<script type="text/javascript">
  Vue.config.productionTip = false;

  const vm = new Vue({
    el: '#root',
    data: {
      number: {
        a:1,  //监听a
        b:1
      }
    },
    watch:{ 
      number:{
        deep: true,  /深度检测开启/
        handler(newValue,oldValue){}
      }
    }
  })
script>

深度监视:❶Vue中的watch默认不监测对象内部值的改变(一层);❷配置deep:true可以监测对象内布值改变(多层)。
⚠️备注⚠️:❶Vue自身可以监测对象内部值的改变,但Vue提供的watch默认不可以!❷使用watch时根据数据的具体结构,决定是否采用深度监视。

watchcomputed对比

watchcomputed之间的区别:❶computed能完成的功能,watch都可以完成;❷watch能完成的功能,computed不一定能完成,例如watch可以进行一步操作。
⚠️两个重要的小原则⚠️:❶所被Vue管理的函数,最好携带普通函数,这样this指向才是vm或组件实例对象;❷所有不被Vue所管理的函数(定时器的回调函数、ajax回调函数等),最好携带箭头函数,这样this指向才是vm或组件实例对象。

⭐8.class与style绑定

绑定class样式
<head>
  <script text="text/javascript" src="../js/vue.js">script>
head>
<body>
  <div id="root">
    /绑定class样式--字符串写法,适用于:样式的类名不确定,需要动态指定/
    <div class="basic" :class="mood" @click="changeMood">{{name}}div><dr/>
    /绑定class样式--数组写法,适用于:要绑定的样式个数和名字不确定/
    <div class="basic" :class="classArr">{{name}}div><dr/>
    /绑定class样式--对象写法,适用于:要绑定的样式个数和名字确定,但是要动态决定用不用/
    <div class="basic" :class="classObj">{{name}}div><dr/>
    
    <div class="basic" :style="{fontSize: fsize+'px'}">{{name}}div>
    /绑定style样式--数组写法/
    <div class="basic" :style="styleObj">{{name}}div>
    /绑定style样式--对象写法/
    <div class="basic" :style="styleArr">{{name}}div>
  div>
body>

<script type="text/javascript"> /basic,normal与happy都是写好的样式/
  Vue.config.productionTip = false;

  const vm = new Vue({
    el: '#root',
    data: {
      name: '尚硅谷',
      mood: 'normal',
      classArr: ['atguigu1','atguigu2','atguigu3'],  /atguigu1,atguigu2,atguigu3都是写好的样式/
      classObj: {
        atguigu1:false,
        atguigu2: false
      },
      fsize: 40,
      styleArr: [{
        color: 'red',
        fontSize: '40px'
      },{
        backgroundColor: 'bull',
      }],
      styleObj: {
        color: 'red',
        fontSize: '40px'
      }
      styleObj2: {
        backgroundColor: 'bull',
      }
    },
    methods: { 
      changeMood:{
       this.mood = 'happy',
      }
    }
  })
script>

⭐9.条件渲染

⑴ v-if

写法v-if="表达式" v-else-if="表达式" v-else="表达式"
⚠️备注⚠️:v-if可以和v-else-if、v-else一起使用,但要求结构不能被"打断"。适用于切换频率较低的场景,特点是不展示的DOM元素直接被移除。

⑵ v-show

写法v-show="表达式"
⚠️备注⚠️:特点不展示的 DOM元素未被移除,适用于切换频率较高的场景。

⭐10.列表渲染

⑴ 基本列表 v-for指令

<body>
  <div id="root">
    
    <ul>
      <li v-for="(p,index) in persons" :key="index">{{p.name}}-{{p.age}}li>
    ul>

    
    <ul>
      <li v-for="(value,k) of car" :key="k">{{k}}-{{value}}li>
    ul>

    
    <ul>
      <li v-for="(char,index) of str" :key="index">{{index}}-{{char}}li>
    ul>

    
    <ul>
      <li v-for="(number,index) of 5" :key="index">{{number}}-{{index}}li>
    ul>
  div>
body>

<script type="text/javascript">
  Vue.config.productionTip = false;
  new Vue({
    el: 'root',
    data: {
     persons: [
       {id:'001',name:'张三',age:'18'},
       {id:'002',name:'李四',age:'17'},
       {id:'003',name:'王五',age:'18'},
     ],
     car: {name:'奥迪A8',price:'70万',color:''},
     str: 'hello'
    }
  })
script>

v-for指令:❶用于展示列表数据❷语法v-for="(item,index) in xxx" :key="yyy"❸可遍历:数组、对象、字符串(用得少)、指定次数(用的最少)。

⑵ key的原理

面试题:react、vue中的key有什么作用? (key的内部原理)
虚拟DOMkey的作用key虚拟DOM对象的标示,当数据发生变化时,Vue会根据新数据生成新的虚拟DOM,随后Vue进行新虚拟DOM旧虚拟DOM的差异比较。比较规则如下:
对比规则:❶旧虚拟DOM中找到了与新虚拟DOM相同的key;若虚拟DOM中内容没变,直接使用之前的真实DOM;若虚拟DOM中内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM。❷旧虚拟DOM中未找到与新虚拟DOM相同的key创建新的真实DOM,随后渲染到页面。
index作为key可能会引发的问题:❶若对数据进行:逆序添加、逆序删除破坏操作( 会产生没有必要的真实DOM更新 ==> 界面效果没问题,但效率低 )。⑵如果结构中还包含输入类的DOM( 会产生错误DOM更新 ==> 界面有问题 )。
开发中如何选择key?
❶最好使用每条数据的唯一标识作为key,比如id、手机号、身份证号、学号等唯一值。❷如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,使用index作为key是没有问题的。

⑶ 列表过滤

<body>
  <div id="root">
    <h2>人员列表h2>
    <input type="text" placeholder="请输入名字" v-model="keyWord">
    <ul>
      <li v-for="(p,index) of filPerons" :key="index">
        {{p.name}}-{{p.age}}-{{p.sex}}
      li>
    ul>
  div>
body>

/监视写法/
<script type="text/javascript">
  Vue.config.productionTip = false;
  new Vue({
    el: '#root'
    data: {
      keyWord:'',
      persons: [
        {id:'001',name:'马冬梅',age:'19',sex:'女'},
        {id:'002',name:'周冬雨',age:'20',sex:'女'},
        {id:'003',name:'周杰伦',age:'21',sex:'男'},
        {id:'004',name:'温兆伦',age:'22',sex:'男'}
      ],
      filPerons: [],
    }
    watch: {
      keyWord: {
      immediate: true,  /一上来就执行,相当于给filPerons赋值,否则filPerons为空/
      handler(val){
        this.filPerons = this.persons.filter((p)=>{
          return p.name.indexOf(val) !== -1
        })
      }
    }
  })
script>
 / 计算属性写法 /
<script  type="text/javascript">
  Vue.config.productionTip = false;
  new Vue({
    el: '#root'
    data: {
      keyWord:'',
      persons: [
        {id:'001',name:'马冬梅',age:'19',sex:'女'},
        {id:'002',name:'周冬雨',age:'20',sex:'女'},
        {id:'003',name:'周杰伦',age:'21',sex:'男'},
        {id:'004',name:'温兆伦',age:'22',sex:'男'}
      ]
    },
    computed: { 
      filPerons(){
        return this.persons.filter((p) => {
          return p.name.indexOf(this.keyWord) !== -1
        })
      }
    }
  })
script>

⑷ 列表排序

<body>
  <div id="root">
    <h2>人员列表h2>
    <input type="text" placeholder="请输入名字" v-model="keyWord">
    <button>年龄升序button>
    <button>年龄降序button>
    <button>原顺序button>
    <ul>
      <li v-for="(p,index) of filPerons" :key="p.id">
        {{p.name}}-{{p.age}}-{{p.sex}}
      li>
    ul>
  div>
body>

<script  type="text/javascript">
  Vue.config.productionTip = false;
  new Vue({
    el: '#root'
    data: {
      keyWord:'',
      sortType:0,  //0原顺序,1降序,2升序
      persons: [
        {id:'001',name:'马冬梅',age:'19',sex:'女'},
        {id:'002',name:'周冬雨',age:'20',sex:'女'},
        {id:'003',name:'周杰伦',age:'21',sex:'男'},
        {id:'004',name:'温兆伦',age:'22',sex:'男'}
      ]
    },
    computed: { 
      filPerons(){
        const arr = this.persons.filter((p) => {
          return p.name.indexOf(this.keyWord) !== -1
        })
        //判断一下是否需要排序
        if(this.sortType){
          arr.sort((a,b) => { /sort(方法)/
            return this.sortType === 1 ? b.age-a.age : a.age-b.age
          })
        }
        return arr
      }
    }
  })
script>

⑸ Vue检测数据改变的原理

/ 模拟一个数据检测 /
<body>
  <div id="root">
    <h1>学生信息h1>
    <button @click="student.age++">年龄+1岁button> <br/>
    <button @click="addSex">添加性别属性,默认值:男button> <br/>
    <button @click="addSex">修改性别属性,默认值:男button> <br/>
    <button @click="addFridend">在列表首位添加一个朋友button> <br/>
    <button @click="updateFrietFriendName">修改第一个朋友的名字为:张三button> <br/>
    <button @click="addHobby">添加一个爱好button> <br/>
    <button>修改第一个爱好为:开车button> <br/>
    
    <h3>姓名:{{student.name}}h3>
    <h3>年龄:{{student.age}}h3>
    <h3 v-if="student.sex">性别:{{student.sex}}h3>
    <h3>爱好:h3>
    <ul>
      <li v-for="(h,index) in student.hobby" :key="index">{{h}}li>
    ul>
    <h3>朋友们:h3>
    <ul>
      <li v-for="(f,index) in student.friends" :key="index">{{f.name}}-{{f.age}}li>
    ul>
  div>
body>

<script type="text/javascript">
  Vue.config.productionTip = false;
  const vm = new Vue({
    el: '#root'
    data: {
      student: {
        name: 'tom',
        age: 18,
        hobby: ['抽烟','喝酒','烫头'],
        friends: [
          {name:'jerry', age:25},
          {name:'tony', age:16}
        ]
      }
    },
    methods: {
      addSex(){ Vue.set(this.student,'sex','男') },  /第二种写法this.$set(this.student,'sex','男')/
      addFridend(){ this.student.friends.unshift({name:'jack',age:20}) },
      updateFrietFriendName(){ this.student.friend[0].name = '张三' },
      addHobby(){ this.student.hobby.push('学习') },
      updateHobby(){ this.student.hobby.splice(0,1,'开车')},/第二种写法Vue.set(),第三种this.$set()/
    }
  })
script>

Vue监视数据的原理vue会监视data中所有层次的数据。
如何监测对象中的数据? 通过setter实现监视,且要在new Vue时就传入要监测的数据❶对象中后追加的属性,Vue默认不做响应式处理;❷如需给后添加的属性做响应式,请使用以下API
Vue.set(target, propertyName/index, value)vm.$set(target, propertyName/index, value)
如何监测数据中的数据? 通过包裹数组更元素的方法实现,本质就是做了两件事❶调用原生对应的方法对数组进行更新;❷重新解析模板,进而更新页面。
Vue修改数组中的某个元素一定要用如下方法:❶使用这些APIpush()、pop()、shift()、unshift()、splice()、sort()、reverse(); ❷.Vue.set() 或 vm.set()
⚠️特别注意⚠️:Vue.set()vm.set()不能给vmvm的根数据对象添加属性!!!

⑹ 收集表单数据

效果图
前端学习笔记____Vue2+Vue3全家桶_第4张图片

示例代码
<body>
  <div @submit.prevent="demo">  /prevent阻止默认行为/
    <form action="">
      <label for="demo">账号:label><input type="text" v-model.trim="demo"> <br/>  /trim去掉前后空格/
      <label for="password">密码:label><input type="text" v-model="password"> <br/>
      <label for="age">年龄:label><input type="number" v-model.number="age"> <br/> /number设置填写的为数字类型/
      <label for="demo">性别:label><input type="radio" name="sex" v-model="sex" value="male"><input type="radio" name="sex" v-model="sex" value="female"> <br/>
      <label for="password">爱好:label> 
      学习<input type="checkbox" v-model="hobby" value="study">
      打游戏<input type="checkbox" v-model="hobby" value="game">
      吃饭<input type="checkbox" v-model="hobby" value="eat"> <br/>
      <label for="password">请选择校区:label> 
      <select v-model="city">
        <option value="">请选择校区option>
        <option value="北京">北京option>
        <option value="上海">上海option>
        <option value="深圳">深圳option>
        <option value="武汉">武汉option>
      select> <br/>
      <label for="password">其他信息:label>
      <textarea v-model.lazy="other">textarea> br> /lazy懒惰/
      <input type="checkbox" v-model="agree">阅读并接受<a href="http://xxxx"> 《用户协议》 a>
      <button>提交button>
    form>
  div>
body>

<script type="text/javascript">
  Vue.config.productionTip = false;
  new Vue({
    el: '#root'
    data: {
      account:'',
      password:'',
      age:'',
      sex:'female',
      hobby:[],
      city:'',
      other:'',
      agree:''
    },
    methods: {
      /思考怎么获取表单填写的所有数据? ❶_date就可以获取到 ❷把data中表相关数据包成一个对象也可以但是h5需要加相应的前缀/
      demo(){
        console.log(this._date)
      }
    }
  })
script>

收集表单数据
⑴.若v-model收集的是value值,用户输入的就是value值
⑵.若v-model收集的是value值,且要给标签配置value值
⑶.若
❶没有配置input的value属性,那么收集的就是checked(布尔值);
❷配置inputvalue属性但若v-model的初始值是非数值,那么收集的就是checked(布尔值),v-model的初始值是数组,那么收集的就是value组成的数组。
v-model的三个修饰符lazy失去焦点再收集数据;number输入字符串转为有效的数字;trim输入首位空格过滤。

⭐11.过滤器

常用处理时间戳的插件month.js(相对)、day.js(轻量)。

<script type="text/javascript" src="../js/dayjs.min.js">script>
<body>
  <div id="root">
    <h2>显示格式化后的时间h2>
    <h3>现在是:{{fmtTime}}h3>
    <h3>现在是:{{getFmtTime()}}h3>
    <h3>现在是:{{time | timeFormater}}h3>  /将time作为参数传给timeFormater/
  div>

  <div id="root2">
    <h2>{{msg}}h2>
  div>
body>

<script type="text/javascript">
  Vue.config.productionTip = false;
  /全局过滤器/
  Vue.filter('mySlice', function(value){ return dayjs(value).format('YYYY-MM-DD HH:mm:ss') }); 

  new Vue({
    el: '#root'
    data: { time:'时间戳数据'},  /时间戳引用这里省略了/
    computed: {
      fmtTime(){ return dayjs(this,time).format('YYYY-MM-DD HH:mm:ss') }
    },
    methods: {
      getFmtTime(){ return dayjs(this.time).format('YYYY-MM-DD HH:mm:ss') }
    },
    filters: {  /局部过滤器/
      timeFormater(value){ return dayjs(value).format('YYYY-MM-DD HH:mm:ss') }
    }
  })

  new Vue({
    el: '#root2'
    data: {
      msg: '尚硅谷',
    },
    computed: {},
    methods: {},
  })
script>

过滤器定义:对要显示的数据进行特定格式化后再显示(适用于一些简单的逻辑处理)。
过滤器语法:❶注册过滤器Vue.filter(name,callback)new filter{ filter:{} }❷使用过滤器{{ xxx | 过滤器名 }}v-bind:属性 = "xxx | 过滤器名"
⚠️备注⚠️:❶过滤器也可以接收额外参数、多个过滤器也可以串联❷并没有改变原本的数据,是产生新的对应数据。

⭐12.内置指令

⑴ 上述学习过指令总结

指令 作用
v-bind 单向绑定解析表达式,可简写为:xxx
v-model 双向数据绑定
v-on 绑定事件监听,可简写为@
v-for 遍历数组/对象/字符串
v-if 条件渲染 (动态控制节点是否存在)
v-else 条件渲染 (动态控制节点是否存在)
v-show 条件渲染 (动态控制节点是否展示)

⑵ v-text指令

v-text指令作用:向其所在的节点中渲染文本内容。
v-text指令与插值语法区别v-text会替换掉节点中的内容,{{xx}}不会。

⑶ v-html指令

v-html指令作用:向指定节点中渲染包含html结构的内容。
v-html指令与插值语法的区别:①v-html会替换掉节点中所有的内容,{{xx}}则不会;②v-html可以识别html结构。
⚠️严重注意⚠️:v-html指令有安全性问题!①在网站上动态渲染任意HTML是非常危险的,容易导致KSS攻击;②一定要在可信的内容上使用v-html,用不要用在用户提交的内容上!

⑷ v-cloak指令

v-cloak指令本质:是一个特殊属性,Vue实例创建完毕并接管容器后,会散删掉v-cloak属性;使用css配合v-cloak可以解决网速慢时页面展示出{{xxx}}的问题。

<head>
  /没有直接引用js文件夹中vue.js的原因,使用该文件延迟5秒才调用vue.js文件/
  <script type="text/javascript" src="http://localhost:8080/resource/5s/vue.js">script>
  <style>
    [v-cloak]{ display: none }
  style>
head>
<body>
  <div id="root">
    <h2 v-cloak>{{name}}h2>  /如果不加v-cloak页面会显示{{name}},5秒之后插值表达式才会解析/
  div>
body>

<script type="text/javascript">
  Vue.config.productionTip = false;
  
  new Vue({
    el: '#root'
    data: { name: '尚硅谷' }
  })
script>

⑸ v-once指令

v-once指令v-once所在节点在初次动态渲染后,就视为静态内容了;以后的数据的改变不会引起v-once所在结构的更新,可以用于优化性能。

⑹ v-pre指令

v-pre指令v-pre可以跳过其所在节点的编译过程;可利用它跳过没有使用指令语法、没有使用插值语法的节点,会加快编译。

⑺ 自定义指令directives

/需求1: 定义一个v-big指令,与v-text类似但是会把绑定的数值放大10倍/
/需求2: 定义一个v-fbind指令,与v-bind类似但可以让其所绑定的input元素默认获取焦点/
<body>
  <div id="root">
    <h2>当前的n值是:<span v-text="n">span> h2>
    <h2>放大10倍后的n值是:<span v-big="n">span> h2>
    <button @click="n++">点我n+1button> <hr/>
    <input type="text" v-fbind:value="n">
  div>
body>

<script type="text/javascript">
  Vue.config.productionTip = false;
  new Vue({
    el: '#root'
    data: { n:1 },
    /局部自定义指令/
    directives: {
      /两种方式,第一写成对象big:{}(完整),第二种写成函数big(){}/
      big(element,binding){  /element是真实DOM元素,binding是一个对象存各种信息/
        element.innerText = binding.value * 10;
      },
      fbind:{  /包含3个钩子函数/
        console.log(this);  /注意此处的this指向window/
        bind(element,value){ element.value = binding.value },  /指令与元素成功绑定时调用/
        inserted(element,value){ element.focus() },  /指令所在元素被插入页面时调用/
        upddate(element,value){ element.value = binding.value }  /指令所在的模板被重新解析时调用/
      }
    },
  })
script>

自定义指令语法:❶局部指令new Vue({ directives:{指令名:配置对象} })new Vue({ directivea(){} })❷全局指令Vue.directive(指令名, 配置对象)Vue.directive(指令名, 回调函数)
配置对象中常用的3个钩子函数:❶bind指令与元素成功绑定时调用❷inserted指令所在元素被插入页面时调用❸update指令所在模板结构被重新解析时调用。
⚠️备注⚠️:❶指令定义时不加v-,但使用时要加v-❷指令名如果是多个单词,要使用kebab-case命名方式,不要用camelCase命名。

三、生命周期

1.生命周期定义

生命周期定义:❶又名生命周期回调函数、生命周期函数、生命周期钩子;❷是Vue在关键时刻调用的以下特殊名称的函数,生命周期函数的名字不可更改;❸生命周期中this指向是vm实例组件实例对象

2.vm生命周期

vm状态 调用的函数
将要创建 调用beforeCreate函数
创建完毕 调用created函数
将要挂载 调用beforeMount函数
挂载完毕 调用**mounted**函数 【重要的钩子】
将要更新 调用beforeUpdate函数
更新完毕 调用undate函数
将要销毁 调用**beforeDestroy**函数 【重要的钩子】
销毁完毕 调用destroyed函数
<body>
  <div id="root">
    <h2 :style="{opacity}">欢迎学习Vueh2>  /这里是{opacity:opacity}简写了/
    <button @click="stop">透明度设置为1button>
    <button @click="stop">点我停止变换button>
  div>
body>

<script type="text/javascript">
  Vue.config.productionTip = false;
  new Vue({
    el: '#root',
    data: { opacity: 1 },
    methods: {
      stop(){
        //clearInterval(this.timer);  /这个方法只是停止了定时器并没有销毁/
        this.$destroy();  /这个方法是销毁了vm,会调用beforeDestroy与destroyed/
      }
    },
    mounted(){
      this.timer = setInterval(() => {
        this.opacity -= 0.01
        if(this.opacity <= 0) this.opacity = 1
      }, 16)
    },
    beforeDestroy(){ clearInterval(this.timer) }
  })
script>

常用的生命周期钩子:❶mounted发送ajax请求、启动定时器、绑定定时器、订阅消息【初始化操作】;❷beforeDestroy清除定时器、解绑自定义时间、取消订阅消息等【收尾工作】。
关于销毁Vue实例:❶销毁后借助Vue开发者工具看不到任何信息;❷销毁后自定义时间会失效,但原生DOM事件依然有效;❸一般不会在beforeDestroy操作数据,因为即使操作数据,也不会在触发更新流程了。

四、Vue组件化编程

⭐1.模块与组件、模块化与组件化

模块:向外提供特定功能的js程序,一般就是一个js文件;复用js文件,简化js编写,提高js运行效率。
组件:用来实现局部(特定)功能效果的代码集合(html/css/js/image...),复用代码,简化项目编码,提高运行效率。
前端学习笔记____Vue2+Vue3全家桶_第5张图片

  • 模块化
  • 组件化

⭐2.组件基本使用

非单文件组件:一个文件中包含有n个组件
单文件组件:一个文件只有一个组件a.vue

代码示例 - 单文件组件语法格式
<body>
  <div id="root">
    <xuesheng>xuesheng>  //4.写组件标签
    <hr>
    <school>school>  //4.写组件标签
  div>
body>

<script type="text/javascript">
  Vue.config.productionTip = false;
  
  /组件重要API-Vue.extend()/
  //1.创建组件
  const student = Vue.extend({
    /组件一定不要写el配置项,因为最终所有的组件要被一个vm管理,由vm决定服务于哪个容器/
    //el:'#root',
    /可以用name配置项指定组件在开发者工具中呈现的名字/
    //name: 'xuexiao',
    template:`    
      

学生姓名:{{name}}

学生年龄:{{age}}

`
, data(){ return { name:'张三', age:18 } }, /这不能用对象形式,因为会影响其他引用该组件的值,另外若写成对象形式也会报错/ }) const school = Vue.extend({ template:`

学校名称:{{name}}

学校地址:{{address}}

`
data(){ name:'尚硅谷', address:'上海' } }) //2.创建vm new Vue({ el: '#root', // 3. 注册组件(局部注册) components: { school: school, //简写成school xuesheng: student } data: {}, }); /全局注册组件/ Vue.components(student, 'student')
script>

⑴ 组件的注意事项

关于组件名一个单词组成(第1种写法 首字母小写)school、(第2种写法 首字母大写)School
多个单词组成(第1种写法kebab-case命名)my-school、(第2种写法CamelCase命名) MySchool(需要Vue脚手架)。
关于组件标签:第1种写法、第2种写法 (不用脚手架时,会导致后续组件不能渲染)。
一个简写形式const school = Vue.extend(options)可简写为const school = options

⑵ 组件的嵌套

代码示例 - 组件的嵌套
<body>
  <div id="root">
    <school>school>
  div>
body>

<script type="text/javascript">
  Vue.config.productionTip = false;
  
  const student = Vue.extend({  /子组件/
    template:`    
      

学生姓名:{{name}}

学生年龄:{{age}}

`
, data(){ return { name:'张三', age:18 } }, }); const school = Vue.extend({ /父组件/ components:{ student }, /组件的嵌套/ template:`

学校名称:{{name}}

学校地址:{{address}}

`
data(){ name:'尚硅谷', address:'上海' } }); /标准化开发时app组件管理所有组件-app组件/ const app = Vue.extend() new Vue({ el: '#root', components: { school }, /使用嵌套组件/ data: {}, });
script>

⑶ VueComponent

代码示例 - 组件的嵌套
<body>
  <div id="root">
    <school>school>
  div>
body>

<script type="text/javascript">
  Vue.config.productionTip = false;
  
  const school = Vue.extend({
    template:`
      

学校名称:{{name}}

学校地址:{{address}}

`
data(){ name:'尚硅谷', address:'上海' } }); console.log(school); /执行结果是构造函数VueComponent()/ new Vue({ el: '#root', components: { school }, data: {}, });
script>

school组件本质是一个名为VueComponent的构造函数,且不是程序员定义的,是Vue.extend生成的。
我们只需要写,Vue解析时会帮我们创建school组件的实例对象。
⚠️特别注意⚠️:每次调用Vue.extend,返回的都是一个全新的VueComponent
VueComponent的实例对象以后简称VC(也可称之为:组件实例对象) ;Vue实例对象,简称vm
关于this指向:①组件配置中data函数methods中的函数computed中的函数它们的this指向均是【VueComponent实例对象】②new Vue()配置中data函数methods中的函数computed中的函数它们的this指向均是【Vue实例对象】。

⑷ 一个重要的内置关系

<body>
  <div id="root">div>
body>

<script type="text/javascript">
  Vue.config.productionTip = false;

  //定义一个构造函数, 使用原型链的原理理解该内置关系
  function Demo(){
    this.a = 1,
    this.b = 2
  };
  //创建一个Demo的实例对象
  const d = new Demo();

  / Demo.prototype === d.__proto__ 显示原型属性与隐式原型属性都是指向原型对象 /
  console.log(Demo.prototype);  /显示原型属性/
  console.log(d.__proto__);  /隐式原型属性/
  
  //通过显示原型属性操作原型对象, 追加一个x属性, 值为99
  Demo.prototype.x = 99
  console.log(d.__proto__.x);   /执行结果为99/
script>

内置关系VueComponent.prototype.__proto__ === Vue.prototype作用让组件实例对象VC可以访问到Vue原型上的属性与方法。
前端学习笔记____Vue2+Vue3全家桶_第6张图片
黄色这条线是vue做的操作,她没有使VueComponent的原型对象指向Object的原型对象而是指向了Vue的原型对象。

⭐3.单文件组件

示例代码-.vue文件的结构
<template> 组件结构 template>

<script> 组件交互先关的代码(数据、方法等) script>

<style> 组件的样式 style>
/注意:需要暴露export/
<template>
  <div>
    <h2>学校名称:{{name}}h2>
    <h2>学校地址:{{address}}h2> 
  div>
template>

<script>  
  export const school = Vue.extend({  /1.分别暴露/
    data(){ return name:'尚硅谷', address:'上海' }
  }); 
  /2.统一暴露/
  //export {school};
  /3.默认暴露(较为常用)/
  //export default school

  /简写/
  export default {
    name: 'School',  /这种首字母大写的命名方式较为常用, 最好与文件名一致/
  }
script>

<style> 组件的样式 style>
.vue文件
<script>
  /引入组件, 注意没有脚手架.vue文件不识别报错/
  import School from './School.vue'
script>

⑴ 文件结构-辅助理解脚手架文件结构

前端学习笔记____Vue2+Vue3全家桶_第7张图片
.vue文件都是一个页面功能,可以看为单文件组件,不需要调用new Vue构造函数。
App.vue是所有vue组件(vue文件)的汇总。
main.js是记录了所有App组件服务于那个容器,这个调用里面new Vue构造函数。
index.html就是最后所有单文件组件服务的容器。


第二章 vue-cli

☘️一、初始化脚手架☘️

⭐1.安装脚手架

安装步骤:①全局安装脚手架npm install -g @vue/cli;②切换到创建项目的目录,然后使用命令创建项目vue create xxxx;③启动项目npm run serve

⭐2.项目文件夹的文件结构

babel.config.js:ES6转ES5的转换器。
package.json&package-lock.json:(包版本控制文件)作用注明各种依赖。
src→components→main.js:该文件是整个项目的入口文件。

/针对main.js文件代码内容解释/
//引入Vue
import Vue from 'vue'
//引入App组件, 它是所有组件的父组件
import App from './App.vue'
//关闭vue的生产提示
Vue.config.productionTip = false

//创建Vue实例对象-vm
new Vue({
  //写了$mount('#app')省略了el:'#app',
  render: h => h(App), /单独在下节解释/
}).$mount('#app')

src→components文件夹:所有的.vue文件(页面组件)。
src→assets文件夹:放的静态资源,如png图片、视频等。
public→index.html:应用界面。

/针对index.html代码解释/
DOCTYPE html>
<html lang="">
  <head>
    <meta charset="utf-8">
    /针对IE浏览器的一个特殊配置, 含义是让IE浏览器以最高的渲染级别渲染页面/
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    /开启移动端的理想视口/
    <meta name="viewport" content="with=device-width,initial-scale=1.0">
    /配置页签图标/
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
    /配置网页标题/
    <title><%= htmlWebpackPlugin.options.title %>title>
  head>
  <body>
    /当浏览器不支持js时noscript中的元素就会被渲染/
    <noscript>
      <strong>strong>
    noscript>

    /容器/
    <div id="app">div>
  body>
html>

⭐3.render()函数

不同版本Vue中.vue.jsvue.runtime.xxx.js的区别:.vue.js是完整版的Vue,包含核心功能+模板解析器;②.vue.runtime.xxx.js是运行版的Vue只包含核心功能没有模板解析器。
不同版本Vue中是因为.vue.runtime.xxx.js没有模板解析器,所以不能使用template配置项,需要使用render()接收到的createElement函数去指定具体内容。

⭐4.脚手架修改默认配置

Vue脚手架默认隐藏了所有webpack相关的重要配置文件,例如webpack.config.js文件,这时若想查看具体的webpack配置,请执行vue inspect > output.js命令,就会生成output.js展示文件(只读文件)。
使用vue.config,js可以对脚手架进行个性化定制,详情见:https://cli.vuejs.org/zh

二、Vue中常用的属性

⭐1.ref属性

<template>
  <div>
    <h1 v-text="msg" ref="title">h1>  /这就相当于id/
    <button ref="btn" @click="showDOM">点我输出上方的Dom元素button>
    <School ref="sch"/>  /sch是组件的实例对象/
  div>
template>
<script>
  import School from './components/School'

  export default {
    name: 'App',
    components: { School },
    data(){
      return { msg: '欢迎学习Vue!' }
    },
    methods: {
      showDOM(){ console.log(this.$refs.title) }  /直接获取到title的DOM元素/
    }
  }
script>
<style>style>

ref属性的作用:被用来给元素或子组件注册引用信息(id的代替者),应用在html标签上获取的是真实DOM元素,应用在组件标签上是组件实例对象(VC)。
ref属性的使用方式:打标识

......

,获取this.$refs.xxx

⭐2.props配置项

//APP.vue文件
<template>
  <div>
    <Student name="李四" sex="" age="18"/>  /:age这样才能接收到变量在{{}}中运算/
  div>
template>
<script>
  import School from './components/Student'

  export default {
    name: 'App',
    components: { Student },
  }
script>
<style>style>
//Student.vue组件-props配置项的3种写法/
<template>
  <div>
    <h1>{{msg}}h1>
    <h2>学生姓名:{{name}}h2>
    <h2>学生性别:{{sex}}h2>
    <h2>学生年龄:{{age}}h2>
  div>
template>
<script>
  export default {
    name: 'Student',
    /当data中命名与props中冲突, props优先/
    data(){
      return { 
        msg: '欢迎学习Vue!',
        myAge:this.age,  /这样就可以写方法修改值了/
      }
    },
    /1.简单接收/
    //props:['name','age','sex'], 
    /2.接收的同时对数据进行类型限制/
    /* props:{
      name:String,
      age:Number,
      sex: String
    }, */
    /3.接收的同时对数据进行类型+默认值的指定+必要性的限制/
    props:{
      name: { type:String,require:true },  /require:true代表name必须的/
      age: { type:Number,default:99 },  /default:99代表age默认值99/
      name: { type:String,require:true }   /一般require与default不同时出现/
    }
  }
script>
<style>style>

配置项props作用:让组件接收外部传过来的数据。props是只读的,Vue底层会检测对props的修改,如果进行 修改,就会发出警告,若业务需求确实需要修改,那么请复制props的内容data中一份,然后去修改data中的数据。

⭐3.mixin混入-两个组件共享一个配置

示例代码-School组件
<template>
  <div>
    <h2 @click="showName">学校名称:{{name}}h2>
    <h2>学校地址:{{addresss}}h2>
  div>
template>
<script>
  /引入局部混合/
  inport {mixin,mixin2} from '../mixin'
  
  export default {
    name: 'School',
    data(){
      return { name: '尚硅谷',address:'北京' }
    },
    mixins:[mixin,mixin2],  /使用局部混合/
    /*methods: {
      showName(){ console.log(this.name) }
    }*/
  }
script>
示例代码-Student组件
<template>
  <div>
    <h2 @click="showName">学生姓名:{{name}}h2>
    <h2>学校性别:{{sex}}h2>
  div>
template>
<script>
  inport {mixin,mixin2} from '../mixin'
  export default {
    name: 'Student',
    data(){
      return { name: '张三',sex:'男' }
    },
    mixins:[mixin,mixin2],  /使用局部混合/
    /* methods: {
      showName(){ console.log(this.name) }
    }*/
  }
script>  /showName是两个组件相同的配置/
/mixin.js文件,文件名自定义/
export const mixin = {
  methods: {
      showName(){ console.log(this.name) }
    }
}
export const mixin2 = {
  methods: {
      showName(){ console.log('你好') }
    }
}
/在main.js文件中, 引入全局混合/
import {mixin,mixin2} from './mixin'

Vue.mixin(mixin)
Vue.mixin(mixin2)

mixin混合(混入)作用:可以将多个组件公用的配置提取成一个混入对象,局部混合mixins:['xxx'],全局混入Vue.mixin(xxx)

⭐4.插件install()

/定义插件-plugins.js文件-写法1/
const obj = {
  install(){ console.log('你好,我是插件!') }
}

export default obj
/定义插件-plugins.js文件-写法2/
export default {
  install(Vue){
    /定义混入等等/
    Vue.mixin({
     methods: { showName(){ console.log('你好') } }
    })
  }
}
/在main.js文件中, 引入插件/
import plugins from './plugins'

Vue.use(plugins);  /使用插件/

⭐5.scoped样式

scoped样式作用:让样式在局部生效,防止冲突。写法

三、案例-Todolist

此处省略了,如果有需要在更新。

四、拓展-浏览器本地储存 (webStorage)

⭐1.localStorage

DOCTYPE html>
<html lang="">
  <head>
    <meta charset="utf-8">
    <title>localStoragetitle>
  head>
  <body>
    <button onclick="saveData()">保存数据button>
    <button onclick="readData()">读取数据button>
    <button onclick="deleteData()">删除数据button>
    <button onclick="deleteAllData()">清空数据button>
  body>
  <script type="text/javascript">
    let p = { name:'张三',age:18 }

    function saveData(){
      localStorage.setItem('msg','你好!');  /这里将前面的window省略了/
      localStorage.setItem('person',JSON.stringify(p))
    }
    function readData(){
      localStorage.setItem('msg','你好!')
      let result = localStorage.setItem('person')
      JSON.parse(result)
    }
    function deleteData(){
      localStorage.removeItem('msg');  /只删除了msg/
    }
    function deleteAllData(){
      localStorage.clear();  /清空所有缓存/
    }
  script>
html>

⭐2.sessionStorage

DOCTYPE html>
<html lang="">
  <head>
    <meta charset="utf-8">
    <title>sessionStoragetitle>
  head>
  <body>
    <button onclick="saveData()">保存数据button>
    <button onclick="readData()">读取数据button>
    <button onclick="deleteData()">删除数据button>
    <button onclick="deleteAllData()">清空数据button>
  body>
  <script type="text/javascript">
    let p = { name:'张三',age:18 }

    function saveData(){
      sessionStorage.setItem('msg','你好!')
      sessionStorage.setItem('person',JSON.stringify(p))
    }
    function readData(){
      sessionStorage.setItem('msg','你好!')
      let result = sessionStorage.setItem('person')
      JSON.parse(result)
    }
    function deleteData(){
      sessionStorage.removeItem('msg');  /只删除了msg/
    }
    function deleteAllData(){
      sessionStorage.clear();  /清空所有缓存/
    }
  script>
html>

五、组件自定义事件

⭐1.组件自定义事件-绑定

示例代码-School组件

/效果: 点击按钮把name给App组件/
<template>
  <div class="school">
    <h2>学校名称:{{name}}h2>
    <h2>学校地址:{{addresss}}h2>
    <button @click="sendSchoolName">把学校名给Appbutton>
  div>
template>
<script>
  export default {
    name: 'School',
    props: ['getSchoolName'],
    data(){ return { name: '尚硅谷',address:'北京' } },
    methods: {
      sendSchoolName(){ this.getSchoolName(this.name) }
    }
  }
script>
<style lang="less" scoped>
  .school{ background-color: red; }
style>

示例代码-Student组件

<template>
  <div class="student">
    <h2>学生名称:{{name}}h2>
    <h2>学生年龄:{{age}}h2>
    <button @click="sendStudentName">把学生名给Appbutton>
  div>
template>
<script>
  export default {
    name: 'Student',
    data(){ return { name: '张三',age:18 } },
    methods: {
      sendStudentName(){
        /触发Syudent组件实例身上的atguigu事件/
        this.$emit('atguigu',this.name)
      }
    }
  }
script>
<style lang="less" scoped>
  .student{ background-color: pink; }
style>

代码示例 - App组件

<template>
  <div class="app">
    <h1 class="title">{{msg}}h1>
    /方法一: 通过父给子传递函数类型props实现:子给父传递数据/
    <School :getSchoolName="getSchoolName"/>
    /方法二: 通过父给子绑定一个自定义事件:子给父传递数据(第1种写法: 使用@或v-on)/
    <Student @atguigu="demo"/>
    /方法三: 通过父给子绑定一个自定义事件:子给父传递数据(第2种写法: 使用ref),灵活性强(如可以绑定时器)/
    <Student ref="student"/>
  div>
template>
<script>
  import School from './components/School'
  import Student from './components/Student'
  export default {
    name: 'App',
    components: { School,Student },
    data(){ return { msg: '欢迎学习Vue!' } },
    methods: { 
      getSchoolName(name){ console.log('APP收到啦学校名',name) },
      demo(name){ console.log('APP收到学生名!',name) }
    },
    mounted(){  /方法三触发/
      this.$refs.student.$on('atguigu',this.demo)
    }
  }
script>
<style>
  .title{ color:green }
style>

⭐2.组件自定义事件-解绑

示例代码-Student组件

<template>
  <div class="student">
    <h2>学生名称:{{name}}h2>
    <h2>学生年龄:{{age}}h2>
    <button @click="sendStudentName">把学生名给Appbutton>
    <button @click="unbind">解绑atguigu事件button>
    <button @click="unbinds">解绑atguigu与demo事件button>
    <button @click="death">销毁当前Student组件的实例button>
  div>
template>
<script>
  export default {
    name: 'Student',
    data(){ return { name: '张三',age:18 } },
    methods: {
      sendStudentName(){
        this.$emit('atguigu',this.name),
        this.$emit('demo')
      },
      unbind(){ this.$off('atguigu')},  /只适用于解绑一个自定义事件/
      unbinds(){ this.$off(['atguigu','demo'])},  /解绑多个自定义事件/
      unAllbind(){this.$off()},  /解绑所有自定义事件/
      death(){ this.$destroy()}  /销毁了当前Student组件的实例/
    }
  }
script>
<style lang="less" scoped>
  .student{ background-color: pink; }
style>

代码示例 - App组件

<template>
  <div class="app">
    <h1 class="title">{{msg}}h1>
    <Student @atguigu="demo" @demo="m1"/>
  div>
template>
<script>
  import School from './components/School'
  import Student from './components/Student'
  export default {
    name: 'App',
    components: { School,Student },
    data(){ return { msg: '欢迎学习Vue!' } },
    methods: { 
      getSchoolName(name){ console.log('APP收到啦学校名',name) },
      demo(name){ console.log('APP收到学生名!',name) },
      m1(){ console.log('demo事件被触发了!')}
    },
  }
script>
<style>
  .title{ color:green }
style>

⭐3.组件自定义事件-总结

组件自定义事件定义:一种组件通讯的方式,适用于:子组件==>父组件
组件自定义事件使用场景:A是父组件,B是子组件,B想给A传数值,那么就要在A中给B绑定自定义事件 (事件的回调在A中)。
绑定自定义事件:第①种写法在父组件中;第②种写法在父组件中.... mounted(){this.$refs.xxx.$on(atguigu,this.test)};若想让自定义事件只能触发一次,可以使用once修饰符或$once方法。
触发自定义事件this.$emit('atguigu',数据)
解绑自定义事件this.$off('atguigu')
组件上也可以绑定原生DOM事件,需要使用native修饰符。
⚠️注意⚠️:通过this.$refs.xxx.$on('atguigu',回调)绑定自定义事件时,回调要么牌子在methods中,要么用箭头函数否则this指向会出问题!

⭐4.全局事件总线

全局事件总线:可以做到任意组件间通信,不是一个新的API,属于总结的组件间数据传输的经验。

/示例代码:main.js文件-安装全局事件总线/
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false

new Vue({
  el:'#app',
  render: h => h(App),
  beforeCreate(){
    Vue.prototype.$bus = this,  /安装全局事件总线,$bus是自定义的可以取任意名/
  }
})

安装全局事件总线语法格式如下

new Vue({
  ......
  beforeCreate(){ Vue.prototype.$bus = this },
  ......
})

使用事件总线示例语法如下

1.接收数据:A组件想接收数据, 则在A组件中给$bus绑定自定义事件, 事件的回调留在A组件自身
methods(){ demo(data){......} },
......
mounted(){ this.$bus.$on('xxx', this.demo) }
2.提供数据: this.$bus.$emit('xxx', 数据)

最好在beforeDestroy钩子中,用$off去解绑==当前组件所用到的=事件。


第三章 vue-router

一、路由的简介

⭐1.vue-router的理解

vue-router定义vue的一个插件库,专门用来实现SPA应用。

⭐2.SPA应用-单页面应用

单页面Web应用。
整个应用只有一个完整页面
点击页面中的导航连接不会刷新页面,只会做页面的局部更新
数据需要通过ajax请求获取。

⭐3.路由的理解

什么是路由? 一个路由就是一组映射关系(value-key)。key为路径,value可能是functioncomponent。的对应关系,多个路由,需要路由器的管理。
路由的分类
▶️后端路由❶理解:valuefunction用于处理客户端提交的请求❷工作过程:服务器接收到一个请求时,根据请求路径找到匹配的函数来处理请求,返回数据。
▶️前端路由❶理解:valuecomponent,用于页面展示页面内容❷工作过程:当浏览器的路径改变时,对应的组件就会显示。

二、基本路由

⭐1. 路由基本使用

1.安装路由命令npm i vue-router
2.在main.js文件中引入路由并应用。
3.编写router配置项,语法结构如下

//1.引入VueRouter 
import VueRouter from 'vue-router'
//2.引入路由组件
import About from '../component/About'

//创建实例对象, 管理一组组的路由规则
export default new VueRouter({
  routes:[
    {path:'/about',component:About}
  ]
}) 

4.实现切换(active-class可配置高亮样式)

About

5.指定展示位置


演示代码如下

<-- 原始html中我们使用a标签实现页面的跳转 -->
<a class="list active" href="./abuot.html">Abouta>  <--list是写好的样式-->
<a class="list" href="./home.html">Homea>
<--App.js文件代码如下-->
<template>
  ......
  <--Vue中借助router-link标签实现路由的切换-->
  <router-link class="list" active-class="active" to="/about">Aboutrouter-link>  
  <router-link class="list" active-class="active" to="/home">Homerouter-link>
    ...
    <--指定组件的呈现位置-->
    <router-view>router-view>
    ...
  ......
template>
/main.js文件-引入路由/
import Vue from 'vue'
import App from './App.vue'     ,/1.引入路由/
import VueRouter from './App.vue'

Vue.config.productionTip = false
VUe.use(VueRouter)  ,/2.应用插件/

new Vue({
  el:'#app',
  render: h => h(App),
  /3.引入后就可以写router配置项了, router必须是函数/
  router: router,
})
/router文件夹中index.js文件-该文件专门用于穿件整个应用的路由器/
import VueRouter from 'vue-router'
,/1.引入组件/
import About from '../component/About'  ,/这是写好的组件/
import Home from '../component/Home'

,/2.创建一个路由器/
const router = new VueRouter({
  routes:[
    {path:'/about',component:About},
    {path:'/home',component:Home}
  ]
})

,/3.暴露/
export default router

,/直接简写如下/
/* export default new VueRouter({
  routes:[
    {path:'/about',component:About},
    {path:'/home',component:Home}
  ]
}) */

⭐2.几个注意点

1.路由组件通常存放在pages文件夹,以班组间通常存放在components文件夹。
2.通过雀环,"隐藏"了路由组件,默认是被销毁的,需要的时候再去连接。
3.每个组件都有自己的$route属性,里面存储着自己的路由信息。
4.整个应用只有一个router,可以通过组件的$router属性获取到。

⭐3.嵌套(多级)路由

1.配置路由规则,使用children配置项。

router:[
   {
     path:'/about',
     component:About,
     children:[
       {path:'/news',component:News},
       {path:'/message',component:Message}
     ]
   }
]

2.跳转(需要写完整路径)

News

⭐4.路由传参query

1.传递参数

<-- 跳转并携带query参数,to的字符串写法 -->
跳转

<-- 跳转并携带query参数,to的对象写法 -->
跳转

2.接收参数

$route.query.id
$route.query.title

⭐5.命名路由

命名路由作用:简化路由的跳转。
1.给路由命名

{  这是一个三级路由
  path:'/about',
  component:About,
  children:[
    { path:'test',
      component:Test,
      children:[
        { name:'hello',  //⚠️给路由命名
          path:'welcome',
          component:Hello,}
      ]
    }
  ]
}

2.简化跳转

<-- 简化前, 需要写完整的路径 -->
跳转

<-- 简化后, 直接通过名字跳转 -->
跳转

<-- 简化写法配合传递参数 -->
跳转

⭐6.路由传参params

⑴ params的基本使用

1.配置路由,声明接收params参数

{
  path:'/about',
  component:About,
  children:[
    { path:'test',
      component:Test,
      children:[
        { name:'hello',
          path:'welcome/:id/:title',   ⚠️//使用占位符声明接收params参数
          component:Hello,}
      ]
    }
  ]
}

2.传递参数

<-- 跳转并携带params参数, to的字符串写法 -->
跳转

<-- 跳转并携带params参数, to的对象写法 -->
跳转

⚠️特别注意⚠️:路由携带params参数时,若使用to的对象写法,则不能使用path配置项,必须使用name配置项。

3.接收参数

{{$route.params.id}}
{{$route.params.title}}  ⚠️这个参数接收方式不简便, 在**⑵props配置项**中讲解简便写法

⑵ params配置项

{
  path:'/about',
  component:About,
  children:[
    { path:'test',
      component:Test,
      children:[
        { name:'hello',
          path:'welcome/:id/:title',   ⚠️//使用占位符声明接收params参数
          component:Hello,
          //▶️props第一种写法, 值为对象, 该对象所有key-value都会以props形式传给Hello组件
          //  props: {id:666,title:'你好'},

          //▶️props第二种写法,值为布尔值,若为真就会把该路由组件收到的所有params参数,以props的形式传给Hello组件
          //  props: true,
          
          //▶️props第三种写法, 值为函数
          props($route){  //⚠️或把$route换成解构赋值{query}形式
            return {id:$route.params.id,title:$route.params.title}
          }
        }
      ]
    }
  ]
}

⭐7.router-link的replace属性

replace属性的作用:控制路由跳转时操作浏览器历史记录的模式。
浏览器的历史记录有两种写入方式:分别为pushreplacepush是追加历史记录,replace是替换当前记录,路由跳转时默认为push
如何开启replace模式:跳转

⭐8.编程式路由导航

编程式路由导航作用:不借助实现路由跳转,让路有更加灵活

示例代码如下

$router的两个API, push()&&replace()
this.$router.push({
  name:'xiangqing',
  params:{id:xxx,title:xxx}
})
this.$router.replace({
  name:'xiangqing',
  params:{id:xxx,title:xxx}
})

this.$router.forward()  //前进
this.$router.back()  //后退
this.$router.go()  //去往指定页面, 可前进也可后退

⭐9.缓存路由组件

缓存路由组件作用:让不展示的路由组件保持挂载,不被销毁,语法结构如下

 ⚠️如不写include属性,代表所有的router-view中所有层级都缓存不销毁
    


 ⚠️缓存多个
    

⭐10.两个新的生命周期钩子

思考一种情况,若某组件即含有缓存路由组件也有类似含有定时器这样需要销毁的组件,怎么办?
要解决该问题就引入了两个新的声明周期钩子,▶️activated()激活的▶️deactivated)()失活的该钩子是路由组件独有的
作用:路由组件所独有的两个钩子,用于捕获路由组件的激活状态。

⭐11.路由守卫

路由守卫作用:对路由进行权限控制。
路由守卫分类:▶️全局守卫、▶️独享守卫、▶️组件内守卫。

⑴ 全局路由守卫

1.全局前置路由守卫-⑴初始化时会调用 ⑵每次路由切换之前调用

router.beforeEach((to,form,next) => {
  ⚠️`meta.isAuth`是在写路由信息时,定义在meta属性中isAuth信息,书写习惯
  if(to.meta.isAuth) {  //判断当前路由是否需要进行权限控制
    if(localStorage.getItem('school') === 'atguigu') {
      alert('暂时无权限查看')
    } else { next()  //放行  }
  }
});

2.全局后置路由守卫-⑴初始化时被调用 ⑵每次路由切换之后调用

router.afterEach((to,form) => {
  if(to.meta.title) {
    document.title = to.meta.title  //修改网页的title
  } else {
    next(   document.title = '登录页' )
  }
})

⑵ 独享路由守卫

⚠️注意⚠️:独享路由守卫没有后置路由!!!

  path:'/about',
  component:About,
  children:[
    { path:'test',
      component:Test,
      beforeEnter(to,form,next){
        if(localStorage.getItem('school') === 'atguigu') {
          alert('暂时无权限查看')
        } else { 
          next() 
        }
      }
    }
  ]

⑶ 组件内路由守卫

export default {
  name:'About',
  mounted(){},
  beforeRouterEnter(to,form,next){},  //通过路由规则, 进入该组件时被调用
  beforeRouterLeave(to,form,next){},  //通过路由规则, 离开该组件时被调用
};

⭐12.路由器的两种工作模式

对于一个url来说,什么是hash值?----- #及其后面的内容就是hash值。
hash值不会包含在HTTP请求中,即:hash值不会带给服务器。
▶️1. hash模式:
❶地址中永远带着#号,不美观
❷若以后将地址通过第三方手机app分享,若app校验严格,则地址会被标记为不合适
❸兼容性好。
▶️2. history模式:
❶地址干净,美观
❷兼容性和hash模式相比略差
❸应用部署上线时需要后端人员支持,解决刷新页面服务端404问题。


第四章 vuex

一、vuex简介

⭐1.理解vuex

vuex是什么:vuexvue中实现集中式状态(数据)管理的一个插件,对vue应用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间的通讯的方式,且适用于任意组件间通信。
什么时候使用vuex 多个组件同一依赖状态;来自不同组件的行为要变成同一状态。(共享)

⭐2.vuex工作原理图

前端学习笔记____Vue2+Vue3全家桶_第8张图片

二、Vuex的基本使用

⭐1.搭建vuex环境

❶首先使用npm i vuex安装Vuex
❷其次Vue.use(Vuex)全局应用;
❸建立store仓库管理上图的3个对象actionsmutationsstate,第一种方法Vuex文件夹中创建store.js文件;第二种方法store文件夹中创建index.js文件,文件内容如下

/该文件用于创建Vuex中最为核心的store/
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
//准备actions用于响应组件中的动作
const actions = {
  jia(context,value){context.commit('JIA',value)}
}
//准备mutations用于操作数据(state)
const mutations = {
  JIA(state,value){state.sum += value}
}
//准备state用于存储数据
const state = { sum:0 }

//创建并导出store
export default new Vuex.Store({
  actions,
  mutations,
  state
})

❹使所有的vc都可以看到store

/在组件中读取vuex中的数据:/
$store.state.sum;
/组件中修改vuex中的数据:/
$store.dispatch('mutations中的方法名',数据)
$store.commit('action中的方法名',数据)

⭐2.getter配置项

上文中我们提到三个常用的配置项actions mutations state,他们是vuex文件中必须配置的项,而getter就作为知识扩展进行了解。

/该代码也是写在Vuex中最为核心的store的文件中/
//准备state用于将state中的数据进行加工
const getter = {
  bigSum(state){
    return state.sum*10
  }
}

export default new Vuex.Store({
  actions,
  mutations,
  state,
  getter
})

总结: 这个Vuex中的getter对象与计算属性computed非常类似,只不过更好的在Vuex中复用。


第五章 element-ui


第六章 vue3

第四-六章暂时不更新…

你可能感兴趣的:(自学前端,自学vue,怎么学习前端,前端,vue)