Vue学习笔记

初始Vue

  • 想让Vue工作,就必须创建一个Vue实例,且要传入一个配置对象
  • root容器里的代码依然符合html规范,只不过混入了一些特殊的Vue语法
  • root容器里的代码被称为vue模板
  • Vue实例和容器是一一对应的
  • 真实开发中只有一个Vue实例,并且会配合组件一起使用
  • {{xxx}}中的xxx要写js表达式,并且xxx可以自动读取到data中的所有属性,一旦data中的数据发生改变,那么模板中用到该数据的地方也会自动更新
  • js表达式和js语句的区别:表达式:一个表达式会产生一个值,并且可以放在任何一个需要值的地方,如:a,q+b,function(1),x===y?a:b;js语句:if(),for()
<body>
  <div id="root">
    <h1>hello,{{name}}</h1>
  </div>
  <script>
    Vue.config.productionTip = false //防止vue在启动时生成生产提示
    //创建Vue实例
    const x  = new Vue({
      el:'#root',  //el用于指定当前Vue实例为哪个容器服务,值通常为css选择器字符串
      data:{   //data中用于存储数据,数据供el所指定的容器去使用
        name:"呵呵世界"
      }
    })
  </script>
</body>

模板语法

  • 插值语法:

    功能:用于解析标签体内容

    写法:{{xxx}},xxx是js表达式,并且可以直接读取到data中的所有属性
  • 指令语法:

    功能:用于解析标签(包括:标签属性,标签体内容,绑定事件...)
    举例:v-bind:href="xxx" 或 简写成 :href="xxx",xxx同样要写成js表达式,并且可以直接读取data值的所有值

数据绑定

vue中有两种数据绑定的方式

  • 单向绑定(v-bind):数据只能从data流向页面
  • 双向数据流(v-model):数据不仅能从data流向页面,还能从页面流向data

1.双向绑定一般懂用于表单类元素上(如:input,select等),2.v-model:value 可以简写成v-model,因为v-model默认的是value的值

el与data的两种写法

  • el的两种写法:a:new Vue()的时候配置el属性,b:先创建Vue实例,随后通过vm.$mount("#root")指定el的值
  • data的两种写法:a:对象式,b:函数式.如何选择:在组件中写的时候必须用函数式,否则会报错.

一个重要的原则:由Vue管理的函数,一定不要写成箭头函数,一旦写成箭头函数,this的指向就不再是Vue实例了

Object.defineProperty

<script>
   let number = 18
   let person = {
     name:'张三',
     sex:'男',
   }
   Object.defineProperties(person,'age',{
    //  value:15,
    //  enumerable:true, //控制属性是否可以枚举,默认false
    //  writeable:true, //控制属性是否可以被修改.默认fasle
    //  configurable:true,//控制属性是否可以被删除.默认false

     get(){ //当有人读取person的age属性值时,get函数(getter)就会被调用,且返回值就是age的值
      console.log("有人读取age属性了")
        return number
     },
     set(value){  //当有人修改age属性时,set函数(setter)就会被调用,切会收到修改的具体值
       console.log("有人修改了age的值,且值是",value)
       number = value
     }
   })
  </script>

数据代理

  • 通过一个对象代理对另一个对象中属性的操作(读/写)
let obj = {x:100}
  let obj2 = {y:200}

  Object.defineProperties(obj2,'x',{
    get(){
      return obj.x
    },
    set(value){
      obj.x = value
    }
  })
  console.log(obj2.x) //输出结果为100
  obj2.x = 300,
  console.log(obj.x) //输出值为300 直接打印obj也可以看出
  
  //上述代码通过数据代理,通过obj2就可以操作obj中x的值

Vue中的数据代理

  • 1.Vue中的数据代理:通过vm对象来代理data对象中属性的操作(读/写)
  • 2.Vue中数据代理的好处:更加方便的操作data中的数据
  • 3.基本原理:通过Object.defineProperties()把data中的所有属性添加到vm身上.为每一个添加vm身上的属性都指定一个对应的setter和getter.在getter和setter内部去操作(读/写)data中对应的属性

常见指令

  • 事件处理v-on:xxx

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

 <!-- <button v-on:click="showinfo"></button>
<button v-on:click="showinfo1($event,66)"></button> -->
<button @click="showinfo"></button>  
<button @click="showinfo1($event,66)"></button>
<!-- v-on:click可简写成@click -->

