Vue2(学习张天禹老师讲解vue2的笔记)

Vue2

vue项目运行时npm版本过低

在终端先输入$env:NODE_OPTIONS="--openssl-legacy-provider"
然后 npm run serve

vue特点

  1. 组件化开发,提高开发效率
  2. 声明式编码,不需要操作DOM,提高开发效率
  3. diff算法,DOM元素复用,提高效率

创建vue实例

为了构建一个Vue应用程序,就是说可以使用vue这种技术了

new Vue({
            el: '#root',
            data: {
                name: "尚硅谷"
            },
            //方法都写在methods里
            methods: {
                showInfo1() {
                    alert("hello")
                }
            }
        });

js表达式和js语句

js表达式:会产生一个值(a,b,a+b,demo(1))

js语句:控制代码的运行 (for循环,if判断)

数据动态绑定

  • 1.单向绑定

    v-bind 可以简写为 :

    <input type="text" :value="name"> <!-- 单向绑定 -->
    

    只能从data中将数据渲染到页面,页面数据的变化不能影响到data中的数据变化


  • 2.双向绑定

    v-model=“”,只能用于表单类元素

    <input type="text" v-model="name"> <!-- 双向绑定 -->
    

    可以从data中将数据渲染到页面,页面数据的变化也可以改变data中的数据


v-model的修饰符

  1. number 就是将输入的值转为数字类型
<input type="text" v-model.number="n1"/>

2.trim 过滤首位的空格

<input type="text" v-model.trim="msg"/>
  1. lazy 光标移走才将输入的数据存储到data中
<input type="text" v-model.lazy ="msg"/>

MVVM模型

image-20240206015132676

M :data中的数据

V:页面

VM:创建的vue实例

总的来说,就是将data中的数据通过vue实例渲染在页面,页面数据的变化也可以改变data中的数据

data中所有属性最终都会出现在vm上

vm上所有属性和vue原型上所有属性都可以在{{ }}中直接输出


defineProperty

  • 给对象添加属性

    Object.defineProperty(person, 'age',{value:18 })
    

    第一个是对象名,第二个为要添加的key,第三个为配置项{value:19}

    defineProperty这个方法增加的属性不能被遍历、删除、更改

    image-20240206015153182

  • get() set()方法

 let number = 18;
        let person = {
            name: "张三",
            sex: "男"
        };
        Object.defineProperty(person, 'age', {
            //当有人读取person.age时,函数被调用,就会返回一个值
            get() {
                console.log("有人读取了age的值");
                return number;
            },
            //当有人修改person.age时,函数被调用,且会收到修改的值
            set(value) {
                console.log("有人修改了age的值");
                number = value;
            }
        });

数据代理

  • 通过一个对象代理另一个对象中属性的操作

      let obj1 = { x: 200 };
      let obj2 = { y: 300 };
      Object.defineProperty(obj2, "x", {
          get() {
              return obj1.x;
          },
          set(value) {
              obj1.x = value;
          }
      })
    
    

    vue中的数据代理

    1. 将data中的数据挂载到vm上的_data属性中
    2. _data中的每一个属性配置一个getter、setter,进行数据代理,就是进行数据的读写操作,也是挂载到vm实例上
    3. vm.name可以修改_data中name的值,这就是数据代理,通过一个对象来修改另一个对象的属性值

插值语法

  • 可以在{{}}中进行一些简单的js表达式运算

​ {{num+1}} {{message.split(‘’)}}

  • vm上存在的属性,以及vue原型上的属性,都可以插入

事件处理

  • 事件的基本使用

    1.用v-on:xxx 或@xxx绑定事件 xxx是事件名

    2.事件的回调函数需要配置在methods中

    3.methods中的函数中this指向的是vm或是组件实例对象

  • 事件的传参

    1. @click="add"不传参,但在methods中add(e)方法会接收到一个参数e,也就是鼠标事件,就会获取的事件触发的DOM元素e.target

    2. click="add(1)"就是简单传参 在methods中add(n),n就是1

    3. @click=“add(1,$event)”,第一个参数就是n,第二个参数就是鼠标事件,在methods中add接收两个参数
      add(n,e)


<button @mouseover="showInfo1(66,$event)">点我提示</button>

 new Vue({
            el: '#root',
            data: {
                name: "尚硅谷"
            },
            //方法都写在methods里
            methods: {
                showInfo1(number) {
                    alert(number)
                }
            }
        });

事件修饰符

修饰符可以连续写(.prevent.stop)

  • prevent:阻止默认事件发生

    <a href="http:baidu.com" @click.prevent="showInfo1">点我</a>
    
  • stop:阻止冒泡事件发生

 <div @click="showInfo1">1
            <div @click.stop="showInfo1">2</div>
 </div>
  • once:事件只发生一次
 <button @click.once="showInfo1">点击</button>

键盘事件

  • 键盘输入完成之后,按下enter键,调用函数
 <input type="text" @keyup.enter="showInfo1">
  • 配合keyup使用

image-20240206015210400

  • 配合keydown使用 (tab\alt\shift\meta\ctrl)

    image-20240206015223235


计算属性

  • 计算属性要写在computed中,必须要return
  • vm直接调用computed里的函数,将结果返回,所以使用时直接用插值语法写方法名,不用调用了
  • 计算属性最终会出现在vm上,所以直接当属性使用即可
  • 计算属性只调用一次,有缓存机制,重复使用时只执行一次,效率更高,并且方便调试
  • 计算属性靠get和set来实现,只要计算属性用到的变量发生变化,就会重新渲染
 computed: {
     fullName() {
                    return this.firstName + this.lastName;
                }
               }
