绑定样式

绑定样式:

对应小程序视频:小程序->在线->VUE->day02 8. 绑定样式 style ...

  1. 绑定内联样式:
    问题: 网页中很多效果都是批量修改多个css属性。如果一个一个修改每个css属性,代码会很繁琐

解决: 只要批量修改一个元素的多个css属性,都用class来修改。

  1. 绑定class:
    (1). 不好的方式: 将整个class看做一个大的字符串来绑定

问题: 极其不便于修改其中某一个class
(2). 好的方式: 对象语法

  1. 直接在HTML中使用匿名对象:
    1). 如何:

<元素 :class="{ class名1:变量1, class名2:变量2,... }"
data:{
变量1:true或false, //开关,是否启用一个class
变量2:true 或false //开关,是否启用一个class
}
2). 原理: new Vue()会从data中取出每个变量的bool值放到HTML中变量的位置上。如果哪个class的变量值为true,则这个class就会出现在最终编译后的页面元素上。如果哪个class的变量值为false,则这个class不会出现在最终编译后的页面元素上。

<!DOCTYPE html>

<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script src="js/vue.js"></script>
  <style>
    .span-cls{
      padding:5px 10px;
    }
    .success{
      background-color:lightGreen;
      border:1px solid green;
      color:green;
    }
    .fail{
      background-color:pink;
      border:1px solid red;
      color:red;
    }
  </style>
</head>
<body>
  <!--1.做界面
    1.1 找哪里可能发生变化
    //本例中:3处变化
    //1. 文本框的内容由用户主动输入改变,所以应该用v-model绑定
    //2. span的样式可能发生改变,但是因为同时修改的css属性很多,所以要绑定class。而且,是在.success和.fail两个class中二选一启用
    //3. span的内容可能发生改变,所以用{{}}或v-text
    1.2 找哪里可能触发事件
    //本例中: 文本框失去焦点时触发验证
  -->
  <div id="app">
    手机号:<input v-model="phone" @blur="vali">
    <!-- <span :class="{success:success, fail:fail}">手机号格式正确</span> -->
    <span :class="{success, fail}">{{msg}}</span>
  </div>
  <script>
    //2. 创建new Vue()对象
    new Vue({
      el:"#app",
      //3. 创建模型对象: 
      //因为界面上需要4个变量,所以
      data:{
        phone:"",
        success:false,
        fail:false,
        msg:""
      },
      //因为界面上需要一个事件处理函数,所以
      methods:{
        vali(){
          //定义手机号的正则: 复习JS高级第一天
          var reg=/^1[3-9]\d{9}$/;
          //如果验证手机号的内容通过
          //     复习JS高级第二天
          if(reg.test(this.phone)){
            //启用success样式类,禁用fail样式类
            this.success=true;
            this.fail=false;
            //并修改错误提示
            this.msg="√ 手机号格式正确"
          }else{//否则如果验证不通过,就禁用success样式类,启用fail样式类
            this.success=false;
            this.fail=true;
            //并修改错误提示
            this.msg="× 手机号格式不正确"
          }
        }
      }
    })
  </script>
</body>
</html>

结果

4). 问题: 如果多个元素都需要使用同一个样式类,但是启用禁用状态各不相同!就会出现命名冲突

5).解决: 用有名称的对象来解决

用有名称的对象来绑定:
1). 如何:
<元素1 :class="变量1">
<元素2 :class="变量2">
data:{
变量1: {
class1:true或false,
... : ...
},
变量2:{
class1:true或false,
... : ...
}
}
2). 好处,即使多个元素共用同一个class,但是启用禁用状态各不相同,也不会发生命名冲突
3). 示例:使用有名称的class对象验证两个文本框

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script src="js/vue.js"></script>
  <style>
    .span-cls{
      padding:5px 10px;
    }
    .success{
      background-color:lightGreen;
      border:1px solid green;
      color:green;
    }
    .fail{
      background-color:pink;
      border:1px solid red;
      color:red;
    }
  </style>