vue中的事件修饰符
  • prevent 阻止默认事件(常用)
  • stop 阻止冒泡事件(常用)
  • once 事件只触发一次(常用)
  • capture 使用事件的捕获模式
  • self 只有event.target是当前操作的元素时才触发事件
  • passive 事件的默认行为立即执行,无需等待事件回调执行完毕
键盘事件
  • enter 会车键
  • delete 删除
  • esc 退出
  • tab 换行(特殊,必须配合keydown使用)

计算属性与监视

<body>
  <div id="root">
     <p>{{fullName}}</p>
  </div>
  <script>
   const vm = new Vue({
     dta:{
       firstName:"张",
       lastName:"三"
     },
     //计算属性
     computed:{
       //完整写法
      //  fullName:{
      //    get(){
      //      return this.firstName + '-' + this.lastName
      //    },
      //    set(value){
      //      const arr = value.split('-')
      //      this.firstName = arr[0]
      //      this.lastName = arr[1]
      //    }
      //  },
       //如果没有set至于get的话以简写
     fullName(){
      return this.firstName + '-' + this.lastName
     }
     }
   })
  </script>
</body>
深度监视
  • vue中的watch默认不监测对象内部值的改变(一层)
  • 配置deep:true可以检测对象内部的改变(多层)
<body>
  <div id="root">
     <h2>今天天气很{{info}}</h2>
     <button @click="ishot = !ishot"></button>
  </div>
  <script>
   const vm = new Vue({
     dta:{
      ishot: false,
      numbers:{
        a:1,
        b:2
      }
     },
     //监视,不仅可以监视普通的属性,也可以监听计算属性
     watch:{
       //  ishot:{
      //   //  immediate:true, //初始化时让handler调用一次,默认为fasle
      //    handler(newVlaue,oldValue){
      //     console.log("ishot被修改了",newValue,oldValue)
      //    }
      //  },
       //监视属性简写(ishot的监听)
       ishot(newVlaue,oldValue){
        console.log("ishot被修改了",newValue,oldValue)
       },
       //监视numbers中a的变化
       'numbers.a':{
        handler(newVlaue,oldValue){
          console.log("numbers.a被修改了",newValue,oldValue)
         }
       },
       //只有有对象中有属性变化就监听(深度监听)
       numbers:{
        handler(newVlaue,oldValue){
          deep:true, //开启深度监听. 默认是false
          console.log("numbers被修改了",newValue,oldValue)
         }
       }
     }
   })

  //  //还可写到vm外面
  //  vm.$watch('ishot',{
  //   handler(newVlaue,oldValue){
  //         console.log("ishot被修改了",newValue,oldValue)
  //        }
  //  })
  </script>
</body>

computed和watch的区别

1.computed能完成的功能,watch都可以完成,2.watch能完成的功能,computed不一定能完成,例如:watch可以进行异步操作

两个重要小原则

1.所被vue管理的函数,最好写成普通函数,这样this的指向才是vm或组件实例对象

2.所有不被vue所管理的函数(定时器的回调函数,ajax的回调函数,promise的回调函数)
,最好写成箭头函数,这样this的指向才是vm或组件实例对象

绑定样式

  • class样式
    :class="xxx", xxx可以是字符串,对象,数组.字符串写法用于:类型不确定,需要动态获取.对象写法适用于:要绑定多个样式,个数不确定,名字也不确定.数组写法适用于:要绑定多个样式,个数确定,名字也确定,但不确定用不用
  • style样式
    :style = "{fontSize:xxx}" 其中xxx是动态值.:style='[a,b]' 其中a,b是样式对象
