Vue2

148 阅读7分钟

01-vue介绍与小胡子语法

  • 配置代码段,网址:snippet-generator.app/
  • 搜索:elementui,是一个组件库,可以选择别人封装好的组件用

01-vue初识

官网

  • 中文官网: cn.vuejs.org/ 默认是vue3

  • 文档读一下:cn.vuejs.org/v2/guide/in… vue2

  • Vue

    Vue (读音 /vjuː/,类似于 view),作者: 尤雨溪
    构建用户界面渐进式JavaScript框架
    是基于HTML,CSS,JS构建的,它提供了一套声明式的,组件化的编程模型。
    我们通常所说的Vue是指Vue全家桶(Vue核心+Vue生态)
    
  • Vue特点:

    1)声明式编程,组件化编程,提高开发效率
    2)不需要操作DOM,只需要操作数据,数据变了,界面会自动刷新
    3)Vue采用了虚拟DOM + 优秀Diff算法
    

Vue快速入门:

  1)先把Vue当成别人封装好的JS库,在项目中直接引用并使用它

快速体验

  • 官网: cn.vuejs.org/v2/guide/in…

  • 引入Vue的方式:

        1)在页面中通过CDN方式引入
        2)下载Vue源码,引入我们下载好的源码
        3)通过NPM工具,下载引入
        4)使用Vue脚手架去引入Vue
    
  • 体验vue

         <!-- 引入Vue.js,人家向外暴露一个Vue类  new Vue -->
         <script src="../lib/vue2.7.8.js"></script>
    </head>
    <body>
        <!-- 定义的容器 -->
        <!-- 容器也叫模板,也叫视图 -->
        <div id="app">
            <h2>你好, {{ name }} === {{ age }} === {{ sex }}</h2>
        </div>
        <script>
            let vm = new Vue({
                // el表示vm实例要与哪个容器进行关联,el对应的值是一个CSS选择器
                el:"#app",
                
                 // data是用来给模板或视图提供数据的
                 data(){
                     return {
                        // return中的对象中的写的数据,就是用来给模板提供的数据
                       // name,age,sex,叫响应式数据,写在data中的数据叫响应式数据
                       // 所谓的响应式数据,是指数据变了,模板会自动刷新
                       // 写在data中的所有的数据,都会挂载到vm对象上,成为vm的属性
                       name:"wc",
                       age:18,
                       sex:"man"
                     }
                 }
           });
           console.log(vm); // 看看是否vm上有name.age.sex
           
          // 总结:
            // 1)vm叫Vue实例   通过new Vue构造器new出来的     对象是属性的无序集合
            // 2)new Vue时,传递一个配置对象    el   data:给模板提供数据
            // 3)响应式数据:数据变了,视图要重新渲染(自动刷新)
            // 4)data中的数据,都要挂载到vm实例上,作为vm实例的属性
            // 5)在vue中,不需要操作DOM,操作的是响应式数据。数据变了,模板自动刷新
      </script>
    

02-vue语法注意事项

MVVM模型

  • MVVM是Model-View-ViewModel的简称,是目前非常流行的架构模式;
  • 通常情况下,我们也经常称Vue是一个MVVM的框架 image.png

小胡子语法注意事项一:

  • {{}} Mustache,插值语法,也叫小胡子语法
  • 一个vm实例只能指定一个模板,一个容器
  • 小胡子语法只能在容器内部使用,容器外是不能使用
  • 只能写在文本节点处,不能写在属性节点。错误示范: image.png

小胡子语法注意事项二:

  • 小胡子中可以放表达式(任何有值的内容都是表达式)
  • 小胡子中可以书写实例的属性
  • 小胡子中可以书写JS表达式
  • 不可以写语句 if.swich.for image.png

03-$mount的使用

配置代码片段

  • 网址:snippet-generator.app/

  • 具体的步骤如下

    第一步,复制自己需要生成代码片段的代码;
    第二步,https://snippet-generator.app/ 在该网站中生成代码片段;
    第三步,在VSCode中配置代码片段; 
    

image.png

  • 命名为:v2 image.png image.png

  • 输入v2就会出现配置好的代码: image.png

通过$mount关联容器

  • $mount需要传递一个容器的CSS选择器(字符串类型)

  • $mount是Vue构造器的原型对象上的方法,所以通过VM实例也可以调用

        let vm = new Vue({
          // el:"#app",   // 作用:让vm实例与容器进行关联
          data(){
              return {
                  name:"wc",
                  age:18,
                  sex:"man"
              }
          }
       });
      console.log(vm);
      
      vm.$mount("#app")
    

02-响应式原理与事件绑定

01-初识响应式原理

    // 问:下面的代码中有几个对象?
    // 答: 3个   vm叫实例对象   new一个{}配置对象    data中返回一个对象 
    let vm = new Vue({
        el:"#app",
        data(){
            return {
                msg:"hello vue"
            }
        }
    });
    console.log(vm);

    // 在vm实例上,还有一个叫_data属性,它里面也包含了data中的数据
    // 之所以以_打头,表示不希望别人使用   私有属性
    console.log(vm._data);

    // vm这个对象 与 data函数调用返回的对象 是两个不同的对象
  • vue2的响应式原理,靠之前的JS高级中的 Object.defineProperty

     // 精细化设置属性  就是给data对象添加msg属性
     Object.defineProperty(data,"msg",{
          // 当获取属性时,自动走get,得到的值是,return后面的值
          get(){
              return vm.msg;  // 获取也要在vm
          },
          // 当给msg属性设置一个属性时,会走set,设置的新值会作为set的参数
          set(val){
              vm.msg = val;   // 设置在vm上
              // 更新视图.....
          }
     })
     // 数据变了,我要更新视图,也就是说,数据变了,我肯定要知道
     // 当数据发生了变化,会走set,在set中可以更新视图...
     data.msg = "i love vue"
     console.log(data.msg);
    

02-事件绑定

  • 在vue中,通过指令来绑定事件。指令:说白了,就是标签的自定义属性 是以v-打头 image.png image.png

  • v-on基本上不用,一般都使用简写 @

  • 一个元素可以同时绑定多个事件,但是一般情况下只是绑定一个 image.png image.png

  • methods中的方法,不要写成箭头函数的形式

  • 如果是箭头函数,内部的this表示window

  • 监听器能不能挂载到vm实例上? 能

        let vm = new Vue({
          el:"#app",
          data(){
              return {
                  msg:"hello vue"
              }
          },
          // methods中放模板中绑定的监听器
          // methods 加了s  可以放很多很多方法
           methods:{
              // handle(){
              //     // console.log("handle...");
              //     // this表示vm实例   vm上有个msg  获取
              //     // console.log(this.msg);
              //     // msg是响应式数据,数据变了,界面要更新  设置
              //     this.msg = "hi vue"
              // }
              
              handle:function(){
                  console.log(this);
                  this.msg = "hi vue"
              },
    
              handle2(){
                  console.log("点击了按钮~");
              },
    
              over(){
                  console.log("鼠标移入了~");
              }
          }
      });
      // 写在methos中的方法,也会挂载到vm实例上的
      vm.handle2()
    

03-传参问题

  • 在绑定一个监听器时,()可以加也可以不加,加()的目的是为了传参

  •     <div id="app">   
          <button @click=" getMsg(123) ">传递一个参数</button>
          <!-- @click=后面是跟了一个""  千万不要当成字符串,它仅仅是vue中的语法 -->
      <!-- "" 仅仅是vue的语法,在""里放JS表达式 -->
      <button @click=" getMsg2(123,'i love you') ">传递两个参数</button>
      
      <!-- 没有加() 在监听器中,默认第一个参数,就是事件对象 -->
      <button @click=" getMsg3 ">获取事件对象方式一</button>
      
      <!-- 加()的目的是为了传参 -->
      <!-- 如果添加了(),监听器中的第1个参数,就不是事件对象了 -->
      <!-- 如果还想获取事件对象,那么需要手动的传递事件对象 $event -->
      <button @click=" getMsg4($event) ">获取事件对象方式二</button>
    </div>
    <script>
      let vm = new Vue({
          el: "#app",
          // data中放响应式数据
          data() {
              return {
          
              }
          },
          // methods中放方法(监听器)
          methods: {
              getMsg(a) {
                  console.log(a);
                  // console.log("getMsg...");
              },
              getMsg2(a, b) {
                  console.log(a, b);
              },
              getMsg3(e) {
                  console.log(e);
              },
              getMsg4(e){
                  console.log(e);
              }
          }
      });
    </script>
    