</head>
<body>
  <!--1.做界面
    1.1 找哪里可能发生变化
    //本例中:每个文本框的验证都有3处变化
    //1. 文本框的内容由用户主动输入改变,所以应该用v-model绑定
    //2. span的样式可能发生改变,但是因为同时修改的css属性很多,所以要绑定class。
    //3. span的内容可能发生改变,所以用{{}}或v-text
    //因为有两个文本框需要验证,所以,共有6处变化
    1.2 找哪里可能触发事件
    //本例中: 文本框失去焦点时触发验证
  -->
  <div id="app">
    手机号:<input v-model="phone" @blur="vali_phone">
    <span :class="phone_class">{{phone_class.msg}}</span><br/>
    身份证号:<input v-model="pid" @blur="vali_pid">
    <span :class="pid_class">{{pid_class.msg}}</span>
  </div>
  <script>
    //2. 创建new Vue()对象
    new Vue({
      el:"#app",
      //3. 创建模型对象: 
      //因为界面上需要6个变量,所以
      data:{
        phone:"",
        pid:"",
        phone_class:{
          success:false,
          fail:false,
          msg:""//因为验证通过或不通过时,都是class和msg同时改变,所以把msg变量也合并进class对象内一起修改。
        },
        pid_class:{
          success:false,
          fail:false,
          msg:""
        }
      },
      //因为界面上需要2个事件处理函数,所以
      methods:{
        vali_phone(){
          //先定义手机号正则: 
          var reg=/^1[3-9]\d{9}$/;
          //如果验证手机号内容通过
          //     复习JS高级第二天
          if(reg.test(this.phone)){
            //启用success样式类,禁用fail样式类
            //并修改错误提示
            this.phone_class={
              success:true,
              fail:false,
              msg:"√ 手机号格式正确"
            }
          }else{//否则如果验证不通过,就禁用success样式类,启用fail样式类
            //并修改错误提示
            this.phone_class={
              success:false,
              fail:true,
              msg:"× 手机号格式不正确"
            }
          }
        },
        vali_pid(){
          //先定义手机号正则: 
          var reg=/^\d{15}(\d\d[0-9Xx])$/;
          //如果验证身份证号内容通过
          //     复习JS高级第二天
          if(reg.test(this.pid)){
            //启用success样式类,禁用fail样式类
            //并修改错误提示
            this.pid_class={
              success:true,
              fail:false,
              msg:"√ 身份证号格式正确"
            }
          }else{//否则如果验证不通过,就禁用success样式类,启用fail样式类
            //并修改错误提示
            this.pid_class={
              success:false,
              fail:true,
              msg:"× 身份证号格式不正确"
            }
          }
        }
      }
    })
  </script>
</body>
</html>

结果

自定义指令

二. 自定义指令:

对应小程序视频: 小程序->在线->VUE->day03 1. 自定义指令

  1. 什么是: 除了官方提供的13种指令之外,程序员根据自身需要为Vue大家庭添加的新的自定义指令
  2. 何时: 只要我们希望在元素刚加载到页面上时,就自动对元素执行一些初始化的DOM操作。就可以用指令
  3. 如何: 2步;
    (1). 添加自定义指令:

    1. Vue.directive("指令名", {
      //回调函数: 会在当前标有这个自定义指令的元素被添加到页面上之后,自动调用该回调函数。

//当自动调用回调函数时,会自动将当前带有自定义指令的元素对象传入inserted函数内
inserted(当前dom元素对象){
//对当前DOM元素对象执行一些初始化操作
}
})

  1. 结果: 在当前页面的内存中的Vue类型中,就多了一种自定义指令
  2. 强调:
  3. 定义指令名时,一定不要加v-前缀
  4. 如果指令名包含多个英文单词,比如my focus,应该-分割多个英文单词,比如my-focus,不应该用驼峰命名
    (2). 如何使用自定义指令: 同使用官方指令完全一样!

html中: <元素 v-指令名></元素>
强调: 但是在使用指令时,却必须加v-前缀!

  1. 原理: 当new Vue()扫描到一个元素上带有不认识的v-开头的指令时,new Vue()就会在内存中,vue大家庭中,查找有没有同名的自定义指令!一旦找到同名的自定义指令,则自动调用指令中的inserted()函数,对当前带有指令的DOM元素执行初始化的DOM操作。
  2. 示例: 添加自定义指令,让一个元素开局自动获得焦点
    2_directive.html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script src="js/vue.js"></script>
</head>
<body>
  <!--我想让文本框开局就自动获得焦点,但是vue官方没有提供对应的指令或其他操作方式。
      我们只能添加自定义的指令!通过指令的自动执行,让文本框获得焦点-->
  <div id="app">
    <input type="text" v-my-focus><button>百度一下</button>
  </div>
  <script>
    //向vue大家庭中添加一个名为my-focus的自定义指令
    Vue.directive("my-focus",{
      //希望当带有这个指令的元素被添加到页面上时,自动调用inserted函数
      inserted(domElem){
        //在函数内,让当前DOM元素自动获得焦点
        domElem.focus();//复习DOM第四天
      }
    })

    new Vue({
      el:"#app"
    })
  </script>