<body>
  <div id="root">
    <!-- 绑定class样式--字符串写法,适用于:样式的类名不确定,需要动态指定-->
     <div class="basic" :class="mood" @click="changeMood">{{name}}</div><br/><br/>
    <!-- 绑定class样式--数组写法,适用于绑定样式的个数不确定,名字也不确定 -->
     <div class="basic" :class="classArr">{{anme}}</div><br/><br/>
    <!-- 绑定class样式--对象写法,适用于绑定样式的个数确定,名字也确定,但要动态决定用不用 -->
     <div class="basic" :class="classObj">{{anme}}</div><br/><br/>
     <!-- 对象形式或者这样写 -->
     <div class="basic" :class="{'style1':false,'style2':true}">{{anme}}</div><br/><br/>
     
    <!-- 内联样式style绑定--对象写法,key中不能有-连字符,省去连字符,后面字母大写 -->
     <div class="basic" :style="{fontSize : a+'px'}">{{anme}}</div><br/><br/>
     <!-- 或者这样写 -->
     <div class="basic" :style="styleObj">{{anme}}</div><br/><br/>
     <!-- 内联样式style绑定--数组写法,数组中包括的是多个对象 -->
     <div class="basic" :style="[styleObj,styleObj2]">{{anme}}</div><br/><br/>
  </div>
  <script>
    // ps:normal,style1,style2,style3为类名,有具体的样式
   const vm = new Vue({
     dta:{
      name:"小镇做题家",
      mood:"normal",
      classArr:['style1','style2','style3'],
      classObj:{
        style1:false,
        style2:true
      },
      a:40,
      styleObj:{
        fontSize:'35px'
      },
      styleObj2:{
        backgroundColor:'red'
      }
     },
     methods: {
      changeMood(){
        this.mood = "style1"
      }
     },
    })
  </script>
</body>

条件渲染 v-show v-if

v-show是在样式上隐藏disply:none,v-if直接不创建这个组件.在开发中如果切换频率高的显示和隐藏用v-show

列表渲染 v-for

可以遍历数组,字典,字符串,指定次数

<body>
  <div id="root">
   <h2>人员列表</h2>
   <ul>
      <!----遍历数组>
     <li v-for='p in persons' :key="p.id">
     <!--可以接收两个参数,第一个参数是item,第二个参数是index-->
      <!--<li v-for='(p,index) in persons' :key="index">-->
       {{p.name}}---{{p.age}}
     </li>
   </ul>
  </div>
  <script>
   const vm = new Vue({
     dta:{
        persons:[
          {id:"001",name:"小李",age:18},
          {id:"002",name:"小红",age:19},
          {id:"003",name:"小张",age:20},
        ],
        car:{
            name:'奔驰',
            price:'30万',
            color:"红色"
            }
        }
     }
    })
  </script>
</body>
Vue中key的作用

key是虚拟Dom对象的标识,当数据发生变化时,Vue会根据新数据生成新的虚拟Dom,随后Vue进行新虚拟Dom与旧虚拟Dom的差异比较,比较规则如下:

  • 旧虚拟Dom中找到了与新虚拟Dom相同的key:1.若虚拟Dom中内容没有变化,直接使用之前的真实Dom.2.若虚拟Dom中内容变化了,则生成新的真实Dom,随后替换掉页面中之前变化的真实Dom
  • 旧虚拟Dom中未找到与新虚拟Dom相同的key:创建新的真实Dom,随后渲染到页面

Vue监视数据的原理

1.vue会检测data中的所有层次的数据

2.如何检测对象中的数据

通过setter实现监视,且要在new Vue的时就传入检测的数据

  • 对象中后裔追加的属性,Vue默认不做响应式处理
  • 如需给后添加的属性做响应式,请使用如下API:
Vue.set(target,propertyName/index,value)或者Vue.$set(target,propertyName/index,value)

3.如何检测数组中的数据?

通过包装数组更新元素方法的实现,本质上就是做了两件事

  • 1.调用原生对应的方法对数组进行更新
  • 2.重新解析模板,进而更新页面
    4.在Vue中修改数组中的某个元素一定要用如下方法(不要用下标赋值的方法去做):

    1.使用这些API:push(),pop(),shift(),splice(),sort(),reverse()

    2.Vue.set() 或 Vue.$set()

特别注意:Vue.set()和Vue.$set()不能给vm或者vm的根元素(data)添加属性

input表单有关

  • 若:<input type="text"/>,则v-model收集的是vlaue值,用户输入的就是value
  • 若:<input type="radio"/>,则v-model收集的是value值,且要给标签配置value值
  • 若:<input type="checkbox"/>
    1.没有配置input的value值,那么收集的就是checked(勾选 或 未勾选,是布尔值)

    2.配置input的value值:

    (1)v-model的初始值是非数组,那么收集的就是checked(勾选 或 未勾选,是布尔值)

    (2)v-model的初始值是数组,那么收集的就是value值组成的数组

v-model的三个修饰符:lazy:失去焦点再收集数据.number:输入字符串转为有效的数组.trim:输入收尾空格过滤

过滤器

定义:对现实的数据进行特定格式化后再显示(适用于一些简单的逻辑处理)