04-事件修饰符

  • .stop - 调用 event.stopPropagation()。

  • .prevent - 调用 event.preventDefault()。

  • .capture - 添加事件侦听器时使用 capture 模式。

  • .once - 只触发一次回调。

         引入Vue.js,人家向外暴露一个Vue类  new Vue -->
         <script src="../lib/vue2.7.8.js"></script>
         <style>
           .box{
            width: 200px;
            height: 200px;
            background-color: skyblue;
           }
       </style>
    </head>
    <body>  
       <!-- 定义的容器 -->
       <div id="app">
           <!-- form表单有默认的提交事件 -->
           <!-- a标签也有默认事件 -->
           <form action="http://www.baidu.com">
               <!-- 一点登录跳到百度 -->
               <!-- <input type="submit" value="登录"> -->
    
               <!-- 打印showMsg...  并且跳百度 -->
               <!-- <button @click="showMsg">点我</button> -->
    
               <!-- @click.prevent 阻止默认事件 -->
               <!-- 方法2 -->
               <button @click.prevent="showMsg">点我</button>
           </form>
           <hr>
           <!-- 先触发里边再触发外边 -->
           <div class="box" @click="showMsg2">
               <!-- 方法2 -->
               <button @click.stop="showMsg3">阻止冒泡</button>
           </div>
           <!-- 捕获    从外向内 -->
           <hr>
    
           <!-- once表示只处罚一次,用的不多 -->
           <button @click.once="showMsg4">只触发一次</button>
    
           <!-- 
              事件的修饰符可以链式来写,谁先谁后无所谓,了解:
               @click.stop.prevent.once
               @click.once.stop.prevent
            -->
    </div>
    <script>
      let vm = new Vue({
          el:"#app",
          data(){
              return {
             
              }
          },
          methods:{
              showMsg(e){
                  console.log("showMsg....");
                  // e拿到事件对象
                  // e.preventDefault(); // 阻止默认事件 法1
              },
              showMsg2(e){
                  console.log("showMsg2...");
              },
              showMsg3(e){
                  console.log("showMsg3...");
                  // e.stopPropagation();  // 阻止冒泡  法1
              },
              showMsg4(){
                  console.log("showMsg4...");
              }
          }
      });
    </script>
    

05-按键修饰符

  • 按键修饰符:

              .enter 回车键
              .left  左键
              .right  右键
              .up  上键
              .down  下键
              .esc
              .a
              .b
              .c
    
  • 代码如下:

    <div id="app">
        请输入你喜欢的人的名字,按回车打印出来:<input type="text" v-model="people" @keyup.enter="handle">
    </div>
    <script>
     let vm = new Vue({
         el:"#app",
         data(){
             return {
                 people:"wc"
             }
         },
         methods:{
             handle(e){
                 // console.log(e);
                 
                 // 未使用按键修饰符
                 // if(e.keyCode === 13){
                 //     console.log("你喜欢的人的名字是:", this.people);  // this表示people
                 // }
    
                 // 使用按键修饰符后,直接打印
                 console.log("你喜欢的人的名字是:", this.people);
             }
         }
     });
    </script>
    

03-指令

01 v-bind指令

  • v-bind作用是用于把数据绑定到属性节点处

      <div id="app">
             <img v-bind:src="url" alt="">
             <!-- v-bind可以简写成: -->
             <img :src="url" alt="">
             <!-- "haha是字符串" -->
             <p title="haha"></p>
    
            <!-- vm身上的动态属性 -->
            <p :title="haha">我是一个P标签</p>
    
            <!-- 不加:表示输入框中有个ok -->
            <input type="text" :value="ok">
    
            <!-- 冒号删了href的属性是name,加上:href的属性是wangcai -->
            <a :href="name">{{name}}</a>
     </div>
    
    <script>
      let vm = new Vue({
          el:"#app",
          data(){
              return {
                  url:"https://cn.vuejs.org/images/logo.svg",
                  haha:"lala",
                  ok:"ok666",
                  name:"wangcai"
              }
          }
      });
    </script>
    

02 v-once指令 (了解)

  • v-once表示只会第一次渲染数据到模板中,后面数据变了,模板也不会刷新了

      <script src="../lib/vue2.7.8.js"></script>
    </head>
    <body>  
      <!-- 定义的容器 -->
      <div id="app"  v-once>
          <!-- v-once表示只会第一次渲染数据到模板中,后面数据变了,模板也不会刷新了 -->
          <!-- <h2 v-once>计数器:{{number}}</h2> -->
          <h2>计数器:{{number}}</h2>
          <button @click="increment">加1</button>
      </div>
    
    <script>
       let vm = new Vue({
          el:"#app",
          data(){
              return {
                 number:0
              }
          },
          methods:{
              increment(){
                 this.number++
              }
          }
      });
    </script>
    

03 v-text (了解)

  • v-text用于更新元素的 textContent:

  • v-text不会解析标签

    <div id="app">
      <h2>{{msg}}</h2>
      <!-- "msg" 不是字符串,不是字符中,不是字符串,不是字符串 -->
      <!-- {{}}是v-text的语法糖,说白了,就是简写形式 -->
      <!-- 基本上不用,一般使用{{}} -->
      <h2 v-text="msg"></h2>
    
      <hr>
    
      <!-- v-text并不会解析标签 -->
      <div v-text="msg2"></div>
    </div>
    <script>
     let vm = new Vue({
       el:"#app",
       data(){
           return {
               msg:"hello vue",
               msg2:"<p style='color:red;'>我是一个P标签</p>"
           }
       }
    });
    </script>
    

04 v-html指令 (了解)

  • v-html能解析字符串 image.png

05 v-pre指令 (了解)

  • v-pre是一个指令,了解,作用:跳过模板编译
  • 之前是小胡子打印出来还是
  • 如果模板中有些标签,不需要编译,可以使用v-pre,跳过模板编译 image.png

06 v-cloak指令 (了解)

  • v-cloak 表示vm和模板没有关联好,不去编译{{}} image.png

07 v-if

  • v-if后面如果是真,就渲染DOM元素或组件

  • v-if可以控制一个DOM元素创建或销毁

  • 如果一个DOM元素,需要频繁地显示或隐藏,建议不要使用v-if

  • v-if是惰性的 如果判断值本身就是false,压根就不会创建

  • 每一次显示,都是创建出一个新的DOM元素,每一隐藏都是移除,销毁掉这个DOM元素

    <div id="app">
         <!-- v-if后面也是写表达式 -->
         <!-- " true " 不是字符串,不是字符串,不是字符串 -->
         <!-- v-if后面如果是真,就渲染DOM元素或组件 -->
         <!-- <h1 v-if=" true ">今天是08月08号,再过一段时间就9月份了</h1> -->
         <!-- v-if后面如果转化成假,这个DOM元素或组件压根不会渲染 -->
         <!-- <h1 v-if=" 1-1 ">今天是08月08号,再过一段时间就9月份了</h1> -->
            
         <button @click="handle">让盒子显示或隐藏</button>
         <!-- v-if可以控制一个DOM元素创建或销毁 -->
         <!-- 频繁地创建或销毁一个DOM元素,性能也很低 -->
         div class="box" v-if="show"></div>
    </div>
    <script>
       let vm = new Vue({
          el:"#app",
          data(){
              return {
                  // 响应式数据
                  // 默认是true
                  show:true
              }
          },
          methods:{
              handle(){
                  this.show = !this.show
              }
          }
       });
    </script>
    

08 v-else-if

  • show是什么就显示哪个div

  • v-if|v-eles-if|v-else中间不要出现其它的标签,否则就失效了,报警告了

    <div id="app">
      <!-- 需求: show是什么就显示哪个div -->
      <div class="pink" v-if=" show==='pink' "></div>
      <div class="skyblue" v-else-if=" show=='skyblue' "></div>
      <!-- v-if|v-eles-if|v-else中间不要出现其它的标签,否则就失效了,报警告了 -->
      <!-- <p>我是一个孤独的P标签</p> -->
      <div class="gold" v-else></div>
    </div>
    <script>
      let vm = new Vue({
          el: "#app",
          data() {
              return {
                  show:"gold"
              }
          }
      });
    </script>
    