//对象形式(可以进行修改操作setter)
computed:{
    fullName:{
        get(){
            return this.firstName + this.lastName;
        },
        set(newVal){
            let arr = newval.split('-');
            this.firstName = arr[0];
            this.lastName = arr[1];
        }
    }
}

过滤器

定义在filters下

在过滤器函数中一定要有一个return,不改变原数据,产生新的相对应的数据,多个过滤器可以串联

过滤器函数有一个形参,就是管道符前面的参数

//跟methods一样
filters:{
  cai(val){
      return val+1//val是
  }
}
<p> {{number | cai}}</p>

全局过滤器

Vue.filter()接收两个参数,第一个是全局过滤器的名字,第二个是全局过滤器的处理函数

Vue.filter('cap',(num)=>{
    return num++;
})

使用场景:1. 配合插值语法,对数据进行特定的格式化 <p> {{number | cai}}</p>

​ 2.配合v-bind

image-20240206015250372

监视属性

  • 监视数据的(data)变化,只要发生变化就被调用
  • 要监视那个数据变化,就把数据名作为方法名
  • 深度监视可以监视一个对象内部属性的变化,函数格式不可以监视,vue自身可以监视对象内部属性,watch默认不可以!
  • 可以用来判断用户名是否被占用,可以开启定时器等异步任务
//对象格式
watch:{
    data上的属性名:{
        immediate:true; //mounted时被调用
        deep:true; //深度监视
        handler(newValue,oldValue){
            
		}
     }
 }
//函数格式
watch: {
	 data上的属性名(newValue,oldValue){
 }
    //如果监听对象的子属性,深度监听
    'info.username'(){
        
    }
}

class绑定

将要动态切换的class用v-bind绑定即可,最终class样式会将动态变化和不变的合并起来

  • class绑定对象 :class=“对象名” 用来控制哪几个样式显示或隐藏

      <div class="box" :class="activeObj"></div>
      new Vue({
          el: '#root',
          data: {
            activeObj:{
              active: true
            },
          },
          methods: {
            btnClick() {
              this.activeObj.active = !this.activeObj.active; //太妙了!!!
            }
          },
        });
    
  • 数组绑定class 增加或删除样式

 <div class="basic" :class="mood"></div>
 new Vue({
            el: '#root',
            data: {
                mood: ["happy", "sad", "normal"]
            },
           methods: {
           btnClick() {
                this.mood.push('sad');
                this.mood.pop();
        }
      },
        });
  • 字符串类型 直接更改class名称,点击切换class类型
<div class="box" :class = "active"></div>
new Vue({
            el: '#root',
            data: {
                active:'sad';
            },
           methods: {
           btnClick() {
                this.active = 'happy';
        }
      },
        });

绑定style样式

 <div :style="styleObj">hello</div>
  new Vue({
            el: '#root',
            data: {
                styleObj: {
                    fontSize: "40px",
                    color: "white"
                }
            },
        });


条件渲染

  • v-if

    1.适用于切换频率较低的场景

    2.不展示的dom元素直接被删除,只能与v-if配合使用,不可以跟v-show

    3.可以连用

    ​ v-if=" "

    ​ v-else-if =" "

    ​ v-else=" "

    必须要写在一起,结构不能被打断

            <h2 v-if="n===1">1</h2>
            <h2 v-else-if="n===2">2</h2>
            <h2 v-else-if="n===3">3</h2>
            <h2 v-else>4</h2>
    
  • v-show

    1.适用于切换频率较高的场景

    2.不展示的dom元素被隐藏 (display:none类似)

     <h2 v-show="n===1">hello</h2>
    

列表展示

  • 遍历数组 item是每一个对象,index为索引

    <li v-for="(item,index) in person" :key="item.id">
     {{item.name}}---{{item.age}}
    </li>
    
  • 遍历对象 第一个收到的是值,第二个是键

    <li v-for="(value,key) in car" :key="k">
     {{value}}---{{key}}
    </li>
    
  • 遍历数组 item就是每一个数组元素

  • 生成1-n的数字,索引还是从0开始

v-for='item in 10'  ==>1,2,3...10

列表过滤

使用filter函数对数组操作