语法:

1.注册过滤器:Vue.filter(name,callback) 或 new Vue{ filter:{} }

2.使用过滤器:{{xxx | 过滤器名}} 或v-bind:"xxx | 过滤器名"

备注: 1.过滤器也可以接收额外的参数,多个过滤器也可以串联.2.并没有改变原本的数据,是产生新的对应的数据.(过滤器的值是挨个传递的,第一个过滤器返回的值作为第二个返回值的参数使用值)

<body>
  <div id="root">
   <h2>过滤器,显示格式化之后的时间</h2>
  <h3>现在的时间是:{{time}}</h3>
  <h3>现在的时间是):{{time | timeForamter}}</h3>
  <h3>现在的时间是:{{time | timeForamter('YYYY_MM_DD') | mySlice}}</h3>
  <h3 :msg="msg | amySlice"></h3>
  </div>
  <script>
   const vm = new Vue({
     dta:{
       time:16358527825,
       msg:"你好,世界啊"
     },
    //  局部过滤器
     filters:{
       timeForamter(value,str='YYYY年MM月DD日 HH:mm:ss'){
        //  time作为参数value的值
          return dayjs(value).format(str)
       },
       mySlice(){ 
          return value.slice(0,4)
       }
     }
    })

    //全局过滤器
    Vue.filters('amySlice',function(value){
      return value.slice(0,4)
    })
  </script>
</body>

内置指令

  • v-text:向其所在的节点中渲染文本内容,与插值语法的区别:v-text会替换掉节点中的内容,{{xxx}}则不会
  • v-html:像指定节点渲染包含html结构的内容.ps:v-html有安全性问题,容易导致xss攻击(获取到网站上的cookie)
  • v-cloak:可以通过设置属性形式[v-cloak]的display:none在数据未加载之前隐藏节点,避免出现插值语法
  • v-once:只渲染一次
  • v-pre:预编译指令,跳过其所在的节点编译过程(不会解析节点所在的插值语法,指令语法)

自定义指令

<body>
  <!-- 
     需求一:定义一个v-big指令,和v-text功能类似,但回把绑定的数值放大10倍
     需求二:定义一个v-fbind指令,和v-bind功能类似,但可以让其绑定的input元素默认获取焦点
     自定义指令总结:
       一.定义语法:
       1.局部指令: new Vue({
         directives:{
           指令名:配置对象
         }
       })
       或者 new Vue({
         directives(){

         }
       })
       2.全局指令:
       Vue.directive(指令名,配置对象) 或者 Vue.directive(指令名,回调函数)
       二.配置中常用的三个回调:
       1.bind:指令与元素绑定时调用
       2.inserted:指令所在的元素被插入页面时
       3.update:指令所在的模板结构被重新解析时调用
       三.备注:
       1.指令定义时不用加v-,但使用时需要加v-.
       2.指令如果是多个单词,要使用kebab-case命名方式,不要用camelCase命名
   -->
  <div id="root">
  <h2>{{name}}</h2>
  <h2>当前的值是:<span v-text="n"></span></h2>
  <h2>增加10倍的值是:<span v-big="n"></span></h2>
  <button @click="n++"></button>
  <input type="text" v-fbind:value='n' />
  </div>
  <script>
   const vm = new Vue({
     dta:{
       name:"世界你好",
       n:1
     },
    // 注意:自定义指令里面的this都是window,不是vm
    directives:{
      // big函数何时会被调用?1.指令与元素成功绑定时(一上来).2.指令所在的模板被重新解析时
      big(element,binding){
        // element指令所在的真实dom,binding是个对象,其中value是绑定的值
         console.log('big')
         element.innerText = binding.value * 10
      },
      fbind:{
        // 钩子函数
        // 指令与元素绑定成功时调用
        bind(element,binding){
         element.value = binding.value
        },
        // 指令所在元素被插入页面时(获取焦点看,拿到父元素)
        inserted(element,binding){
          element.focus()
        },
        // 指令所在的模板被重新解析时
        update(element,binding){
          element.value = binding.value
          element.focus()
        }
      }
    }
    })
    // --------------------------------------------------------------------------
    // 全局的自定义指令写法
    Vue.directive("fbind",{
       // 指令与元素绑定成功时调用
       bind(element,binding){
         element.value = binding.value
        },
        // 指令所在元素被插入页面时(获取焦点看,拿到父元素)
        inserted(element,binding){
          element.focus()
        },
        // 指令所在的模板被重新解析时
        update(element,binding){
          element.value = binding.value
          element.focus()
        }
    })
    Vue.directive('big',function(element,binding){
      console.log('big')
      element.innerText = binding.value * 10
    })
  </script>