09 template标签

  • template标签,也叫幽灵标签; 看上去是标签,但是渲染不出来

  • template可以当做不可见的包裹元素

  • template 控制一片div的显示或隐藏

    <div id="app">
      <template v-if="number==1">
          <div>haha</div>
          <div>haha</div>
          <div>haha</div>
      </template>
    
      <template v-else-if="number==2">
          <div>xixi</div>
          <div>xixi</div>
          <div>xixi</div>
      </template>
    
      <template v-else>
          <div>hehe</div>
          <div>hehe</div>
          <div>hehe</div>
      </template>
    </div>
    <script>
      let vm = new Vue({
          el: "#app",
          data() {
              return {
                  number: 1
                  // number是1显示第一片div
              }
          }
      });
    </script>
    

10 v-show

  • 通过v-show控制元素的显示与隐藏

    <div id="app">
      <button @click="handle">通过v-show控制元素的显示与隐藏</button>
      <!-- v-show后面不是字符串 -->
      <div class="box" v-show="show"></div>
    </div>
    <script>
      let vm = new Vue({
          el:"#app",
          data(){
              return {
                  // 响应式数据
                  show:true
                  // 如果为false    div标签还在,只是加上了style="display:none;"
              }
          },
          methods:{
              handle(){
                  this.show = !this.show
              }
          }
      });
    

v-if和v-show的区别?

v-if

  • v-if是控制元素的创建或销毁,每次创建出来的都是新的,创建或销毁DOM元素,很耗性能。
  • v-if后面的条件是false,它是惰性的,DOM元素压根不会创建
  • v-if支持template标签
  • v-if会导致浏览器的重排(重排一定会引起重绘)

v-show

  • v-show后面的条件不管是true或false,DOM元素都会创建,它是通过display来控制元素的显示或隐藏
  • v-show不支持template标签
  • v-show导致浏览器的重绘(重绘不一定引起重排)。
  • 如果需要频繁控制元素的显示或隐藏,那么使用v-show,不频繁,也可以使用v-if,尽可能使用v-show

11 v-modle指令

表单提交是开发中非常常见的功能,也是和用户交互的重要手段

  • 比如用户在登录、注册时需要提交账号密码
  • 比如用户在检索、创建、更新信息时,需要提交一些数据

v-model可以用来收集表单中的数据

  • v-model一般用在表单元素

  • v-model指令可以在表单 input、textarea以及select元素上创建双向数据绑定

  • 双向数据绑定:data变input内容变,输入框内容变data也变

    <div id="app">
      <!-- 不使用v-model,实现双向绑定 -->
      <!-- 希望:输入框内容变了,data也变    触发input事件 -->
      <!-- 不加小括号第一个参数表示事件对象 -->
      <input type="text" :value="msg" @input="inputChange">
    </div>
    <script>
      let vm = new Vue({
          el:"#app",
          data(){
              return {
                  msg:"i love vue"
              }
          },
          methods:{
              inputChange(e){
                  // 通过事件对象拿输入框内容    拿到之后要改变msg,给msg赋值就行
                  this.msg = e.target.value
              }
          }
      });
    </script>
    
  • 使用v-model

    <div id="app">
        //  v-model就是一个语法糖: :value + @input
        //  实现双向数据绑定
        <input type="text" v-model="msg">
    </div>
    <script>
      let vm = new Vue({
          el:"#app",
          data(){
              return {
                  msg:"i love vue"
              }
          },
          methods:{
              inputChange(e){
                  // 通过事件对象拿输入框内容    拿到之后要改变msg,给msg赋值就行
                  this.msg = e.target.value
              }
          }
      });
    </script>
    
  • 在vue中,如果监听器中的代码就一行,可以写在模板中,不建议使用 image.png

01 v-model绑定textarea

如何收集textarea中的数据 image.png

02 v-model绑定checkbox

  • checkbox可以作为一个单选框

  • checkbox多选框:v-model绑定的就是一个数组了

  • 每一个input上,必须有一个value

     <div id="app">
      <!-- checkbox可以作为一个是否同意的单选框 -->
      <label for="agree">
          <!-- 单个选框(是否同意按钮) v-model的值是布尔值 -->
          <input type="checkbox" id="agree" v-model="isAgree"> 同意xxx协议
      </label>
      <h2>单选框:{{isAgree}}</h2>
    
      <hr>
    
      <!-- checkbox多选框:v-model绑定的就是一个数组了 -->
      <!-- 每一个input上,必须有一个value -->
      <div class="hobbies">
          <h2>请选择你的爱好:</h2>
          <label for="sing">
              <input type="checkbox" id="sing" v-model="hobbies" value="sing"> 唱歌
          </label>
          <label for="coding">
              <input type="checkbox" id="coding" v-model="hobbies" value="coding"> 打代码
          </label>
          <label for="basketball">
              <input type="checkbox" id="basketball" v-model="hobbies" value="basketball"> 打篮球
          </label>
      </div>
      <h2>爱好:{{hobbies}}</h2>
    </div>
    
    <script>
      let vm = new Vue({
          el:"#app",
          data(){
              return {
                  isAgree:false,
                  hobbies:[]
              }
          }
      });
    </script>
    

03 v-model绑定radio

  • 收集radio输入框的内容

  • v-model收集的也是value值

  • name选项保证二选一

  • value不写可能收集不到数据

    <div id="app">
      <div class="gender">
          <label for="male">
              <!-- v-model收集的也是value值 -->
              <input id="male" name="sex" type="radio" v-model="gender"  value="male"></label>
          <label for="female">
              <input id="female" name="sex" type="radio" v-model="gender" value="female"></label>
          <h2>性别: {{gender}}</h2>
      </div>
    </div>
    
    <script>
      let vm = new Vue({
          el:"#app",
          data(){
              return {
                  gender:"female"
              }
          }
      });
    </script>
    

04 v-model绑定select

  • select下拉菜单
  • 需要加上value,因为最终收集的是value中的数据
  • v-model需要写在select身上

select的单选

  <select v-model="fruit">
        <option value="apple">苹果</option>
        <option value="orange">橘子</option>
        <option value="banana">香蕉</option>
    </select>
    <h2>单选:{{fruit}}</h2>

select的多选

  • 加上multiple 多选

  • size=3 表示可视区中显示几个选项

     <select multiple size="3" v-model="fruit2">
         <option value="apple">苹果</option>
         <option value="orange">橘子</option>
         <option value="banana">香蕉</option>
     </select>
     <h2>多选:{{fruit2}}</h2>
     
     <script>
     let vm = new Vue({
         el:"#app",
         data(){
             return {
                 // 默认情况下选中
                 fruit:"banana",
                 fruit2:["apple"]
             }
         }
     });
    </script>
    

05 v-model的修饰符

  • lazy 把input事件切换成change事件

  • input事件:输入框内容变,data也变

  • change事件:失去焦点后data中的数据才变

        input type="text" v-model.lazy="msg">
        <h2>msg:{{msg}}</h2>
    
  • number将绑定的字符串内容,转化为数字类型

        <input type="text" v-model.number="number">
        <!-- typeof number 判断number的类型  是否是字符串 -->
        <h2>number:{{number}} --- {{ typeof number }}</h2>
    
  • trim去掉首尾空格

         <input type="text" v-model.trim="str">
         <h2>str:{{str}}</h2>
    
  • 多个修改符可以连用

         <input type="text" v-model.lazy.number.trim="str">
    

12 v-for指令