filterPerson(){
  return this.person.filter((item)=>{
    return item.name.indexOf(this.keyWord) != -1; //===> return []
})

将filter产生的新数组return出去,数组名为filterPserson

列表排序

使用sort方法对数组操作

filterPerson(){
                const arr = this.person.filter((item)=>{
                  return item.name.indexOf(this.keyWord) != -1;
                })
                if(this.sortType){
                  arr.sort((a,b)=>{
                  return this.sortType == 1 ? a.age - b.age : b.age - a.age;
                })
                }
                return arr;
            }

key和diff算法

key是虚拟DOM对象的标识,当数据发生变化时,vue会根据根据新的数据形成新的虚拟DOM,然后新的DOM会与旧的DOM元素进行比对,最终将虚拟DOM转换为真实DOM

  1. 新旧的key相同的虚拟DOM:比较他们的内容是否一致,一致则直接复用。不一致的部分重新生成真实的DOM
  2. key不同的虚拟DOM:创建新的真实的DOM,渲染到页面

vue的响应式

为了实现响应式页面,通过对data中的数据进行加工,为每一个data中的属性加了getter和setter,只要data中数据一改变,set就被调用,并且重新解析模板,实现页面的更新。

Vue.set

vue中如果要给对象直接加一个属性如this.person.age=18,vue会监听不到对象的改变,页面也不会显示,age也不会配置get,set

如果想让后增加的属性具有get,set,可以使用vue.set('this.person','age',18)这种方式,set的第一个配置对象不能是vm和vm.data,只能是data中的对象

只要是data中的对象,vue就会为其属性配置setter和getter,在数组中的对象也是,只要修改对象中的属性就会重新解析模板

  • 只能给data数据中的对象数据上增添一个新的属性

    Vue.set(target,key,value)

    Vue.set(this.person, "sex", "男")
    

数组元素的更新

vue没有为数组元素配置get,set,直接更改数组元素,vue不会监听改变,也不会渲染到页面

  1. vue中数组元素如果arr[0]='hello'这样进行修改,vue将无法监听到数组的变化,因为没有配置get,set

  2. 正确做法是使用一下7个方法或创建一个新的数组来接收过滤后的元素,来展示到页面

  • 可以用Vue.set(this.person, 0, “男”) 0代表数组中元素的索引值,将数组中索引为0的元素改为男

  • vm.person.push(“男”) 使用数组方法 vm.person.splice(0,1,“男”)

  • splice(从第几个元素开始,删除几个,在删除元素的位置添加的新元素)

    var arr = [1,2,3,4,5];
    
    // 添加
    arr.splice(0,0,0);// [0,1,2,3,4,5]
    
    // 修改
    arr.splice(0,1,23);// [23,1,2,3,4,5]
    
    // 删除
    arr.splice(0,1);//[1,2,3,4,5]
    

    这些方法可以实现数组元素的更新,让页面发生更新

    这些方法都改变的是原数组,不产生新数组


##收集表单提交数据

image-20240206015306644

爱好<input type="checkbox" v-model="hobby" value="足球">足球   //复选框的value配置之后,hobby写成[],收集到的就是['足球'],如果不配置value,hobby是'',收集的
                                                                true/false
性别<input type="radio" v-model="sex" name="sex" value="男"><input type="radio" v-model="sex" value="女">//单选框value必须配置,name属性必须一致

@change 和 @click的区别

@change 是在内容改变的时候触发 @click是在点击的时候触发,此时内 容还没有改变

##v-html

可以直接解析html模板,但具有安全性的风险,一般表单提交不能使用v-html

image-20240206015319589

image-20240206015331586

v-cloak

防止页面因为网速慢没有解析完vue模板而出现{{XXX}}的问题

在vue实例创建完毕并接管容器之后就会删除该属性

配合css使用[ v-cloak]:{display:none} [v-clock]属性选择器

 <h2 v-cloak>{{name}}</h2>
 [v-cloak]: {
    display:none;
 }

v-once

  • 从vue的data中第一次渲染到界面之后,data中数据的变化不再影响页面

    <h2 v-once>{{name}}</h2>
    

v-pre

直接跳过vue的解析,渲染到页面

一般在没有用到vue的插值语法、指令语法的节点,加快编译速度

<h2 v-pre>hello,world</h2>
<h2>{{name}}</h2>

自定义指令函数式

  1. 把要构造的指令写在directives:{ }, 跟methods类似

  2. 在标签里写v-big,在directives中构造是就只用big(){}

  3. 只要data中数据发生改变,模板重新解析时,就会重新调用该函数

  4. 相当于对象式的bind和update

     <h2 v-big="n"></h2>
     directives: {
            big(element, binding) {
              element.innerHTML = binding.value * 10;
            }
    

    element是添加指令所对应的DOM元素,binding是将指令与元素绑定,binding.value就是n


自定义指令对象

对象中包含三个回调函数

1.bind(element,binding){ } 当指令与元素绑定成功时调用

2.inserted(element,binding){ } 当指令所对应的元素插入到页面后调用

3.update(element,binding){ } 当data中数据发生变化时调用

directives: { 
        fbind: {
          //当元素与指令绑定成功时,相当于初始化时就别调用
          bind(element, binding) {
            element.value = binding.value;
          },
          //当vue将元素插入到页面后
          inserted(element, binding) {
            element.focus();
          },
          //当data数据变化时,重新调用
          update(element, binding) {
            element.value = binding.value;
          }
        }
      }

生命周期

image-20240206015348236

beforeCreate:无法通过vm去访问 data/props/methods,初始化声明周期、事件,没有开始数据代理,数据监测

created: data/props/methods都可用,可以通过vm去访问,但组件的结构尚未生成,不能操作DOM,只是在内存中生成了 HTML结构

beforeMount: 页面生成vue未解析的DOM元素,只是将要将内存中的HTML结构渲染到页面

mounted:生成经过vue解析后DOM元素,页面渲染到浏览器,可以操作DOM元素了

数据变化之后执行

{

beforeUpdate:data中数据更新完成,页面还没修改,还是旧数据,相当于data中数据是新数据,页面还是旧数据,还没有将data数据渲染到页面

当数据变化之后,操作DOM元素,就用updated

updated:页面和数据都是data更新后的,最新的数据

}

this. d e s t o r y ( ) 销毁组件 v c , v m 。执行 t h i s . destory()销毁组件vc,vm。执行this. destory()销毁组件vc,vm。执行this.destory()之后,vc,vm上的自定义事件全部不奏效了

image-20240206015408400

//vue解析完模板挂载到页面上
mounted(){
    
},
//vm销毁时
beforeDestory(){
    clearInterval(timer)
}

组件

实现局部功能代码和资源的集合(将html,css,js,视频、文字样式等资源统一起来)

复用率高,好维护

单文件组件 .vue 一个文件只有一个组件

创建组件 :

const school = Vue.extend({
    data() {
        return {
          studentName: "小王",
          age: 18
        }
      }
})
//可以简写为
const school = {
    data() {
        return {
          studentName: "小王",
          age: 18
        }
      }
}

Vue.extend({})返回一个构造函数vueComponent

组件名

image-20240206015422103

可以在组件中配置name:‘school’,在vue开发者工具中就会显示该组件名

data为什么要写成函数形式

data(){
    return{
        a:1,
        b:3
    }
}

这样当不同的地方使用该组件时,都会返回一个全新的对象,别的地方修改对象数据,互不影响

VueComponent

每一个组件就是一个构造函数vueComponent,是Vue.extend生成的

当在模板中写时,vue会帮我们创建一个vc的实例对象,即new VueComponent({options}) options是Vue.extend({})中配置的属性

不同的组件是不同的构造函数vueComponent,虽然都差不多,但是return出来的,是不同的vueComponent

vc和vm区别

vc和vm99%相似,都有数据代理,数据监测,methods,computed…

区别:vm有el来确定放置DOM元素的位置,vc没有el

​ vc中的data必须写成函数式,vm的data可以直接写成对象(不在脚手架中)


生成模板快捷键

<v

##一个重要的内置关系

image-20240206015448618

为了让vc也可以访问到vue原型上的属性和方法

构造函数有一个显式原型属性prototype来找到构造函数原型对象

构造函数的实例对象有一个隐式原型属性–proto–也是指向构造函数的原型对象

构造函数的原型对象有一个–proto–属性来指向object的原型对象


初始化脚手架

image-20240206015503905

先设置一下淘宝镜像,在create项目前

npm config set registry https://registry.npm.taobao.org/


脚手架结构

执行npm run serve 之后

  1. 执行main.js文件 该文件是整个项目的入口文件
import Vue from 'vue' //引入vue
import App from './App.vue' //引入App组件,他是所有组件的父组件

Vue.config.productionTip = false //关闭vue的生产提示

new Vue({
  render: h => h(App),
}).$mount('#app')

  1. assets文件夹中配置静态资源(图片,音频等)
  2. components文件夹中写组件

render函数

创建html元素,解析组件模板

image-20240206015520262

##vue的项目流程

  • 就是通过main.js将App组件渲染到页面指定位置
  • main.js就是vue项目的入口文件,是将App组件渲染到index.html文件的预留区域
  • render函数是创建App.vue的模板
  1. 先访问main.js
  2. 访问App.vue ,再访问App.vue中的子组件
  3. 解析App.vue模板,并挂载到指定的容器中

vue.js和vue.runtime.vue.js

只要有runtime就代表是运行版本的vue,不包含模板解析器,只能用render函数来解析模板

image-20240206015543589


$nextTick

  1. this.$nextTick(回调函数)

  2. vue在解析模板时,不会立即更改,只有将代码执行一遍后统一重新解析

  3. 只有在DOM元素更新到页面之后才执行函数体内代码

    this.$nextTick( () =>{
            this.$refs.inputTitle.focus();
          });
    

mixin混入

  • 配置mixin.js文件,写一些共用的方法,数据

    export const hunru = {
      methods: {
        showName() {
          alert(this.name)
        }
      }
    }
    
  • 在需要用到的组件里引入mixin.js文件

    import { hunru } from "../mixin";
    
  • 且要在组件里配置mixins属性

    mixins: [hunru],
    
  • ==全局混合 > vm和所有vc都会得到mixin.js中的方法

    (1)将mixin.js引入到main.js中

    (2)Vue.mixin(hunru)


插件(plugins.js)

  • 为了增强vue,在插件里写一些方法和数据,在vm和vc中都可以使用

  • 定义插件

    创建一个插件的js文件

    image-20240206015559868

  • 使用插件

    1.在main.js中引入插件js文件

    2.使用插件

    Vue.use(插件名)
    

scoped

  • 写在style标签里,为了使相同class名在不同组件中使用

    <style scoped>
    </style>
    
  • 父组件里修改子组件的样式,在使用第三方组件库时,修改组件默认样式

    /deep/ h5{}


浏览器本地储存

1.浏览器通过localStorage和sessionStorage属性来实现本地储存

2.localStorage保存一些数据,关闭浏览器,再次打开是数据还在

3.sessionStorage存一些数据,随着浏览器的关闭而消失

  • 添加一个数据

    localStorage.setItem('msg','hello')
    sessionStorage.setItem('msg','hello')
    

    都是以字符串形式储存,第一个是key,第二个是value

  • 读取数据

    localStorage.getItem('msg')
    //没有对应的value会返回NUll
    
  • 删除某个数据

    localStorage.removeItem('msg')
    
  • 删除所有数据

    localStorage.clear()
    

父子组件传参

父向子传参,props

image-20240206015613534

props属性,父向子传参

  • props传过来的属性,会直接出现在vc实例上,所以可以在插值语法中直接使用

  • props是只读的,不能修改props的值

  • 如果从父组件里传的参数是通过axios请求得来的,在created、mounted中无法得到该值,可以通过watch属性监听该props属性,将值存入data中。而且必须用watch的对象方式监听。

  • 让组件接受外部传来的数据

    ​ (1)传递数据到组件

    <Student name="郭彦孚" sex="男" :age="1" />
    

    ​ (2)接受数据

    ​ 1.简单接收

     props: ["name", "sex", "age"]
    

    ​ 2.限制类型 限制必要性 指定默认值

    image-20240206015628331

  • props中的数据名不能和data中的数据名相同,props的优先级更高,会优先显示props中属性名的值

  • :age=“js表达式”

  • 组件中先读取props中的数据

  • props中传过来的数据不能改变,如果要改变复制一份放入data中,且不能同名

    props: ["name", "sex", "age"],
    data() {
        return {
          myAge: this.age,
        };
      },
    methods: {
        add() {
          this.myAge++;
        },
      }, 
    

##自定义事件(子向父传值)

1.主要实现子向父组件进行数据传递

2.和click等内置事件一样(@click=“”),要在父组件中给子组件添加一个自定义事件,父组件会收到子组件传过来的值

​ 也可以添加事件修饰符.once之类的

<School @getSchoolName="schoolName" />
methods: {
 schoolName(name) {
   console.log("我的学校是" + name);
 },
},

3.在子组件内用$emit(“自定义事件名”,要传的参数) 来使用该自定义事件

methods: {
    send() {
      this.$emit("getSchoolName", this.name);
    },
  },

4.解绑自定义事件

  • 解绑一个自定义事件

    this.$off(“自定义事件”)

  • 解绑多个自定义事件

    this.$off([“自定义事件“,”自定义事件”])

  • 解绑所有自定义事件

​ this.$off()

第二中方法:父组件先给子组件一个函数,子组件调用该函数进行传值


子组件使用原生事件

使用一个事件修饰符(.native)

vue会将写在组件中的事件都看做自定义事件,要想触发原生的事件,要加.native

<School @click.native="schoolName" />


##ref属性

  • 就是id的替代者

    ​ (1)可以在组件标签和html标签中添加ref=“xxx”

    ​ (2)应用在html标签上时获取的是真实DOM元素,在组件中获取的是组件的实例对象vc,然后就可以调用该组件的方法和数据

    ​ (3)获取时this.$refs.xxx

  • ref可以加在组价标签里,得到这个组件的实例对象,实现父组件直接调用子组件的方法和数据,给子组件绑定事件

this.$ref.student.$on('自定义事件名',回调函数),这个要在mounted函数中执行

##全局事件总线

  1. 实现任意组件间的通信

  2. 数据发送方,调用 e m i t ( ′ 事件名 称 ′ , 要发送的数据 ) 数据接收方,调用 emit('事件名称',要发送的数据) 数据接收方,调用 emit(事件名,要发送的数据)数据接收方,调用on(‘事件名称’,事件处理函数) 最后在beforeDestory()函数中解绑自定义事件

  3. 安装全局事件总线$bus

    o n , on, on,emit, o f f 属性只有在 v u e . p r o t o t y p e 上才有,而 v c , v m 都可以访问 v u e . p r o t o t y p e ,所以每个组件都可以获得 off属性只有在vue.prototype上才有,而vc,vm都可以访问vue.prototype,所以每个组件都可以获得 off属性只有在vue.prototype上才有,而vc,vm都可以访问vue.prototype,所以每个组件都可以获得on, e m i t , emit, emit,off属性,将 b u s 绑定在 v u e . p r o t o t y p e 上,每个组件都可以看见它,并且将 bus绑定在vue.prototype上,每个组件都可以看见它,并且将 bus绑定在vue.prototype上,每个组件都可以看见它,并且将bus配置为vm,即 b u s 也会拥有 bus也会拥有 bus也会拥有on, e m i t , emit, emit,off属性

    new Vue({
      render: h => h(App),
      beforeCreate() {
        Vue.prototype.$bus = this   //this就是vm
      }
    }).$mount('#app')
    
  4. 使用事件总线

    1. 接受数据:A组件想接受数据,就在A组件中给$bus绑定自定义事件,事件的回调留在A组件

        methods: {
          //改变done的值
          checkTodos(id) {
            this.todos.forEach((todo) => {
              if (todo.id == id) todo.done = !todo.done;
            });
          },
        },
        mounted() {
          this.$bus.$on("checkTodos", this.checkTodos); 
          //第一个是事件名,第二个是要执行的回调函数,也可以直接写成箭头函数
          this.$bus.$on('checkTodos',(val)=>{
              this.todos = val
          })
        },
        beforeDestroy() {
          this.$bus.$off("checkTodos");
      },
      
      
    5. 提供数据
      this.$bus.$emit("checkTodos", id);
    

消息订阅与发布

一种任意组件间通信的方式

使用步骤:

	1. 安装pubsub:``npm i pubsub-js``
	1. 在需要通信的组件中引入 ``import pubsub from 'pubsub-js'``
	1. 在接受数据的组件中订阅消息
mounted(){
    this.pid = pubsub.subscribe('事件名',回调函数)  //每一个订阅消息都会返回一个id,要在beforeDestory中取消订阅
}beforeDestroy() {
    pubsub.unsubscribe(pid)
},
  1. 提供数据的组件中发布消息 pubsub.publish('事件名',数据)

动画效果

用把实现动画的内容包裹,中可以增加name属性,appear:页面一出现就有动画效果

css样式

.v-enter-active{
  animation: change 1s;
}
.v-leave-active{
  animation: change 1s reverse;
}

@keyframes change {
  from{
    transform: translateX(-100%);
  }
  to{
    transform: translateX(0px);
  }
}

##第三方动画库

  1. 安装动画库 npm install animate.css

  2. 引入 import 'animate.css'

  3. 配置样式

<transition name="animate__animated animate__bounce" enter-active-class="animate__rubberBand" leave-active-class="animate__bounceOut">
      <h1 v-show="isShow" class="title">hello</h1>
</transition>

动态切换组件

<component is="组件名"> </component>

is表示出现的组件是那个,组件名要和引入的一致

<div>
    <component :is="comName"></component>
</div> 
data() {
    return {
      comName: "Left",
     };
  },

在切换组件时,隐藏的组件会被销毁,显示的组件会重新渲染,之前的数据不会被保留

使用keepalive可以保留组件不被销毁,数据保存

 <keep-alive> <component :is="comName"></component></keep-alive>

可以使用include=“组件名” 来选择要进行缓存的组件

<keep-alive include=“Left,Right”>
     <component :is="comName"></component>
</keep-alive>

插槽

就是在复用组件时,对复用组件的html结构进行调整

  1. 默认插槽

​ 在组件标签里添加html结构,该html结构会插入到该组件里的位置

//在引入top组件的文件里,在top标签里直接添加html结构
<Top>
    <p>hello,world</p>
</Top>

//top组件中,在想插入的位置摆放<slot>标签
<template>
  <div>
    <slot></slot>
  </div>
</template>
  1. 具名插槽

​ 每个slot标签都有name属性 <slot name='left'></slot>组件标签里加的元素要加上slot="left"

<Left>
     <template v-slot:left>      //v-solt:指定插槽,只有在template中  v-slot:简写为# 
       <p>hello</p>
     </template>
</Left>

<Top>
 <p slot="left">hello,world</p>  
 <p slot="left">hhhh</p>         
</Top>
  

//left组件
<div>
     <slot name="left"> </slot> //可以直接在slot标签中写内容,称为后备内容,当组件没有传内容时,默认显示
</div>
  1. 作用域插槽

还可以传值 父组件直接可以获得子组件传的值

数据在子组件,结构由父组件决定

//app组件
<Left> 
<template v-solt:header='params'>
        <p>{{ scope.params }}</p>    //hello
 </template>
</Left>

//left组件
<div>
      <slotname:'header' msg="hello"></slot>
</div>

ESLint

//在方法形参()之前,不需要空格

“space-before-function-paren”:[“error”,“never”]

配置代理

image-20240206015651493

  • 在vue.config.js中进行配置

    module.exports = {
      devServer: {
        proxy: {
          '/api': {  //匹配所有以api开头的路径
            target: '<url>',  //代理目标的基本路径
            pathRewrite: { '^/api': '' }, //修改传回服务器的路径
            ws: true,
            changeOrigin: true
          },
          '/foo': {
            target: '<other_url>'
          }
        }
      }
    }
    

axios在vue中的封装

  1. 安装axios

    npm i axios -S

  2. 引入axios

    import axios from ‘axios’

    axios.defaults.baseURL = ‘http://www.baidu.com’ //全局配置默认请求根路径

    Vue.prototype.$http = axios

  • axios的返回值是promise实例对象,用await和async进行修饰和简化

Vuex

vuex中一般存储组件之间共享的数据,适用于多组件共享某些数据,将这些共享的数据集中起来管理

vuex中数据都是响应式的,能够保持数据与页面的同步,数据改变重新解析模板

是实现集中式状态管理的一个Vue插件,适用于任意组件间通信

image-20240206015703114

  1. 搭建vuex环境

    安装vuex

    npm i vuex安装的是vuex4版本,该版本只能用在vue3,vue2只能用vuex3版本 npm i vuex@3

    (1)创建store文件:src/store/index.js (先要有vuex,再创建store实例)

    store实例对象是由Vuex.store({})构造出来的,构造之后,在vc,vm上就会出现$store属性

    $store属性中 有dispatch,commit方法

    //引入vue
    import Vue from 'vue'
    //引入vuex
    import Vuex from 'vuex'
    Vue.use(Vuex)
    //用于响应组件中的动作
    const actions = {}
    //用于储存数据
    const state = {}
    //用于操作数据
    const mutations = {}
    //创建并导出store
    export default new Vuex.Store({
      actions, mutations, state
    })
    

    (2)在main.js中引入store

    //引入store
    import store from './store'
    //创建vm
    new Vue({
      render: h => h(App),
      store,
      beforeCreate() {
        Vue.prototype.$bus = this
      }
    }).$mount('#app')
    
  2. 基本使用

    1.在组件中使用dispatch给actions

     this.$store.dispatch("jia", this.n);
    

    2.在store中配置actions,actions主要写业务逻辑,将数据commit给mutations进行操作

    如果没有网络请求或业务逻辑,可以直接越过actions,直接编写commit

    const actions = {
      //context上下文,有commit,dispatch,state属性
      jia(context, value) {
        context.commit('JIA', value)
      },
      jian(context, value) {
        if(context.state.sum % 2){
            context.commmit('JIA',value)
        }
      }
    }
    

    3.mutations主要进行数据加工

    mutations会收到两个参数,第一个是state,第二个就是传递过来的数据

    const mutations = {
      JIA(state, value) {
        state.sum += value;
      },
      JIAN(state, value) {
        state.sum -= value;
      }
    }
    

    4.state 就是将一些共享的数据存放进来,类似与组件中的data

    在组件模板中想使用state中数据 $store.state.sum

    //用于储存数据
    const state = {
      sum: 0
    }
    

    5.getters 就是将state中的数据进行运算加工,类似与组件中的computed

    在组件中读取 $store.getters.bigData

    const getters = {
      bigData(state){
         return state.sum*10  //必须要用return语句,收到的参数就是state
      }
    }
    

    6.mapState帮助程序猿简化代码,优化computed计算属性

    首先要在组件中引入mapState import {mapState} from 'vuex'

    computed: {
        //借助mapState生成计算属性,从state中读取sum,并且形成sum函数
        ...mapState(["sum"]),//==>sum(){
                                    //return this.$store.state.sum
    		                        	}
      },
    

    7.mapActions,模板中调用的函数要传参increment(n)

    帮我们生成与actions对话的方法,即this.$store.dispatch("jia", this.n);

      methods: {
        // increment() {
        //   this.$store.dispatch("jia", this.n);
        // },
        ...mapActions({ increment: "jia" }),
      },
    

    mapActions使用时若需要传参,则要在模板绑定事件时传递参数,否则参数是事件对象

     <button @click="increment(n)">+</button>
    
    1. mapMutations,模板中调用的函数要传参increment(n)
      methods: {
        // increment() {
        //   this.$store.commit("jia", this.n);
        // },
        ...mapMutations({ increment: "jia" }),
      },
    
  3. vuex模块化

让代码更好维护,让数据分类更加明确

​ (1)修改store.js

// count相关配置
const countOptions = {
  namespaced:true,  //开启命名空间,mapState,mapActions等才能识别是哪个配置中的state,actions等
  actions:{
    addOdd(context,value){
      if(context.state.sum % 2){
        context.commit('ADDODD',value);
      }
    }
  },
  mutations:{
    ADD(state,value){
      state.sum += value;
    },
    DECREASE(state,value){
      state.sum -= value;
    },
    ADDODD(state,value){
      state.sum += value;
    }
  },
  state:{
    sum:0,
  },
  getters:{
  }
}

//person相关配置
const personOptions = {
  namespaced:true,
  actions:{
  },
  mutations:{
    ADDPERSON(state,value){
      console.log(value);
      state.personList.unshift(value)
    }
  },
  state:{
    personList:[{id:'000',name:'李四'}]
  },
  getters:{
    length(state){
      return state.personList.length
    }
  }
}
//导出时要加modules:{}
export default new Vuex.Store({
  modules:{
    countAbout:countOptions,
    personAbout:personOptions
  }
})

​ (2)组件读取数据

  • 读state中数据
//直接读取
this.$store.state.count.sum
//借助mapState
...mapState('countAbout',['sum'])
  • 组件中调用commit,dispatch,getters的方式都类似
//直接读取
this.$store.commit('countAbout/ADD',person)
//借助mapState
...mapMutations('countAbout',{add:'ADD'})

路由

一个路由就是一个对应关系,key为路径,value为组件

用来实现单页面应用,每条路径对应一个页面

基本使用

​ 1.安装vue-router npm i vue-router@3.5.2 -S (vue2版本只能使用 vue-router3)

//在src目录下创建一个router文件夹,里面创建index.js文件
1.导入Vue和VueRouter的包
import Vue from 'vue'
import VueRouter from 'vue-router'
// vue使用vueRouter插件
Vue.use(VueRouter)
// 创建路由实例对象
const router = new VueRouter({
    //routes中定义hash地址和组件之间的对应关系
    routes:[
    	{path:'/home',component:要展示的组件}
    ]
})
export default router

​ 2.要在main.js中挂载router实例

import router from './router/index.js'
new Vue({
  render: h => h(App),
  router //
}).$mount('#app')

注意点

  • 切换路径时,原来的组件会被销毁,切换到原路径时会重新挂载
  • 路由组件通常写在pages文件夹中,普通组件写在components文件夹中
  • 每个组件有 r o u t e 和 route和 routerouter,在 r o u t e 中有自己的路由信息,整个应用只有一个 route中有自己的路由信息,整个应用只有一个 route中有自己的路由信息,整个应用只有一个router,所有组件的$router相同

router-view组件占位符

指定组件的呈现的位置

将该路由下路径对应的组件放入

##router-link

用来替换a链接

<router-link to='/home'>首页</router-link>

浏览器历史记录有两种写入方式 push和replace

router-link默认是push方式,每一条记录都会记录,从栈底开始,先进后出

replace是代替当前记录,浏览器只保存一条记录

首页


##redirect重定向

重新跳转到指定位置

routes:[
    	{path:'/',redirect:'/home'},
        {path:'/home',component:Home}
    ]

嵌套路由

1.在router中配置 children:[{}]

注意:在path中不需要 /

  {
      path: '/home', component: Home,
      children: [
        { path: 'news', component: News },
        { path: 'message', component: Message },
      ]
    },

2.在组件跳转时要添加前缀

<router-link to="/home/message">Message</router-link>

路由的query传参

1.组件跳转,对象写法,要传递的参数写在query里

 <router-link
        :to="{
          path: '/home/message/detail',
          query: {
            id: '',
            title: ''
          },
        }"
      >