</body>

生命周期

常用的生命周期钩子:

1.mounted:发送ajax请求,启动定时器,绑定自定义事件,订阅消息[等初始化操作]

2.beforeDestroy:清除定时器,解绑自定义事件,取消订阅消息等[收尾工作]

关于销毁Vue实例:

1.销毁后借助Vue开发者工具看不到任何消息

2.销毁后自定义事件会失效,但原生的Dom事件依然有效

3.一般不会在beforeFestory操作数据,因为即便操作数据,也不会再触发更新流程

//无法通过vm访问data中的数据,methods中的方法
     beforeCreate() {
       
     },
    //可以通过vm访问到data中的数据,methods中配置的方法
     created() {
       
     },
    // 此时1.页面呈现的是未经Vue编译的Dom结构.2.所有对Dom的操作,最终都不奏效
     beforeMount() {
       
     },
     //Vue完成模板的解析,并把初始的真实DOM元素放入页面后(挂载完毕)调用mounted.此时1.页面中呈现的是经过Vue编译的Dom.2.对Dom的操作均有效(尽可能避免).
     //至此初始化过程结束,一般在此进行:开启定时器,发送网络请求,订阅消息,绑定自定义事件等初始化操作
    mounted() {
      
    },
    //此时:数据是新的,但页面是旧的,即:页面尚未和数据保持同步
    beforeUpdate() {
      
    },
    // 此时:数据是新的,页面也是新的.即:页面和数据保持同步
    updated() {
      
    },
    // 此时:vm中所有的:data,methods,指令等等.都处于可用状态,马上要执行销毁过程.一般在此阶段:关闭定时器,取消订阅消息,解绑自定义事案件等收尾操作
    beforeDestroy() {
      
    },
    // 销毁完毕
    destroyed() {
      
    },

组件

实现应用中局部功能代码和资源的集合.分为非单文件组件和单文件组件.非单文件一般是在html中包含很多组件.单文件组件一般是值一个.vue文件就是一个组件

使用(非单文件组价)组件的步骤:

  • 1.创建组件
 //Vue.extend()可以省略
 const school =  Vue.extend({
      // 注意Vue2只允许也有个根标签
      template:`
      <div>
       <h3>{{schoolname}}</h3>
       <h3>{{schooladdress}}</h3>
      </div>
      `,
      // 组件中的data必须用函数式,不然不能保证数据修改不互相影响
      data() {
        return {
          schoolname:'上海高级中学',
          schooladdress:'青浦区十二河西路45号'
        }
      },
    })
  • 2.注册组件
 const vm = new Vue({
     dta:{
       name:"世界你好",
       n:1
     },
    //  此处为局部注册
     components:{
      school:school
     }
 })
 
 //全局注册
vue.component('school',school)
    
  • 3.使用组件
 <div id="root">
   <school></school>
  </div>
  • 关于组件名的注意点:
    一个单词组成的:school,School.多个单词组成的my-school,MyScool(需要脚手架支持)
关于VueComponent
  • 1.school组件本质是一个名为VueComponent的构造函数,且不是程序员定义的,是Vue.extend生成的
  • 2.我们只需要写<school/>或<school></school>,Vue解析时会帮助我们创school的实例对象,即帮助我们执行:new VueComponent(optios)
  • 3.特别注意:每次调用Vue.extend({}),返回的都是一个全新的VueComponent
  • 4.关于this的指向
    (1).组件配置中:

    data函数.methods函数,watch中的函数,computed中的函数,他们的this均是(VueComponent实例对象)

    (2).new Vue()配置中:

    data函数.methods函数,watch中的函数,computed中的函数,他们的this均是(Vue实例对象)
  • 5.Vuecomponent的实例对象,以后简称VC(也可成为组件实例对象).vue的实例对象简称VM

Vue中重要的内置关系

  • 1.VueComponent.prototype.proto === Vue.prototype
  • 2.为什么有这个内置关系:让组件的实例对象(vc)可以访问到Vue原型上的属性和方法