01 v-for遍历数组

  • v-for 遍历,把一片数据渲染到页面上

  • v-for写谁身上 最终生成谁

  • v-for="(item,index) in data(data中的数据)

    <div id="app">
       <!-- v-for 遍历,把一片数据渲染到页面上 -->
       <!-- 遍历数组 -->
       <ul>
          <!-- v-for写在谁的身上,最终就遍历出多少个谁 -->
          <!-- v-for="(item,index) in data" -->
          <!-- item数组中的每一项,index数组中的索引 -->
          <li v-for="(item,index) in students">
              {{ item.name }}  ---  {{ index }}
         </li>
       </ul>
    </div>
    
    <script>
     let vm = new Vue({
         el: "#app",
         data() {
             return {
                 students: [{
                     id: 1,
                     name: "貂蝉"
                 },
                 {
                     id: 2,
                     name: '妲己'
                 },
                 {
                     id: 3,
                     name: '大桥'
                 },
                 {
                     id: 4,
                     name: '小乔'
                 },
                 {
                     id: 5,
                     name: '周瑜'
                 },
                 {
                     id: 1,
                     name: "貂蝉"
                 },
                 {
                     id: 2,
                     name: '妲己'
                 },
                 {
                     id: 3,
                     name: '大桥'
                 },
                 {
                     id: 4,
                     name: '小乔'
                 },
                 {
                     id: 5,
                     name: '周瑜'
                 }
                 ],
             }
         }
     });
    </script>
    

02 v-for遍历对象

   <div id="app">
    <h2>遍历对象</h2>
    <!-- 最终生成p标签,v-for写谁身上 最终生成谁 -->
    <!-- value是值   wangcai 18 男 -->
    <p v-for="value in obj">
        {{value}}
    </p>
    <hr>
    <!-- 可以写两个参数: key是键  键是指name、age、sex -->
    <p v-for="(value,key) in obj">
        {{value}} --- {{key}}
    </p>
    <hr>
    <!-- 也可以写三个参数 加上索引 索引一般不用 -->
    <p v-for="(value,key,index) in obj">
        {{value}} --- {{key}} --- {{index}}
    </p>
</div>

<script>
    let vm = new Vue({
        el: "#app",
        data() {
            return {
                obj: {
                    name: "wangcai",
                    age: 18,
                    sex: '男'
                }
            }
        }
    });
</script>

03 v-for遍历数字和字符串

 <div id="app">
    <h2>遍历数字</h2>
    <!-- 遍历从1-5  索引0-4 -->
    <p v-for="(num,index) in 5">
        {{num}} --- {{index}}
    </p>
    <hr>
    <h2>遍历字符串</h2>
    <!-- str是字符串中的每一个字母 -->
    <p v-for="(str,index) in 'ILoveVue'">
        {{str}} --- {{index}}
    </p>
</div>

04 计算属性、侦听器

01-计算属性的基本使用

  • 小胡子中的运算尽可能放在计算属性中
  • 计算属性:根据已有的状态,计算出一个新的状态
  • 计算属性写成函数的形式,实际上是一个属性值
  • 不能调用 即加()
  • 计算属性的值,取决于函数的返回值

计算属性不能写异步代码。如:定时器,ajax,事件绑定...

  • 在计算属性中,this表示vm

  • 计算属性会缓存

    <div id="app">
      请输入你的姓:<input type="text" v-model="firstName"> <br>
      请输入你的名:<input type="text" v-model="lastName"> <br>
      <!-- vue官方不推荐在{{}}语法中做运算 -->
      <!-- 拼出全名 -->
      <!-- <p>全名:{{ firstName + lastName }}</p> -->
    
      <p>全名:{{ allName() }}</p>
      <p>全名:{{ allName() }}</p>
      <p>全名:{{ allName() }}</p>
      <p>全名:{{ allName() }}</p>
      
      <hr>
    
      <!-- 在模板中,第1次使用计算属性时,会执行计算属性对应的函数 -->
      <!-- 后面如果计算属性依赖的数据没有发生变化,计算属性会缓存起来 -->
      <p>全名:{{ allName2 }}</p>
    
      <!-- 下面使用计算属性,都是从缓存中取出来的属性,性能高 -->
      <p>全名:{{ allName2 }}</p>
      <p>全名:{{ allName2 }}</p>
      <p>全名:{{ allName2 }}</p>
      
    <script>
      let vm = new Vue({
          el:"#app",
          data(){
              return {
                  firstName:"wang",
                  lastName:"Cai"
              }
          },
          methods:{
              // 把复杂运算放到方法中,也是OK的
              allName(){
                  // 走了四次
                  console.log("我是方法....");
                  return this.firstName + this.lastName
              }
          },
          
          // 计算属性
          computed:{
              // 状态 ==> 数据
              allName2(){
                  // 走一次,因为数据没变化  后面三次都是走的缓存
                  console.log("我是计算属性....");
    
                  // 计算属性的值,取决于函数的返回值
                  // return 123;
    
                  // 当计算属性依赖的数据变化了,计算属性会重新计算
                  // console.log(this);   this表示vm
                  return this.firstName + this.lastName;
              }
          }
      });
      console.log(vm);
    </script>
    

02-计算属性的完整写法

  • 写成对象的形式

    <script>
      let vm = new Vue({
          el:"#app",
          data(){
              return {
                  firstName:"Wang",
                  lastName:"Cai"
              }
          },
          methods:{
              updateName(){
                  // 计算属性allName也会挂载到vm上的
                  this.allName = "李-四"
              }
          },
          computed:{
              // 计算属性的另一种写法(用的不多) 对象的形式
              allName:{
                  // 当在模板中使用计算属性时,会自动走get
                  get(){
                      return this.firstName + "-" + this.lastName;
                  },
                  // 当修改计算属性时,会走set,但是一般情况下,不会修改计算属性
                  set(val){
                      // val是计算属性的新值
                      // console.log("set...");  // 验证修改后有没有走set
    
                      // console.log(val);  // 李-四
                      let arr = val.split("-") // 切成数组
                      this.firstName = arr[0]  // 拿到李
                      this.lastName = arr[1] 
                      // 拿到四
                  }
              }
          }
      });
    </script>
    

03 计算属性与方法的区别

  • 计算属性computed:属性

  • methods:方法

  • 使用时methods加(),computed不加()

  • computed有缓存

    <div id="app">
      <h2>{{ showMsg() }}</h2>
      <h2>{{ showMsg() }}</h2>
      <h2>{{ showMsg() }}</h2>
      <h2>{{ showMsg() }}</h2>
      <h2>{{ showMsg() }}</h2>
      <hr>
      <h2>{{ showTotal }}</h2>
      <h2>{{ showTotal }}</h2>
      <h2>{{ showTotal }}</h2>
      <h2>{{ showTotal }}</h2>
      <h2>{{ showTotal }}</h2>
    </div>
    
    <script>
      let vm = new Vue({
          el:"#app",
          data(){
              return {
               
              }
          },
          methods:{
              showMsg(){
                  console.log("我是方法");
                  return "method"
              }
          },
          computed:{
              // 有缓存
              showTotal(){
                  console.log("我是计算属性");
                  // 返回什么就是什么
                  return "computed"
              }
          }
      });
      console.log(vm);
    </script>
    

04-侦听器watch的使用

数据变了做一些其他事情,watch去监听这个数据

  • 函数的写法

      watch:{
            keyword(){
                  console.log("我侦听到了keyword的变化");
              }
      }
    
  • 对象的写法

      watch:{
            // 对象的写法,需要在对象中写一个handler
            // 当keyword发生了变化,会自动执行handler
            // handler名字不能随便写
            handler(){
                      console.log("我侦听到了keyword的变化");
                  }
      }
    

05-侦听器的配置选项

  • 如果想侦听到对象中所有的属性,需要写成对象的形式

在侦听器中可以写异步代码

     let vm = new Vue({
        el: "#app",
        data() {
            return {
                a: {
                    b: {
                        count: 1,
                        msg: '我爱你'
                    }
                }
            }
        },
        watch:{
           a:{
                deep:true, // 深度侦听  一上来没执行
                immediate:true, // 一上来,先执行一次侦听器
                handler(){
                    // console.log("i love u");  // 不能监听到,需要配置deep

                    // 在侦听器中可以写异步代码
                    setTimeout(()=>{
                        this.a.b.msg = "lalala"
                    },3000)
                }
            }
        }
   });

05 动态类名与行内样式

01-绑定class

01-动态类名之单个状态写法

  • 在一个标签上,既可以写动态类型(前面加:),也可以写非动态类型(前面不加:)

    <div id="app">
      <!-- 动态类名的写法  box2是一个状态 -->
      <!-- 在一个标签上,既可以写动态类型,也可以写非动态类型 -->
      <div :class="box2" class="box3">动态类名-单个状态的写法</div>
    </div>
    
    <script>
      let vm = new Vue({
          el:"#app",
          data(){
              return {
                  box2:"bad"
              }
          }
      });
    </script>
    