</body>
</html>

结果
命名规则:

  1. 如果这个名字将来是在HTML中使用,如果包含多个单词,都用-分割多个单词,而不要用驼峰命名
    因为HTML默认不区分大小写的!

比如: HTML无法区分: myFocus, MyFocus, myfocus

  1. 如果这个名字是js中的变量名或对象名,则如果包含多个单词,应该用驼峰命名。因为js中不能随便写-,与减法的减号冲突!

计算属性

三. 计算属性:

对应小程序视频: 小程序->在线->VUE->day03 2. 计算属性

  1. 问题: 有些值,需要根据其他属性值经过复杂的计算才能获得
  2. 解决: 使用计算属性
  3. 什么是: 自己不保存属性值,而是需要根据其他变量的值动态计算获得自己的属性值的特殊属性,就叫计算属性
  4. 如何:
    (1). new Vue({

el:"#app",
data:{ ... },
methods:{ ... },
computed:{
计算属性名(){
复杂的计算过程
return 返回值
}
}
})
(2). 使用计算属性时:
<元素>{{计算属性名}}</元素>
强调:千万不要加()

  1. 原理:
    (1). 首次new Vue()扫描到计算属性时,会自动执行计算属性的函数,获得返回值。new Vue()会立刻将本次计算的返回值缓存起来,反复使用。

(2). 下一次new Vue()再次扫描到同名的计算属性时,不会重复调用函数重复计算,而是自动从缓存中获取计算结果,直接使用!——避免重复计算,效率高!
(3). 除非当计算属性依赖的另一个变量值发生变化,才重新调用一次计算属性的函数,计算出新的结果,再次缓存起来反复使用!

  1. computed中的计算属性与methods中的函数有什么差别:
    (1). methods中普通函数的计算结果不会被缓存,导致反复计算——效率低

(2). computed中的计算属性值会被缓存,反复使用,不会反复计算——效率高

  1. 如何选择:
    (1). 如果一个操作更倾向做一件事儿,而不太关心返回的结果时——优先选择methods

(2). 如果一个操作更倾向于使用操作的返回值时,而不太关心过程——优先选择computed。

  1. 示例: 使用计算属性计算购物车总价:
    3_computed.html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script src="js/vue.js"></script>
</head>
<body>
  <div id="app">
    <h3>总价: ¥{{total.toFixed(2)}}</h3>
    <!--1.想把购物车中的商品显示到页面上-->
    <ul>
      <li v-for="(p,i) of cart" :key="i">
        {{p.lid}} | {{p.lname}} | ¥{{p.price.toFixed(2)}} | {{p.count}} | 小计:¥{{(p.price*p.count).toFixed(2)}}
      </li>
    </ul>
    <h3>总价: ¥{{total.toFixed(2)}}</h3>
  </div>
  <script>
    new Vue({
      el:"#app",
      data:{
        cart:[
          {lid:1, lname:"华为", price:5588, count:2},
          {lid:2, lname:"苹果", price:8588, count:1},
          {lid:3, lname:"小米", price:3588, count:3}
        ]
      },
      methods:{
      
      },
      computed:{
        //定义一个专门根据购物车中商品列表计算总价的计算属性
        total(){
          console.log(`调用了一次total()`)
          var result=0;
          //遍历购物车中每个商品
          for(var p of this.cart){
            //将每个商品的单价*数量求出小计,将小计累加到总计中
            result+=p.price*p.count;
          }
          //返回总计
          return result;
        }
      }
    })
  </script>
</body>
</html>

运行结果

过滤器

四. 过滤器:

对应小程序视频: 小程序->在线->VUE->day03 3. 过滤器

  1. 什么是: 可以对变量的原始值进行加工后再显示出来 的函数
  2. 为什么: 程序中很多变量值是不能直接给人看的,必须经过加工才能显示给人看。比如:
    (1). 性别: 程序中保存的是1和0,人希望看到的是男和女

(2). 时间: 程序中保存的是毫秒数,人希望看到的是年月日时分秒

  1. 何时: 今后只要变量的原始值不能直接给人看,需要加工后才能给人看时,都要用过滤器
  2. 如何:2步
    (1). 为Vue大家庭添加过滤器函数:


Vue.filter("过滤器名称", function(变量的原始值){
← return 加工后的新值
})
(2). 在HTML中使用过滤器:
<元素>{{变量 | 过滤器名称}} </元素>
连接

  1. 原理: 当new Vue()扫描到|过滤器语法时,就去Vue大家庭中查找有没有同名的过滤器。如果找到同名的过滤器,就自动调用过滤器函数。而且会将|前的变量的原始值自动传给过滤器函数的参数。在过滤器函数内对原始值进行加工后。过滤器函数返回加工后的新值。new Vue()再把新值显示到元素的内容位置
  2. 示例: 使用过滤器过滤性别后再显示
    4_filter.htm
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script src="js/vue.js"></script>
</head>
<body>
  <div id="app">
    <h3>性别1:{{sex1 | sexFilter}}</h3>
    <h3>性别2:{{sex2 | sexFilter}}</h3>
  </div>
  <script>
                                //   1或0
                                //     ↓
    Vue.filter("sexFilter",function(oldVal){
      return oldVal==1?"男":"女";
    })

    new Vue({
      el:"#app",
      data:{
        sex1:1, 
        sex2:0
      }
    })
  </script>
</body>
</html>

运行结果

7 其实过滤器也可以传参数:

(1). 如何: 2步

  1. 定义过滤器时:
    Vue.filter("过滤器名",function(变量的原始值, 自定义形参, ...){

})
1). 第一个形参永远时变量的原始值
2). 自定义的其它形参必须从第二个位置开始写

  1. 使用过滤器时:
    <元素>{{变量 | 过滤器名(实参值1, ..., ...)}}</元素>

1). 调用时,自定义的第一个实参值,要放在过滤器第一个实参值位置,但是却是传给过滤器中第二个形参的
2). 调用时,变量的原始值总是默认传给过滤器的第一个形参。
(2). 示例: 使用参数控制翻译性别的语言种类
4_filter2.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script src="js/vue.js"></script>
</head>
<body>
  <div id="app">
    <h3>性别1:{{sex1 | sexFilter("en")}}</h3>
    <h3>性别2:{{sex2 | sexFilter("en")}}</h3>
    <h3>性别1:{{sex1 | sexFilter("cn")}}</h3>
    <h3>性别2:{{sex2 | sexFilter("cn")}}</h3>
  </div>
  <script>
                                //1或0  "en"或"cn"
                                //  ↓        ↓
    Vue.filter("sexFilter",function(oldVal, yuyan){
      if(yuyan=="en"){
        return oldVal==1?"Male":"Female"
      }else{
        return oldVal==1?"男":"女";
      }
    })

    new Vue({
      el:"#app",
      data:{
        sex1:1, 
        sex2:0
      }
    })
  </script>
</body>
</html>

运行结果

8.其实过滤器也可以连用:
解析图

(1). 如何: <元素>{{变量 | 过滤器1 | 过滤器2 | ... }}</元素>
(2). 强调: 后一个过滤器接到的不是原始的变量值,而是前一个过滤器加工后的中间产物
(3). 示例: 为性别翻译后的结果追加性别图标
4_filter3.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script src="js/vue.js"></script>
</head>
<body>
  <div id="app">
    <h3>性别1:{{sex1 | sexIcon}}</h3>
    <h3>性别2:{{sex2 | sexIcon}}</h3>
    <h3>性别1:{{sex1 | sexFilter("en") | sexIcon}}</h3>
    <h3>性别2:{{sex2 | sexFilter("en") | sexIcon}}</h3>
    <h3>性别1:{{sex1 | sexFilter("cn") | sexIcon}}</h3>
    <h3>性别2:{{sex2 | sexFilter("cn") | sexIcon}}</h3>
  </div>
  <script>
    //                      1,0,男,女,Male,Female
    //                              ↓             
    Vue.filter("sexIcon",function(oldVal){
      if(oldVal==0){
        return "♀";
      }else if(oldVal==1){
        return "♂";
      }else if(oldVal=="男"||oldVal=="Male"){
        return oldVal+"♂";
      }else{
        return oldVal+"♀";
      }
    })
                                //1或0  "en"或"cn"
                                //  ↓        ↓
    Vue.filter("sexFilter",function(oldVal, yuyan){
      if(yuyan=="en"){
        return oldVal==1?"Male":"Female"
      }else{
        return oldVal==1?"男":"女";
      }
    })

    new Vue({
      el:"#app",
      data:{
        sex1:1, 
        sex2:0
      }
    })
  </script>
</body>
</html>

运行结果

axios

axios