//参考原型
//实例的隐式原型属性永远指向自己缔造者的原型对象
 //定义一个构造函数
    function Demo(){
      this.a = 1
      this.b = 2
    }
    //创建一个demo的实例对象
    const d = new Demo()
    console.log(Demo.prototype) //显式原型属性(只有函数才有的)
    console.log(d.__proto__) //隐式原型属性(对象中有的)

    //指向同一个原型对象
    console.log(Demo.prototype === d.__proto__) //输出true

    //程序员通过显式原型属性操作原型对象,追加一个x属性,值为99
    Demo.prototype.x = 99
    
    // 下面两种写法一样
    console.log(d.__proto__.x)
    console.log(d.x)

单文件组件(xxx.vue)

//快捷键<v
<template>
<!-- 组件结构 -->
  <div class="demo">
    <h2>学校名字:{{name}}</h2>
    <h2>学校地址:{{address}}</h2>
    <button @click="tipClick">点我</button>
  </div>
</template>

<script>
// 与组件交互相关的代码(数据,方法等)
// 注意:这里采用默认暴露的方式:export default,此处也省略了Vue.extend()
export default {
  name:'school', //组件的名字,在开发者工具中会显示这个名字
  data() {
    return {
      name:"第一初级中学",
      address:"上海市海防大学路"
    }
  },
  methods: {
    tipClick(){
      alert("哈哈哈")
    }
  },
}
</script>

<style>
/* 样式 */
.demo{
  background-color: aquamarine;
}
</style>

ref属性

  • 被用来给元素或子组件注册引用信息(通过id获取元素的替代者)
  • 应用在html标签上获取的是真实的DOM元素,应用在组件标签上是组件实例对象(vc)
  • 使用方式:

    打标识:<h1 ref="xxx">...</h1> 或者<HelloWorld ref="xxx"></HelloWorld>

    获取:this.$refs.xxx
<template>
  <div id="app">
    <h1 ref="title">略略略</h1>
    <HelloWorld ref="hell"/>
    <button @click="btnClick">点我</button>
  </div>
</template>

<script>
import HelloWorld from './components/HelloWorld.vue'

export default {
  name: 'App',
  components: {
    HelloWorld
  },
  methods:{
    btnClick(){
      console.log(this.$refs.title)   //输出真实Dom元素<h1>略略略</h1>
      console.log(this.$refs.hell)  //输出HelloWorld组件的VueComponent对象(vc)
    }
  }
}
</script>

props属性

让组件接收外部传过来的数据

  • 1.数据传递
<Demo name="xxx" />
  • 2.接收数据
    第一种方式(只接受):
props:['name']<br/>

第二种方式(限制类型):

props:{
    name:String
}

第三种方式(限制类型,限制必要性,指定默认值):

props:{
    name:{
        type:String, //类型
        require:true, //必要性
        default:'老王' //默认值
    }
}

props是只读的,Vue底层会监测你对props的修改,如果进行了修改,就会发出警告.若业务需求确实要修改,那么请复制props的内容到data中一份,然后去修改data中的数据

mixin 混入

// mixin.js把公共的抽离出来
export const hunhe = {
    data:{
        x:10,
        y:100
    },
    //methods中的方法如果和被混入对象中的方法一样时,以被混入对象的为准
    methods:{
        click(){
            console.log('点击了')
        }
    },
    //和被混入对象中的钩子函数都调用
    mounted(){
        console.log('这是钩子函数')
    }
}
//-------------------------
//组件vc
// 1.导入  2.使用
import { hunhe } from '../mixin.js'
{
    data:{
        name:小明
    },
    //以数组形式加入混合
    mixins:[ hunhe ]
    methods:{
        
    },
    mounted(){
        
    }
}

插件

功能:用于增强Vue

本质:傲寒install方法的一个对象,install的第一个参数是Vue,第二个以后的参数是插件使用者传递的数据.

定义插件:

//plugis.js
export default {
    inastall (Vue,options){
    //1.添加全局过滤器
    Vue.filter(...)
    //2.添加全局指令
    Vue.directive(...)
    //3.配置混入对象
    Vue.mixin(...)
    //添加实例方法
    Vue.prototype.$myMethod = function(){...}
    Vue.prototype.$myProperty = xxx
    
  }
}

使用插件:

导入 import plugin from '../plugins.js'
//用Vue.use(插件名)
Vue.use(plugin)

scoped样式

作用:让样式在局部生效,防止冲突.