</router-link>

2.接受参数

$route.query.id

$route.query.title


路由的params传参

传参前先占位

params传参时,to写成对象写法时,传参不能用path,只能用name

参数不能是数组

params传参时,若想让参数传不传都行,在占位时在参数后加?

image-20240206015723411

image-20240206015734250

<router-link :to="`/home/message/${m.id}/${m.title}`">Message</router-link>

3.接受参数

$route.params.id

$route.params.title

路由的props配置

方便路由组件接受参数

1.在router中配置props,return一个对象

 {
          path: 'message', component: Message,
          children: [{
            path: 'detail', component: Detail,
            props($route) {
              return { id: $route.query.id, title: $route.query.title }
            }
          }]
        },

2.在组件接受数据,之后便可以在组件模板中使用

export default {
  name: "Detail",
  props: ["id", "title"],
};

声明式导航&编程式导航

  1. 声明式导航

​ 普通网页中点击a链接,在vue中点击都属于声明式导航

  1. 编程式导航

​ 调用Api实现页面hash地址的变化,to可以怎么写,push()括号内就可以怎么写

  • this.$router.push('hash地址') 跳转到指定位置,并增加一条历史记录,可以前进和回退。
  • this.$router.replace('hash地址') 跳转到指定位置,并且代替原来页面,不能回退。
  • this.$router.back() 后退一步
  • this.$router.forward() 前进一步