02-动态类名之对象写法

  • :class后面跟一个对象 { K:V } key是键,value是值

    <div id="app">
      <div :class="obj">
          千里之行,始于足下。——老子
      </div>
    </div>
    
    <script>
      let vm = new Vue({
          el:"#app",
          data(){
              return {
                  obj:{
                      // 键表示类名  值表示是否有这个类
                      one:true,
                      two:true,
                      three:false,
                      four:0
                  }
              }
          }
      });
    </script>
    

03-动态类名之数组写法

  • 直接写 数组的形式 image.png
  • 定义在状态里(响应数据) image.png

02-绑定style

01-动态行内样式之对象的写法

  • 写在标签里 image.png

  • 当成状态

     <div id="app">
         <p :style="obj">
          任何人都应当有自尊心,自信心,独立性,不然就是奴才
         </p>
    </div>
    
    <script>
      let vm = new Vue({
          el:"#app",
          data(){
              return {
                  // vm.obj.color = "red" 通过这种形式添加的数据并不是响应式数据
                  // 不是响应式数据,就意味着页面不会更新,但数据加上去了
    
                  obj:{  // obj本身就是响应式数据
                  
                      // 响应式数据可以修改
                      width:"200px",
                      height:"200px",
                      // vm.obj.background = "gold"   修改响应式数据,模板会更新
                      background:"skyblue"
                  }
    
                  // 需求:后期想给obj上添加响应式数据,如何添加?
                  // 去官网查
                  // 答:$set
              }
          }
      });
      vm.$set(vm.obj,"color","red")
    </script>
    
  • 删除一个响应式数据,使用$delete image.png

02-动态行内样式之数组的写法

  • 第一种写法:

     <!-- 数组中写对象 可以写多个对象 -->
     <p :style="[{color:'red',background:'skyblue'},{height:'300px'}]">
          任何人都应当有自尊心,自信心,独立性,不然就是奴才
     </p>
    
  • 第二种写法:

      <p :style="[obj1,obj2]">
          任何人都应当有自尊心,自信心,独立性,不然就是奴才
      </p>   
      <script>
      let vm = new Vue({
          el:"#app",
          data(){
              return {
                  obj1:{color:'red',background:'skyblue'},
                  obj2:{height:'300px'},
              }
          }
      });
    
  • 第三种写法:

       <p :style="arr">
          任何人都应当有自尊心,自信心,独立性,不然就是奴才
      </p>
      <script>
      let vm = new Vue({
          el:"#app",
          data(){
              return {
                  arr:[
                      {color:'red',background:'skyblue'},
                      {height:'300px'},
                  ]
              }
          }
      });
    

06-数组更新检测与Vue生命周期

01-数组更新检测

数组更新检测

  • Vue 将被侦听的数组的变更方法进行了包裹,所以它们也将会触发视图更新

    • push()
    • pop()
    • shift()
    • unshift()
    • splice()
    • sort()
    • reverse()
  • 下面的7个方法,会引起界面更新

    <div id="app">
      <ul>
         <li>{{name}}</li>
         <li>{{age}}</li>
         <li>{{sex}}</li>
         <li>{{hobby}}</li>
      </ul>
      <button @click="updateHobby">修改睡觉为打代码</button>
    </div>
    
    <script>
      let vm = new Vue({
        el:"#app",
        data(){
            return {
                name:"wc",
                age:18,
                sex:"man",
                hobby:["睡觉","吃饭","打豆豆"]
            }
        },
        methods:{
            updateHobby(){
                // 这样修改,数据已经变了,但是模板没有刷新
                // 这个修改数据,并非是响应式的
                // 如果数组中的数据是基本数据类型,通过索引去修改它,界面并不会更新
                // this.hobby[0] = "打代码";
    
                // 数据变了,界面也没有刷新
                // 通过数组的length修改数据,并排是响应式的
                // this.hobby.length = 2;
    
                // 调用数组的push,pop方法,也是响应式的
                // this.hobby.push("写代码")
                
                // this.hobby.pop()
                // this.hobby.splice(0,1,"打代码")
    
                // map返回一个加工后的新数组
                // console.log(this.hobby.map(item=>item=="睡觉" ? "打代码" : item));
                this.hobby = this.hobby.map(item=>item=="睡觉" ? "打代码" : item);
            }
        }
    });
    </script>
    
  • 数组中的元素是一个对象,通过索引修改对象中的属性,也会引起界面的更新

  • 在data中,一个对象不管嵌套多深,所有数据都是响应式数据

      <div id="app">
           <p>{{arr}}</p>
           <button @click="handle">修改data中的数据</button>
    </div>
    <script>
      let vm = new Vue({
          el: "#app",
          data() {
              return {
                  arr: ["xq", 123, { name: 'wangcai' }, true]
              }
          },
          methods:{
              handle(){
                  // 数据变了,但是界面没有更新,
                  // 通过索引调用  不是响应式数据
                  // this.arr[0] = "666";
    
                  // 调用数据的7个方法,是响应式的
    
                  // 如果数组中的元素是一个对象的话,通过索引去修改对象中的属性,也会引起界面的更新
                  this.arr[2].name = "xiaoqiang";
              }
          }
      });
    
      // 总结数据更新检测:
      //      在data中定义的数据都是响应式数据,有特殊情况:
      //      数组中的元素有可能是响应式的【数组中的元素是对象】,也有可能不是响应式的【基本类型】
      //      调用数组上的7个方法,也会引起界面更新
    </script>
    

02-Vue生命周期

  • 生命周期函数,也叫钩子函数,会在合适的时机自动调用

  • 函数的名字,不能随便,都是vue定死的

    <div id="app">
     <p :style="{opacity:tmd}">Vue是一个很NB的框架!!!</p>
    </div>
    
    <script>
     let vm = new Vue({
         el:"#app",
         data(){
             return {
                 tmd:1
             }
         },
         // 生命周期函数,也叫钩子函数
         // 这个函数会在合适的时机自动调用
         // 函数的名字,不能随便,都是vue定死的
         // 每一个钩子函数,都有特定的含义
         mounted(){
             setInterval(()=>{
                 this.tmd -= .1;
                 if(this.tmd<=0) this.tmd = 1;
             },500)
         }
     });
    </script>
    

02-Vue生命周期的8个钩子函数

  • beforeCreate,created

  • beforeMount,mounted

  • beforeUpdate,updated

  • beforeDestroy,destroyed

     <div id="app">
      <button @click="add">加1</button>
      <span ref="cur">{{count}}</span>
      <button @click="minus">减1</button>
      <br>
      <button @click="handle">销毁vm</button>
    </div>
    
    <script>
      let vm = new Vue({
          el:"#app",
          data(){
              return {
                  count:1
              }
          },
          methods:{
              add(){
                  this.count++
              },
              minus(){
                  this.count--
              },
              handle(){
                  // 销毁vm
                  this.$destroy(); 
              }
          },
          // 生成周期函数,最先执行执行的是beforeCreate,
          // 说明:vm还没有初始化完成   不能通过vm使用data中的方法和methods中的方法
          // 项目中没有什么用,了解就OK了
          beforeCreate(){
              // vm还没有初始化配置完毕,在这里不能获取vm的属性或方法
              console.log("初始化阶段:beforeCreate","vm没有初始化完毕",this.count);
              // this.count拿不到
          },
          // vm实例已经初始化完成了
          // 有用,在项目中,通常可以在这里发送ajax请求
          created(){
              // 此处,就可以获取vm的属性或方法了
              console.log("初始化阶段:created","vm初始化完毕", this.count);
          },
          // vm挂载之前调用
          // 项目中用的也不多 
          beforeMount(){
              // 可以获取vm实例,可以得到vm实例上的属性或方法,但是不能获取真实DOM
              console.log("挂载阶段:beforeMount","vm挂载之前执行一次",this.count,this.$refs.cur);
          },
          // vm已经挂载完毕了
          mounted(){
              // 挂载完毕,就可以获取DOM元素
              // 在这里,也可以发生ajax请求  个人一般在mounted中发请求
              console.log("挂载阶段:mounted","vm挂载完毕",this.$refs.cur);
          },
          // 更新阶段,当响应式数据发生了变化,就会触发一次
          beforeUpdate(){
              console.log("更新阶段:beforeUpdate",this.count);
          },
          // 更新阶段:当vm的响应式数据发生变化,更新界面会触发一次
          updated(){
              // 能不能在updated中更新状态?
              // 答:不能,会导致死循环
              console.log("更新阶段:updated",this.count);
          },
          // vm销毁之前调用
          beforeDestroy(){
              console.log("销毁阶段:beforeDestroy",this.count);
          },
          // vm销毁完毕:处理后事,如关闭之前开的一些定时器,或其它的收尾工作
          destroyed(){
              console.log("销毁阶段:destroyed",this.count);
          }
      });
    
      // 总结:
      //    初始化阶段:beforeCreate  created  只会执行一次
      //    挂载阶段:beforeMount  mounted  只会执行一次
      //    更新阶段:beforeUpdate  updated  只响应式数据发生变化,都会调用,调用N次
      //    销毁阶段:beforeDestroy  destroyed  
      //      销毁后,并不是说界面看不见了,vm实例还可以访问,但是它不工作了!!!!
    </script>
    