写法:<style scoped>

浏览器的本地存储(localStorage,sessionStorage)

//存储
 localStorage.setItem(key,value) //key和value必须都是字符串

//读取
localStorage.getItem(key)

//删除
localStorage.removeItem(key)

//清空
localStorage.clear()

//ps:sessionStorage和localStorage的用法一样,只不过浏览器关闭sessionStorage会被清除,而localStorage不会被清除

组件的自定义事件

  • 一种组件间通信的方式,适用于:子组件 ===>父组件
  • 使用场景:A是父组件,B是子组件,B想给A传数据,那么就在A中给B绑定自定义事件(事件的回调在A中)
//通过父组件子组件传递函数类型的props事件(函数回调传值),子给父传递数据
<School :getSchoolName='schoolNameMthod' />

//通过父组件给子组件定义一个自定义事件实现:子给父传递数据(使用V-on或者@)
<Studen @myClcik="clickMthods" /> //子组件通过this.$emit('myClcik',"666","888"),后面参数也可以包装成一个对象

//通过父组件给子组件绑定一个自定义事件:子给父传递数据(使用ref)
<HelloWoreld ref='hell' /> // this.$refs.hell.$on('监听的事件名',function(){
    //注意:如果函数直接写在这里,以普通函数的写法去写,那这里的this是HelloWoreld的VueComponent(vc).解决办法:第一种箭头函数,第二种可以把这个函数拆分到methods中去
})

//解绑自定义事件
this.$off('clickMthods') //解绑一个
this.$off(['clickMthods','schoolNameMthod']) //解绑多个
this.$off() //解绑所有的自定义事件

组件绑定原生事件,如@click,系统会判定会这是一个自定义事件,想要原生事件生效,应该用native修饰.@click.native='xxx'

全局事件总线(GlobalEventbus)

  • 1.一种组件间通信的方式,适用于任意组件间通信
  • 2.安装全局事件总线:
new Vue({
    .....
    beforeCreate(){
        Vue.prototype.$bus = this //暗转全局事件总线,$bus就是当前应用的vm
    }
})
  • 3.使用事件总线
    1.接收数据:A组件想接受数据,则在A组件中给$bus绑定自定义事件,事件的回调留在A组件自身
 methods(){ 
     demo(prams){
     .....
 }
 ....
 mounted(){
     this.$bus.$on('xxx',this.demo)
 }
 }

2.提供数据:this.bus.emit('xxx',传递的数据)

  • 4.最好在beforeDestory钩子中,用$off去解绑当前组件所用到的事件

消息的订阅与发布

  • 1.一种组件间通信的方式,适用于任意组件

  • 2.使用步骤:
    1.安装pubsub:npm i pubsub-js

    2.引入:import pubsub from 'pubsub-js'

    3.接收数据:A组件想接受数据,则在A组件中订阅消息,订阅的回调留在A组件自身.

    methods(){
        demo(parmas){
        ....
    }
    ....
    mounted(){
        this.pid = pubsub.subscribe('xxx',this.demo)
    },
    deforeDestory(){
        Pubsub.unsubscribe(this.pid)
    }
    }
    

    4.提供数据:pubsub.publish('xxx',数据)

    5.最好在deforeDestory钩子中,用Pubsub.unsubscribe(pid)去取消订阅

    nextTick

    • 1.语法:this.$nextTick(回调函数)
    • 2.作用:在下一次DOM更新结束后执行其指定的回调
    • 3.什么时候调用:当改变数据后,要基于更新后的新DOM进行某些操作时(如输入框的失去焦点),要在nextTick所指定的回调函数中执行

    Vue封装的过渡和动画

    作用:咋插入和移除DOM元素时,在合适的时候给元素添加样式类名

    写法

    (-).准备好样式:
    元素的进入样式
    1.v-enter:进入的起点
    2.v-enter-active:进入过程中
    3.v-enter-to:进入的终点
    元素离开的样式:
    1.v-leave:离开的起点
    2.v-leave-active:离开过程中
    3.v-leave-to:离开的终点
    (二)使用<transition>包裹要过渡的元素,并配置name属性
    <transition name="hello">
      <h1 v-show='isShow'>你好啊</h1>
    

</transition>
(三)若有多个元素需要过渡,则需要使用:<transition-group>,且每个元素都要指定key值

> 项目中可以用第三方动画库,如:animate.css