this.$router.push({
        path:'/home',
        query:{
          id:'002',
          name:'tom'
     	 }
})

缓存路由组件

为了将不展示的组件数据不丢失(路由一切换,默认组件自动销毁)

include=“组件名” 代表要缓存的组件是xxx

:include=[“组件名”,“组件名”] 缓存多个组件

 <keep-alive include="Home">
        <router-view></router-view>
 </keep-alive>

路由中独有的声明周期

  1. activated(){} 组件被激活时调用

  2. deactivated(){} 组件失活时调用

路由守卫

就是为了控制路由的访问权限,满足一些条件才能进入页面

  1. 全局前置守卫 router.beforeEach((to,from,next)=>{})

    • to 是将要访问的路由的信息 to.path 是hash地址
    • from 是将要离开的路由的信息
    • next( ) 是放行 next(‘/login’) 跳转到登录页面

    在进行权限校验的路由里配置 meta:{isAuth:true}

    router.beforeEach((to, from, next) => {
      if (to.meta.isAuth) {
        if (localStorage.getItem('school') === 'guigu') {
          next()
        }
        else {
          alert('sorry')
        }
      } else {
        next()
      }
    })
    

    全局后置守卫,在组件跳转后执行

    router.afterEach((to) => {
      document.title = to.meta.title || "vue"
    })
    
  2. 独享守卫,配置在path中

    是某个路由独享的,配置在该路由下

      { path:'news',
        component:News,
        beforeEnter:(to,from,next)=>{
          if (to.meta.isAuth) {
            if (localStorage.getItem('school') === 'guigu') {
              next()
              }
              else {
                alert('sorry')
              }
            } else {
              next()
            }
           }
        }
    
  3. 组件内路由守卫