07-非单文件组件

01-认识组件

  • 组件:代码+资源,集合

非单文组件使用分为三步骤

  • 第一步:定义

  • 第二步:注册

  • 第三步:使用

    <div id="app">
      <!-- 第三步:使用 -->
      <!-- 配置好之后,当成标签来使用 -->
      <Hello></Hello>
      <Hello></Hello>
      <Hello></Hello>
      <Hello></Hello>
      <Hello></Hello>
    </div>
    
    <script>
    
      // 第一步:定义
      // 在extend中传组件的配置项
      // 之前new Vue时,传递的配置项,在Vuex.extend中基本上都可以配置
      let Hello = Vue.extend({
          // el 只有在根组件中才可以配置el,在普通组件中不能配置el
          template:"<h2>我是Hello组件</h2>", // 配置当前组件对应的模板
      })
    
      let vm = new Vue({
          el:"#app",
          data(){
              return {
               
              }
          },
          
          // 第二步:注册
          components:{
              // Hello:Hello 注册名、组件名   一样可以写一个
              Hello
          }
      });
    </script>
    

02-组件嵌套

  <div id="app">
    <!-- 使用组件就相当于使用标签 -->
    <Count></Count> <br>
    <Count></Count> <br>
    <Count></Count> <br>
    <Count></Count> <br>
    <Count></Count> <br>
    <Box></Box>  <br>
    <Box></Box>  <br>
    <Box></Box>  <br>
    <Box></Box>  <br>
</div>

<script>
    // 定义
    let Hello = Vue.extend({
        template: "<h1>我是Hello组件</h1>"
    })

    // Count组件
    let Count = Vue.extend({
        // 注册  Count里注册一个Hello
        components:{
            Hello
        },
        data(){
            return{
                count:0
            }
        },
        methods:{
            add(){ this.count++ },
            minus(){ this.count-- }
        },
        // 之前是el  现在是template
        template: `
            <div class="box">
                // 使用
                <Hello></Hello>
                <button @click="minus">-</button>
                <span>{{count}}</span>
                <button @click="add">+</button>
            </div>
        `
    })

    // 定义Box组件
    let Box = Vue.extend({
        data(){
            return{
                f:16
            }
        },
        // 配置
        template:`
            <div class="box1">
                <p :style="{fontSize:f+'px'}" @click="f++">我是一个孤独的P标签</p>
            </div>
        `
    })

    let vm = new Vue({
        el: "#app",
        // 注册  vm里注册一个Count
        components:{
            Count,
            Box
        },
        data() {
            return {

            }
        }
    });
</script>

03-根组件的template

对于根组件来说,可以在两个地方,指定模板

  • 1)el对应容器内部的html代码段

  • 2)配置template,用来指定模板

  • template的优先级更高

    <div id="app">
      <div>我是一个DIV</div>
    </div>
    
    <script>
      // 对于根组件来说,可以在两个地方,指定模板
      //    1)el对应容器内部的html代码段
      //    2)配置template,用来指定模板
      //    如果指定了template,它的优先级更高  打印出haha  而不是:我是一个DIV
      let vm = new Vue({
          el: "#app",
          template:`
              <div>haha</div>
          `,
          data() {
              return {
    
              }
          }
      });
      // template指定模板  用$mount
      vm.$mount("#app")
    </script> 
    

04-引出App组件

  <div id="app">
  </div>
  <script>
     // 定义App组件
    const App = Vue.extend({
        // App组件中还可以有其他组件  Count Box
        // 注册
        components:{
            Count,
            Box
        },
        // 定义
        template:`
            <div> App组件 </div>
        `
    })
    let vm = new Vue({
        // 跟组件中注册,根目录下就有一个App组件
        components:{
            App
        },
        // 使用
        template:`
            <div>
                <App></App>
            </div>
        `,
        data() {
            return {

            }
        }
    });
    vm.$mount("#app")
 </script>

05-全局注册组件

注册组件分两种:

  • 1)局部注册 在哪里注册,在对应的模板中使用

  • 2)全局注册 只需要注册一次,可以在任何地方使用

    <div id="app1">
      <div>
          我是DIV1
          <hr>
          <Count></Count>
      </div>
    </div>
    
    <div id="app2">
      <div>
          我是DIV2
          <hr>
          <Count></Count>
      </div>
    </div>
    <script>
      // 定义Count组件
      const Count = Vue.extend({
          data() {
              return {
                  count: 1
              };
          },
          template: `
              <div>
                 <button @click="count++">加</button>
                 <span>{{count}}</span>
                 <button @click="count--">减</button>    
              </div>
           `
      });
      // 全局注册  在项目中,有些组件为了使用方法,都会使用全局注册
      组件名:Count,组件:Count
      Vue.component("Count",Count)
      let vm1 = new Vue({
          el:"#app1",
          data(){
              return {
               
              }
          }
      });
      let vm2 = new Vue({
          el:"#app2",
          data(){
              return {
               
              }
          }
      });
    </script>
    

06-vm、vc与组件的关系

  • 根组件实例叫vm 普通组件实例叫vc

  • vm看得见 vc看不见 image.png

  • VueComponent是一个类,Vue底层会帮我们new

    <div id="app">
    
    </div>
    
    <script>
      // 定义Count组件
      // extend返回一个构造函数,叫VueComponent
      const Count = Vue.extend({
          data() {
              return {
                  count: 1
              };
          },
          template: `
              <div>
                 <button @click="count++">加</button>
                 <span>{{count}}</span>
                 <button @click="count--">减</button>    
              </div>
           `
      });
      console.log(Count);
      // c叫组件对象  这是我们new出来的
      // 之前vue底层帮我们new出来
      let c = new Count();
      // 也可以使用Vue原型对象上的属性或方法
      console.log(c.$data);
      let vm = new Vue({
          el: "#app",
          data() {
              return {
                  a:1
              }
          }
      });
      // console.log(vm.$data);
    </script>
    
  • Student构造器对应的是VueComponent类的实例:vc,底层帮我们new出来

    <div id="app">
      <Student></Student>
    </div>
    
    <script>
      Vue.prototype.coding = function(){
          console.log("开始打代码了...");
      }
    
      // 当我们使用Vue.extend 得到一个VueComponent构造器
      // 不需要我们new  Vue底层会帮我们new 
      let Student = Vue.extend({
          data() {
              return {
                  info: 'I love Vue!!!'
              };
          },
          template: `
              <h1 @click="changeInfo">{{info}}</h1>
          `,
          methods: {
              changeInfo() {
                  // this.info = "I love React!!!"
                  // 问:this是谁?
                  // 答:vc     Student构造器对应的实例vc,底层帮我们new出来的
                  // 组件内的this,不是vm,不是vm,不是vm,是VueComponent类的实例
                  // 看上去和vm很像,但实际上,两者是不同东西
                  // 组件内的this,就是VueComponet类的实例,可以叫它VC
                  // this.coding();  
    
                  console.log(this.__proto__.__proto__ === Vue.prototype);
              }
          }
      });
    
    
      let vm = new Vue({
          el: "#app",
          components:{
              Student
          },
          data() {
              return {
                  a: 1
              }
          },
          methods:{
              ok(){
                  // this表示vm
                  console.log(this);
              }
          }
      });
    </script>
    