#### 配置代理(解决跨域问题)
什么是跨域:当一个请求url的协议,域名.端口号三者之间任意一个与当前页面url不同即为跨域
- 方法1:在Vue.config.js中添加如下配置

devServer:{
proxy:'http://localhost:5000'
}
//说明:
1.优点:配置简单,请求资源时直接发给前端(8080)即可
2.缺点:不能配置多个代理,不能灵活的控制请求是否走代理
3.工作方式:若按照上述配置代理,当请求了前端不存在的资源时,那么该请求会转发给服务器

- 方法2:编写vue.config.js配置具体代理规则

module.exports= {
devServer:{
proxy:{
'/api1':{//匹配所有以'/aopi1'开头的请求
target:"http://localhost:5000",//代理目标的基础路径(不要写后面的路径了)
ws: true,// 是否启用websockets
changeOrigin: true,//是否开启代理
pathRewrite:{ 'api1':'' }//匹配以api开头的路径替换成空字符串
}
}
}
}


#### 插槽slot
1.作用:让父组件可以让子组件指定位置插入html结构,也是一种组件间通信的方式,适用于父组件===>子组件<br/>
2.分类:默认插槽,具名插槽,作用域插槽<br/>
3.使用方式:<br/>
 -.默认插槽:
 

父组件:
<Catergory>
<div>html结构1</div>
</Catergory>
子组件:
<template>
<div>

<slot>默认插槽内容</slot>
</div>
</template>


二.具名插槽

父组件:
<Catergory>
<template slot="center">
<div>html结构1</div>
</template>
<template slot="footer">
<div>html结构1</div>
</template>
</Catergory>
子组件:
<template>
<div>

<slot name="center">默认插槽内容</slot>
<slot name="footer">默认插槽内容</slot>
</div>
</template>

  
  三.作用域插槽

//理解:数据在组件自身,但根据数据生成的结构需要组件的使用者来决定.
父组件:
<Catergory>
<template slot-scope="data>

<ul>
<li v-for="g in scopeData.games" :key="g">{{ g }}</li>
</ul>
</template>
<template slot="footer">

<ul>
<h4 v-for="g in scopeData.games" :key="g">{{ g }}</h4>
</ul>
</template>
</Catergory>
子组件:
<template>
<div>
<slot :games="games"></slot>
</div>
</template>

<script>
export default {
name:"Category",
data(){
return{
games:['海贼王',"猫和老鼠","大话西游"]
}
}
}
</script>


#### vuex
专门在vue中实现集中式状态,数据管理的一个vue插件,对vue应用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间的通信方式,且适用于任意组件间的通信<br/>
1.//创建文件:src/store/index.js

//引入vue核心库
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//应用插件(需要在stroe实例创建前使用,不然会报错)
Vue.use(Vuex)

//准备actios对象----响应组件中用户的动作
const actions = {}
//准备mutatios对象---修改state中的数据
const mutatios = {}
//准备state对象---保存具体的数据
const state = {}
//准备getters---用于将state中的数据进行加工
const getters = {}

//并暴露store
export default new Vuex.store({
actions,
mutations,
state,
getters
})

2.在main.js中创建vm时传入store配置项

//引入store
import store from './store'
...
//创建vm
new Vue({
el:'#app'
render:h=>h(App)
store
})


#### 路由
1.理解:一个路由就是一组映射关系(key-vlaue),多个路由需要路由器(router)进行管理<br/>
2.前端路由:key是路径,vlaue是组件<br/>
##### 基本使用
1.安装vue-router,命令: npm i vue-router<br/>
2.应用插件:Vue.use(VueRouter)<br/>
3.编写router配置项

//引入VueRouter
import VueRouter from 'vue-router'
//引入组件
import About from '../components/about'
import Home from '../components/home'
//创建router实例对象,去管理一组一组的理由规则
const router = new vueRouter({
routes:[
{
path:"/about",
component:About
},
{
path:"/home",
component:Home
},
]
})
//暴露router
export default router

4.实现切换(active-class可配合样式进行高亮显示等)<br/>

<router-link active-class="active" to="/about"></router-link>

5.指定展示位置

<router-view></router-view>

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,753评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,668评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,090评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,010评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,054评论 6 395
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,806评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,484评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,380评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,873评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,021评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,158评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,838评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,499评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,044评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,159评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,449评论 3 374
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,136评论 2 356

推荐阅读更多精彩内容