路由进入该组件时进行一些判断

  1. 进入守卫 beforeRouteEnter(to,from,next){}
  2. 离开守卫 beforeRouteLeave (to, from, next) {}

路由器的两种工作模式

路由器默认是hash模式(#),可以在路由器中添加mode:'history',转变为history模式

UI组件库

1.Element UI https://element.eleme.cn



  • 34
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
根据引用中的信息,张天禹老师Vue2笔记主要包括以下内容: 1. 脚手架文件结构: 包括了src文件夹、public文件夹、babel.config.js、package.json等文件,这些文件组成了Vue项目的基本结构。 2. Vue.js与vue.runtime.xxx.js的区别: Vue.js是完整版的Vue,包含了核心功能和模板解析器,而vue.runtime.xxx.js是运行版的Vue,只包含核心功能,没有模板解析器。因此,在使用vue.runtime.xxx.js时,无法直接使用template配置项,需要使用render函数来指定具体内容。 3. vue.config.js配置文件: 使用vue.config.js可以对Vue脚手架进行个性化定制,可以通过该文件来修改默认配置。 4. ref属性: 在Vue中,ref属性用来给元素或子组件注册引用信息(相当于id)。在html标签上使用ref获取的是真实DOM元素,在组件标签上使用ref获取的是组件实例对象。使用方式是通过打标识和this.$refs.xxx来获取。 5. props配置项: 在Vue中,props配置项用来设置父组件向子组件传递数据的属性。子组件可以通过props获取到来自父组件的数据。 以上就是张天禹老师Vue2笔记的一些主要内容。123 #### 引用[.reference_title] - *1* [尚硅谷Vue2-3(张天禹老师) 学习笔记](https://blog.csdn.net/weixin_55092718/article/details/126071878)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}} ] [.reference_item] - *2* [尚硅谷 张天禹老师vue2笔记(方便自己查阅)](https://blog.csdn.net/xianyu120/article/details/120850859)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}} ] [.reference_item] - *3* [Vue2学习笔记(尚硅谷张天禹老师)day-01](https://blog.csdn.net/qq_53916344/article/details/123890478)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}} ] [.reference_item] [ .reference_list ]

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

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值