07-Vue.extend创建组件简写方式

   <script>
    // 下面是Vue.extend的简写形式
    // 定义组件
    let App = {
        // 为了在调试工具中显示正确的组件名,通常会配置name选项
        name:"App",
        data(){
            return{
                name:"wc"
            }
        },
        template:`
            <div>
                <h1 @click="handler">{{name}}</h1>
            </div>
        `,
        methods:{
            handler(){
                this.name = "xq";
                // this表示vc
                console.log(this);
            }
        }
    }

    let vm = new Vue({
        el:"#app",
        components:{
            // Abc表示注册名  App表示组件名
            // "Abc":App    // 上面不配置name选项    组件名就是Abc
            App
        },
        data(){
            return {
             
            }
        }
    });
</script>

08-脚手架

安装插件

  • 插件一:Vetur,从Vue2开发就一直在使用的VSCode支持Vue的插件
  • 插件二:Volar,官方推荐的插件

Vue CLI 安装和使用

  • 全局安装: npm install @vue/cli -g

  • 升级Vue CLI(如果是比较旧的版本,可以通过下面的命令来升级): npm update @vue/cli -g

  • 通过Vue的命令来创建项目: vue create 项目的名称

    每次修改js都需要重新跑一下 npm run serve
    

scoped表示该样式只在当前组件显示 < HelloWorld/>组件 image.png

vue.config.js中使用lintOnSave关闭exlint image.png

根组件下的 < App/>组件

 export default 向外暴露出一个对象

image.png

09-父传子与todolist案例

image.png

01-父传子

01-props的第一种写法

  • props代表子组件接收父组件的数据
  • props有多种写法,第一种写法,props后面写一个数组
  • props中写自定义属性的名字 image.png
  • 自定义属性,加 : image.png

02-props的第二种写法

  • 对象的写法 image.png

02-子传父

01-在组件上绑定自定义事件

  • 父组件 App

    <template>
      <div class="app">
        <h1>我是父组件 王健林</h1>
        <hr>
        <MySon @wc="handler"></MySon>
      </div>
    </template>
    <script>
      import MySon from "./components/MySon.vue"
      export default {
           name: 'App',
           components: {
                 MySon
           },
            methods:{
              handler(val){
                // val是子传递给父的数据
                console.log("val:",val);
              }
           }
     }
    </script>
    
  • 子组件 MySon

    <template>
      <div class="son">
          <h1>我是子组件 王思聪</h1>
          <!-- @click="clickHandler" 不叫自定义事件,是封装好的事件 -->
          <button @click="clickHandler">触发自定义事件</button>
      </div>
    </template>
    
    <script>
    export default {
      name: "MySon",
      props:[],
      data() {
        return {
           money:500,
        };
      },
      methods: {
        clickHandler(){
         //   console.log("clickHandler...");
        // 在这里,触发自定义事件
    
        // 为什么找两次
        // 因为在vc身上没有是$emit,沿着原型链可以去Vue的原型对象上找到$emit
        // console.log(this);
    
        // this.money给父亲
        // this.$emit("wc",this.money)
    
        this.$emit("xq",this.car)
       }
     },
    };
    </script>
    

02-$on绑定自定义事件

通过ref拿DOM元素

<template>
   <MySon @wc="handler" ref="cur"></MySon>
</template>

<script>
 // 当组件挂载完毕执行一次mounted
 mounted(){  
  // 当代码走到这里,说明,组件都挂载,渲染完毕
  // 问:能不能获取组件实例? 答:可以

  // console.log(this.$refs.cur); // 得到VC实例,才能实现绑定

  // 可以通过$on绑定自定义事件
  // 当xq事件发生了,处罚监听器
  this.$refs.cur.$on("xq",(val)=>{
    // 谁触发了xq事件,就可以传递数据
    console.log("val:",val);
  })
},  
</script>

10-自定义指令 directives

指令:对DOM元素进行底层操作时,可以使用自定义指令

01-自定义局部指令

  • 自定义局部指令:只能在当前组件中使用
  • 在MyCommont1组件中定义的自定义指令,在其它组件中是不能使用的
  • 想要在其他组件中使用,需要封装全局指令 在main.js中配置 image.png

02-自定义全局指令

  • 自定义全局指令:在任意组件中使用

  • 第二个参数是函数形式 image.png

  • 第二个参数是对象形式 image.png

11-过滤器 filter

01-局部过滤器

使用过滤器

time时间进行格式化,进行过滤
 <h1>{{ time | timeFormat }}</h1>
  • myapp文件夹下安装 npm i moment
  • 安装出现以下问题,在npm i moment后加上 --legacy-peer-deps image.png
  • 安装成功过后进行以下操作 image.png

02-全局过滤器

image.png

12-插件

  • 在main.js中使用插件 image.png
  • 自定义插件
  • vue规定插件身上要有一个install方法 image.png image.png

13-事件总线

  • 配置全局事件总线,就是在Vue原型对象身上配置$bus属性

    $bus身上有,$on$emit  
    $on注册自定义事件 订阅 可以用来接收数据  
    $emit触发自定义事件  发布 可以用来发送数据
    
  • 在mian.js中配置 image.png

孙子传给爷爷

  • 孙子中,发布数据 image.png
  • 爷爷中,订阅(接收)数据 image.png 老大传给老二,兄弟间
  • 老大发布 image.png
  • 老二订阅 image.png

14-github案例

  • 分成两个组件,是兄弟关系 image.png
  • 方法一:在上面组件发送请求,响应请求就返回到上面组件,拿到数据后然后再把数据传到下面组件
  • 方法二:把搜索框的内容拿到传到下面组件,然后在第二个组件中发送请求,响应请求返回到第二个组件中 image.png
  • 在vue.config.js配置代理
  • 不需要记,用的时候去vue官网抄 image.png

01-对axios二次封装

  • 安装:npm i nprogress image.png image.png

  • 导出封装后的axios

    export default axios;
    
  • 使用axios image.png

15-前端路由

01-前端路由的两种

  • 路由器router:维护一个映射表,映射表可以决定的数据的流向
  • 前端路由核心:url发生了变化,监听到url变化了,需要切换页面(组件)

01-hash路由

image.png

02-h5中的history路由

API

  • pushState( ):打开一个指定的地址; image.png
  • popstate( ):前进或后退可以被监听到 image.png

02-vue-router的基本使用

  • 安装Vue Router:npm install vue-router@3.5.3

  • 若安装不上后面加上 --legacy-peer-deps

  • 一个路由器中可以配置N个路由,一个路由就是一个对象

  • 这个对象中,配置一个路径对应一个组件

    总结一个路由的基本使用:
       1)创建router文件夹,里面创建index.js
       2)在index.js中引入路由,并安装插件(npm install vue-router@3.5.3)  Vue.use
       3)创建路由器对象  new VueRouter()  并导出
       4)在路由对象中配置路由规则  routes 
       5)在main.js中 导入路由器对象  并挂载到根组件上  
       6)配置路由的出口,就是当路径匹配到的话,对应的组件放在哪里
    
  • router-view是vue-router这个插件中内置好的组件

  • 代表路由的出口,路径匹配到的组件,就需要放到出口中 image.png

  • redirect表示重定向 image.png

03-router-link实现跳转

  • router-link,类似于a标签 image.png

      总结:
      1)vue-router帮我们封装了两个组件
        <router-view></router-view>  路由的出口
        <router-link></router-link>  类似于a标签,点击实现跳转
      2)使用vue开发的项目,都是单页面  SPA
        url改变了,监听到,需要在路由出口中放不同的组件,页面只有一张,变化的是路由出口中的组件
    

04-路由懒加载

  • 懒加载:切换到这个路由时再去加载
  • 第一步在硬盘打包 npm run build
  • 第二步使用import进行懒加载,在硬盘再次打包npm run build
  • 第三步 npm run serve
  • 第四部利用魔法注释起名字,再次打包npm run build
  • npm run serve image.png

05-嵌套路由和404组件