对应小程序视频: 小程序->在线->VUE->day03 4. axios

  1. 问题: 虽然在jquery中$.ajax()函数已经很好用!但是,在vue中几乎很少使用DOM操作,自然也就很少使用jQuery。所以,几乎vue中不会把jquery引入项目中!所以,在vue中就无法使用$.ajax()
  2. 解决: 今后每学习一种框架,都会包含一种专门的发送ajax请求的函数!在vue中,用的就是axios函数库
  3. 什么是axios: 第三方开发的,基于Promise技术的,专门发送http请求的一组函数库。
  4. 何时: 今后只要在vue中发送ajax请求,都用axios
  5. 如何:
    (1). 下载并引入axios.js

<script src="js/axios.min.js">

(2). 发送请求: 
a. 发送get请求: 
axios.get("url",{params:{ 参数: 值, ... }}).then(result=>{
    //result.data中才是服务器端返回的数据
})
b. 发送post请求: 
axios.post("url","参数1=值1&参数2=值2&...").then(result=>{
    //result.data才是服务器端返回的数据
})
  1. 示例: 使用axios请求首页商品,商品详情,登录验证
    5_axios.html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <table id="data">
    <thead>
      <tr>
        <th>商品名称</th>
        <th>描述</th>
        <th>单价</th>
      </tr>
    </thead>
    <tbody>
      <tr v-for="(p,i) of products" :key="i">
        <td>{{p.title}}</td>
        <td>{{p.details}}</td>
        <td>¥{{p.price.toFixed(2)}}</td>
      </tr>
    </tbody>
  </table>
  <script src="js/vue.js"></script>
  <script src="js/axios.min.js"></script>
  <script>
    //必须用live server运行,且端口必须是5500
    //1. 去东哥新浪云服务器请求学子商城首页商品列表/index
    axios.get(
      "http://xzserver.applinzi.com/index"
    ).then(result=>{
      console.log(result.data);
      new Vue({
        el:"#data",
        data:{
          products:result.data
        }
      })
    })
    
  </script>
</body>
</html>

结果

5_axios2.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    [v-cloak]{
      display:none
    }
  </style>
</head>
<body>
  <ul id="app">
    <li v-cloak>品名: {{title}}</li>
    <li v-cloak>描述: {{subtitle}}</li>
    <li v-cloak>单价: ¥{{price.toFixed(2)}}</li>
    <li v-cloak>服务承诺: {{promise}}</li>
  </ul>
  <script src="js/vue.js"></script>
  <script src="js/axios.min.js"></script>
  <script>
    //!!!地址栏: xxx.html?lid=10

    //从地址栏获得查询字符串参数
    var search=location.search;
    //如果有查询字符串参数的话
    if(search!==""){
      console.log(search);//?lid=10
      //                        |
      //                 ["?lid","10"]
      //                    [0]   [1]
      //将search按=切割,然后取第二部分商品编号值
      var lid=search.split("=")[1];

      //想从东哥新浪云服务器请求5号商品的详细信息
      axios.get(
        "http://xzserver.applinzi.com/details",
        {
          // params:{ lid:lid }
          params:{ lid } 
        }
      ).then(result=>{
        console.log(result.data);
        new Vue({
          el:"#app",
          data:{
            title:result.data.product.title,
            subtitle:result.data.product.subtitle,
            price:result.data.product.price,
            promise:result.data.product.promise
          }
        })
      })
    }
  </script>
</body>
</html>

结果

5_axios3.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script src="js/vue.js"></script>
  <script src="js/axios.min.js"></script>
</head>

<body>
  <div id="app">
    用户名:<input v-model="uname"><br />
    密码:<input type="password" v-model="upwd"><br />
    <button @click="login">登录</button>
  </div>
  <script>
    new Vue({
      el: "#app",
      data: {
        uname: "",
        upwd: ""
      },
      methods: {
        login() {
          axios.post(
            "http://xzserver.applinzi.com/users/signin",
            `uname=${this.uname}&upwd=${this.upwd}`
          ).then(result=>{
            if (result.data.ok == 1) {
              alert(`登录成功,欢迎${result.data.uname}`);
            } else {
              alert(`登录失败, ${result.data.msg}`)
            }
          })
        }
      }
    })
  </script>
</body>

</html>

结果

生命周期

六. 生命周期:

对应小程序视频: 小程序->在线->VUE->day03 5. 生命周期

  1. 问题: 将来项目中所有的js代码必须写在new Vue()内部!new Vue()外部不能写任何js代码!但是,有些需要在页面加载完成后就自动执行的代码写哪儿?
  2. 错误:
    (1). DOM时: 都写在window.onload中!但是new Vue()没有window.onload