嵌套路由步骤

  • 第一步:创建组件,pages文件夹下
  • 第二步:配置规则,router文件夹下的index文件里
  • 第三步:配置出口并使用,组件里

404组件

  • 创建NotFound组件 image.png

06-动态路由

  • 配置 image.png

       vue-router帮我们提供了两个组件:
        <router-view>
        <router-link>
      除上上面的两个组件之外,还有两个对象,就是vc实例身上
        $route 路由对象  身上有N个属性   params属性
        $router 路由器对象  隐式原形对象上有N个方法  back  forward  go(-1)  go(1)
        一个路由器有n个路由
    

params传参 image.png

  • 也可以在组件实现跳转,相当于a标签 image.png

query传参 image.png

07-编程式路由

声明式路由 image.png

编程式路由 image.png

  • 后退 image.png

08-路由导航守卫

  • 没有登录进去也可以访问
  • 配置路由的全局守卫 image.png

16-CRM案例

image.png

  • npm i 安装依赖
  • 路由组件:在router文件夹下index.js里配置的组件,可以放在pages文件夹也可以放在views文件夹里
  • components里放的是非路由组件

17-vuex状态管理(集中状态管理)

官网:vuex.vuejs.org/zh/guide/

image.png

 store:仓库
 State:状态
 Mutations:修改状态唯一属性
 Devtool:追踪状态 

01-vuex介绍与非脚手架中使用

Vuex:集中状态管理 状态理解成数据

引入Vuex.js
<script src="./libs/vuex.js"></script>

<div id="app">
    <h1>根组件</h1>
    <hr>
    <add-counter></add-counter>
    <hr>
    <sub-counter></sub-counter>
</div>

<script>
    // 创建一个仓库  需要传入一个配置对象
    let store = new Vuex.Store({
        // state是状态  是集中管理的状态
        // 状态是响应式的
        // 组件中的data中的状态也是状态式
        state: {
            counter: 0
        },
        // 修改状态的唯一途径
        mutations: {
            
        },
        // 放异步代码,如果有异步操作,代码需要写在actions中
        actions: {

        },
        // 类似于组件中的计算属性
        // 根据已有状态计算出一个新的状态
        getters: {

        }
    });

    // 定义组件
    let AddCounter = Vue.extend({
        template: `
        <div>
            <p>我是addcounter组件</p>
            <p>在addcounter组件中使用仓库中的数据:{{$store.state.counter}}</p>
            <button @click="add">加1</button>
        </div>
        `,
        methods:{
            add(){
                // 这样是粗暴地修改状态  极力不推荐
                // 如果其它组件也这样修改状态,状态不好追踪了
                // this.$store.state.counter++;
                
                // 这时需要commit一个mutation,通过mutation去修改状态
            }
        }
    })
    let SubCounter = Vue.extend({
        template: `
        <div>
            <p>我是subcounter组件</p>
            <p>在subcounter组件中使用仓库中的数据:{{$store.state.counter}}</p>
            <button @click="sub">减1</button>
        </div>
        `,
        methods:{
            sub(){
                // this.$store.state.counter--;

               // 利用commit一个mutation
                this.$store.commit("sub")
            }
        }
    })

    // this.$store.state.counter
    let vm = new Vue({
        el: "#app",
        store, // vuex也是一个插件,需要挂载到根组件上,就意味着,它的子子孙孙,都可以使用这个仓库了
        components:{
            AddCounter,
            SubCounter
        },
        data() {
            return {

            }
        }
    });
</script>
  • mutations修改状态

       mutations: {
              // 每一个mutations就是一个函数
              // 第1个参数是仓库中的state
              // payload 是commit mutation时,传递的参数
              // 下面的100传给了playload
              add(state,payload){
                  // state.counter++;
                  state.counter += payload
              },
              sub(state){
                  state.counter--;
              }
          }
          
          在组件中使用:
          mutations: {
                  // 需要commit一个mutation,通过mutation去修改状态
                  // 组件中调用
                  this.$store.commit("add",100)
           }
    

02-脚手架中使用vuex

  • 在src(源码)文件夹下创建一个store文件夹(仓库)
  • 创建脚手架 vue create myapp
  • 不选Linter,否则安装vuex时报错 image.png
  • 安装vuex npm i vuex@3.6.2
  • store下创建index.js,导入vuex、导出store仓库
  • main.js中导入store仓库,并把仓库挂载到根目录上
  • 在components文件夹下创建组件、定义组件
  • App中使用组件 image.png

03-mapState的使用

  • mapState将仓库中的状态映射成组件的计算属性 image.png

04-mapGetters的使用

  • mapGetters也可以把仓库中的计算属性映射成组件的计算属性 image.png
  • 使用getter的方式一 image.png
  • 使用getter的方式二 image.png

05-mapMutations的使用

  • mapMutations可以把仓库中的mutation映射成组件的方法 image.png
  • 传参 image.png

06-mapActions的使用

  • mapActions可以action映射成组件的方法 image.png image.png

18-过渡动画

image.png

  • vue中的过渡动画

  • Vue外向暴露了一些类,利用这些class就可以完成过渡动画。

      v-enter-from:进入过渡开始的状态 
      v-enter-active:进入过渡生效时状态
      v-enter-to:进入过渡结束的状态 
    
      v-leave-from: 离开过渡的开始状态
      v-leave-active: 离开过渡生效时状态
      v-leave-to: 离开过渡结束的状态 
    

image.png

  • div需要用transition包住,如果没有起名就用v-打头

      rotate是旋转  
      0deg0度
      scale是缩放
    

19-vant组件库

  • 封装好的组件库,网站:vant-contrib.gitee.io/vant/v2/#/z…

    1)全部安装
         # Vue 2 项目,安装 Vant 2:
         npm i vant@latest-v2 -S
    (2)自动按需引入
        # 安装插件:
        npm i babel-plugin-import -D
        babel.config.js 中配置
    (3)组件中使用——引入
        全局注册
        局部注册
    

20-网易云音乐

  • 创建项目时,选择router 、vuex直接就可以安装

  • 项目运行后,安装 axios、vant(npm i vant@latest-v2 -S)

  • 按需引入,安装插件 npm i babel-plugin-import -D

    网易云本地接口文件夹下:运行入口,node app.js
    若报错,安装:npm install express
    

适配

  • 安装: npm i postcss

  • 安装:npm i postcss-pxtorem

  • 创建:postcss.config.js文件

    配置
    module.exports = { 
       plugins: { 
         'postcss-pxtorem': { 
           rootValue: 37.5, 
           propList: ['*'], 
         }, 
      }, 
    };
    

21-新蜂商城

项目部署

  • 第一步:npm run biuld打包

  • 第二步:去Gitee上创建一个仓库,网址:gitee.com/

    登录后,点击创建仓库,如下:
    (1)左上角点击仓库
    (2)右上角点击+
    (3)写名字
    (4)点击创建
    

(1) image.png (2) image.png (3) image.png (4) image.png

  • 第三步:创建完复制链接 image.png 右键点,Git Bash Here 必须先安装Gei image.png git clone克隆+链接,paste粘贴 image.png 效果如下,点回车 image.png

  • 第四部:复制打包后的文件

    打开桌面上生成的文件夹 image.png

    复制打包后生成的dist文件夹中的文件,复制到xfshop文件夹里 image.png clear清除 image.png

  • 第五步:把项目扔到原仓库

    cd xfshop进到xfshop里 image.png git add . image.png git commit -m "项目over" image.png git push origin master image.png

  • 第六步:查看效果,代码已放入仓库 image.png

  • 第七步:点击右上方“服务”——>Gitee Pages image.png 启动 image.png

  • 第八步:出错

  • 打包后的index.html中,直接是/js,需要在前面加上/xfshop image.png

    搜索,在vue.confi中配置
    

image.png image.png

配置代码:publicPath:"/xfshop",
  • 第九步:配置好,重新打包:npm run build 打包后效果(前面加上了/xfshop) image.png
  • 第十步:重新把dist文件夹中的代码复制到xfshop文件夹中
  • 第十一步:传到git服务器上,git add .重复上述步骤:git commit -m "项目over"、git push origin master
  • 第十二步:点击服务,更新 image.png
  • 第十三步:若报错,重新更新不勾选强制使用HTTPS image.png 不要走https,后端有的不支持https image.png