(2). jq时: 都写在$(document).ready(function(){ ... })!但是new Vue()也不用jquery

  1. 正确: 其实每个new Vue()对象创建的过程都会经历一个生命周期,在生命周期的每个阶段,都会自动触发一个类似于window.onload这样的回调函数!
    4. vue的生命周期包括: 4个阶段>>鄙视题

(1). 创建create(对象)——必经阶段

  1. 创建new Vue()对象
  2. 引入并创建data对象,同时请保镖——可以操作data中的变量
  3. 引入methods中的函数——可以调用methods中的函数
  4. 暂时不会扫描DOM树,生成虚拟DOM树——暂时不能执行DOM操作!
    (2). 挂载mount(页面内容)——必经阶段
  5. 扫描真实DOM树,生成虚拟DOM树
  6. 首次加载数据到页面中显示!
  7. 可以执行DOM操作了!
    (3). 更新update——只有当data中的数据被改变时才触发

(4). 销毁destroy——只有主动调用$destroy()销毁当前new Vue()时才触发

  1. 其实每个阶段前后,都会自动触发一个回调函数——钩子函数
    共8个钩子函数!

beforeCreate() (1). 创建阶段create created()
beforeMount()
(2). 挂载阶段mount
mounted() —— 因为此时既有data对象,又有虚拟DOM树,所以今后axios请求都要放在mounted()中才保险
beforeUpdate()
(3). 更新阶段update
updated()
beforeDestroy
(4). 销毁阶段 destroy
destroyed

  1. 示例: 使用生命周期和钩子函数请求服务器端数据并加载到页面

5_axios.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <table id="data">
    <thead>
      <tr>
        <th>商品名称</th>
        <th>描述</th>
        <th>单价</th>
      </tr>
    </thead>
    <tbody>
      <tr v-for="(p,i) of products" :key="i">
        <td>{{p.title}}</td>
        <td>{{p.details}}</td>
        <td>¥{{p.price.toFixed(2)}}</td>
      </tr>
    </tbody>
  </table>
  <script src="js/vue.js"></script>
  <script src="js/axios.min.js"></script>
  <script>
    var vm=new Vue({
      el:"#data",
      data:{
        products:[]
      },
      beforeCreate(){
        console.log(`创建data对象前自动执行...`)
      },
      created(){
        console.log(`创建data对象后自动执行...`)
      },
      beforeMount(){
        console.log(`将数据挂载到页面上之前自动执行...`)
      },
      mounted(){
        console.log(`将数据挂载到页面上之后自动执行...`)
        // //如果希望页面加载完成后,就自动发送请求,请求服务器端首页商品
        axios.get(
          "http://xzserver.applinzi.com/index"
        ).then(result=>{
          console.log(result.data); 
          //将请求回来的商品列表保存到data中的products变量上,最终绑定到页面上显示!
          this.products=result.data;
        })
      },
      beforeUpdate(){
        console.log(`更新data中的变量前自动执行...`)
      },
      updated(){
        console.log(`更新data中的变量后自动执行...`)
      },
      //vm.$destroy()
      beforeDestroy(){
        console.log(`销毁整个new Vue()对象前自动执行...`)
      },
      destroyed(){
        console.log(`销毁整个new Vue()对象后自动执行...`)
      }
    })
    
  </script>
</body>
</html>

运行结果

5_axios2.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    [v-cloak] {
      display: none
    }
  </style>
</head>

<body>
  <ul id="app">
    <li v-cloak>品名: {{title}}</li>
    <li v-cloak>描述: {{subtitle}}</li>
    <li v-cloak>单价: ¥{{price.toFixed(2)}}</li>
    <li v-cloak>服务承诺: {{promise}}</li>
  </ul>
  <script src="js/vue.js"></script>
  <script src="js/axios.min.js"></script>
  <script>
    new Vue({
      el: "#app",
      data: {
        title: "",
        subtitle: "",
        price: 0,
        promise: ""
      },
      mounted() {
        //!!!地址栏: xxx.html?lid=10

        //从地址栏获得查询字符串参数
        var search = location.search;
        //如果有查询字符串参数的话
        if (search !== "") {
          console.log(search);//?lid=10
          //                        |
          //                 ["?lid","10"]
          //                    [0]   [1]
          //将search按=切割,然后取第二部分商品编号值
          var lid = search.split("=")[1];

          //想从东哥新浪云服务器请求5号商品的详细信息
          axios.get(
            "http://xzserver.applinzi.com/details",
            {
              params:{ lid }
            }
          ).then(result => {
            console.log(result.data);
            this.title=result.data.product.title;
            this.subtitle=result.data.product.subtitle;
            this.price=result.data.product.price;
            this.promise=result.data.product.promise
          })
        }
      }
    })

  </script>
</body>

</html>

运行结果

组件component

七. 组件component:

  1. 什么是组件: 包含专属的HTML+JS+CSS+数据的可重用的页面独立的功能区域。
  2. 为什么: 重用
  3. 何时: 今后只要在页面中发现反复使用的功能区域,都要创建为组件,再反复使用
  4. 如何: 2步:
    (1). 添加一个自定义组件:

//如果包含多个单词,用-分割
Vue.component("组件名",{
//每个组件其实都是一个缩微版的new Vue()
//但是有两处不同:

标红:
 template:`<唯一父元素包裹> 组件的HTML片段 </唯一父元素包裹>`,
data(){ //可被反复调用
//每次调用时都会新创建一个data对象
return {//new Object()
变量:初始值
}
},

/同new Vue()的部分*/
methods:{ ... },
computed:{ ... },
钩子函数(){ ... },
... ...
})
(2). 在HTML中使用组件:
组件其实就是一个可重用的自定义HTML标签而已!组件名就是自定义标签名!
<组件名></组件名>

  1. 原理:
    (1). 当new Vue()扫描页面时,发现了不认识的自定义HTML标签,就会回内存中Vue大家庭中找自定义组件。

(2). 只要找到同名的组件,先用组件的template内容代替当前自定义标签的位置
(3). 为这个区域创建一个缩微的new Vue()对象副本,并创建一个当前组件专属的data对象副本,包含专属的变量
(4). 结果: 这个小的组件区域,就拥有了专属的HTML+数据+一个缩微版的new Vue()组件对象。
解析图

  1. 示例: 创建一个修改数量的组件,并反复使用

6_component.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script src="js/vue.js"></script>
</head>
<body>
  <div id="app">
    <my-counter></my-counter>
    <my-counter></my-counter>
    <my-counter></my-counter>
  </div>
  <script>
    //先定义一个自定义组件,可以修改数量
    Vue.component("my-counter",{
      //Vue三步
      //1. 先做界面
      //1.1 找可能发生变化的位置
      //本例中: span的内容可能发生变化
      //1.2 找可能触发事件的位置
      template:`<div>
        <button @click="minus">-</button>
        <span>{{n}}</span>
        <button @click="add">+</button>
      </div>`,
      //2. 创建对象
      //因为界面上需要1个变量
      data(){
        return {
          n:0
        }
      },
      //因为界面上需要2个事件处理函数
      methods:{
        add(){
          this.n++;
        },
        minus(){
          if(this.n>0){
            this.n--
          }
        }
      }
    })

    new Vue({
      el:"#app"
    })
  </script>
</body>
</html>

运行结果

组件化开发

正课:

总结

  1. 绑定语法+13种指令
    (1). 如果元素的内容需要随变量自动变化: {{}}

(2). 如果元素的属性值需要随变量自动变化: :
(3). 控制一个元素显示隐藏: v-show
(4). 控制两个元素二选一显示: v-if v-else
(5). 多个元素多选一显示: v-if v-else-if v-else
(6). 只要反复生成多个相同结构的元素组成列表时: v-for :key="唯一标识"
(7). 只要绑定事件: @ $event
(8). 防止用户短暂看到{{}}: v-cloak和v-text
(9). 只要绑定原始HTML代码片段内容: v-html
(10). 如果元素的内容只在首次加载时绑定一次,之后都不会改变: v-once
(11). 保护内容中的{{}}不被编译: v-pre
(12). 今后只要想获得表单元素的值或状态: v-model

  1. 绑定样式:
    (1). 需要精确修改某一个css属性,就绑定style:

    1. <元素 style="固定样式" :style="{css属性:变量名, ...}"
      data:{

变量名:css属性值
... : ...
}

  1. <元素1 style="固定样式" :style="变量名1">
    <元素2 style="固定样式" :style="变量名2">

data:{
变量名1:{
css属性名: 属性值,
... : ...
},
变量名2:{
css属性名: 属性值,
... : ...
}
}
(2). 只要批量修改一个元素的多个css属性就绑定class

  1. <元素 class="固定class" :class="{class名:变量名, ...}"
    data:{

变量名:true或false,
... : ...
}

  1. <元素1 class="固定class" :class="变量名1"
    <元素2 class="固定class" :class="变量名2"

data:{
变量名1:{
class名:true或false,
... : ...
},
变量名2:{
class名:true或false,
... : ...
},
}

  1. 只要希望在页面加载时自动对元素执行一些初始化操作时就用自定义指令:
    (1). 添加自定义指令:

Vue.directive("自定义指令名",{
inserted(domElem){ 对domElem执行DOM操作 } }) (2). 使用自定义指令: <元素 v-自定义指令名>

  1. 今后只要根据其他变量的值动态计算出一个属性值就用计算属性:
    <元素>{{计算属性}}</元素>

new Vue({
el:"#app",
data:{...},
methods:{...},
computed:{
计算属性名(){
计算过程
return 计算结果
}
}
})

  1. 希望将变量的原始值先加工后再显示给用户看时就用过滤器:
    Vue.filter("过滤器名",function(oldVal, 自定义形参,...){

return 加工后的新值
})
<元素>{{ 变量 | 过滤器(实参值, ...) | ... }}</元素>

  1. 只要在vue中发送ajax请求,就用axios
    axios.defaults.baseURL="服务器端接口的公共基础地址部分"

axios.get(
"服务器端接口地址的相对路径",
{
params:{ 参数名: 参数值, ... }
}
).then(result=>{
... result.data...
})

axios.post(
"服务器端接口地址的相对路径",
"参数名1=参数值1&参数名2=参数值2&..."
).then(result=>{
... result.data...
})
强调: 在vue内使用axios,then中必须用箭头函数,保持then内this与外部this一致,都指向当前new Vue()对象

  1. vue生命周期4个阶段 8个钩子函数
    beforeCreate(){ ... } (1). 创建(create) created(){ ... } beforeMount(){ ... } (2). 挂载(mount) mounted(){ ... 经常在这里发送ajax请求 ... } beforeUpdate(){ ... } (3). 更新(update) updated(){ ... } beforeDestroy(){ ... } (4). 销毁(destroy)

destroyed(){ ... }

  1. 只要希望重用一块独立的功能区域就用组件:
    (1). 定义组件

Vue.component(组件标签名,{
template:HTML内容片段,
data(){ return { 变量 } },
//其余和new Vue()完全相同
})
(2). 在HTML中使用自定义组件
<组件标签名/>或双标记也行
(3). 原理: new Vue()扫描到自定义组件标签,
a.组件的template中的HTML内容代替页面中<组件标签>位置。

  1. 并为这个小区域专门创建一个缩微版的vue类型对象。
    1). 调用组件的data()函数为当前组件副本创建一个专属数据对象副本。

2). 引入组件对象中的methods等其他内容到当前组件对象副本中

  1. 组件化开发:
    (1). 步骤:

    1. 拿到页面先划分功能区域
      1). 从上到下,按功能不同划分区域

2). 按是否重用划分

  1. 为每个组件创建独立的.js文件,其中包含一个组件对象及其内容
  2. 将所有组件引入唯一完整的html页面中,并在<div id=”app”></div>中添加父组件标签。
    (2). 运行时:
  3. new Vue()扫描<div id=”app”>,发现父组件标签,创建并替换父组件
  4. 父组件扫描自己内部的template内容,创建并替换子组件
    (3). 三种组件:
  5. 根组件: new Vue()
  6. 全局组件: Vue.component(...)
  7. 子组件: 3步
    1). var 子组件对象名={

内容必须符合组件的要求
}
子组件对象名必须是驼峰命名
2). 父组件对象中:{
... ...
components{ 子组件对象名, ... ,... }
}
子组件对象名必须是驼峰命名
3). 父组件template中用<子组件标签名/>引入子组件内容
components会将子组件对象名的驼峰命名自动翻译为-分隔
所以, 使用子组件标签时,要用-分隔多个单词
(2). 组件间传参: 父给子

  1. 父组件给:
    <子组件 :自定义属性名="父组件变量">
  2. 子组件取:
    props:["自定义属性名"]

结果: 在子组件内,props中的"自定义属性名"与子组件自己data中的变量用法完全相同!

今日对应小程序视频列表:
小程序->在线->VUE->day02 8. 绑定样式 style ...
小程序->在线->VUE->day03 1. 自定义指令

  1. 计算属性
  2. 过滤器
  3. axios
  4. 生命周期
    6.1 创建单个组件

6.2 Vue组件化开发todo

正文结束
本文作者:
文章标题:Vue day03
本文地址:https://rickyduan.ink/index.php/archives/102.html
版权说明:若无注明,本文皆学习日记原创,转载请保留文章出处。
最后修改:2020 年 09 月 25 日 08 : 15 PM
如果觉得我的文章对你有用,请随意赞赏