vue.js基础知识学习

Vue 专栏收录该内容
2 篇文章 0 订阅

打包工具:webpack,Gulp

vue.js

  • vue.js React都是前端框架,都可以开发网站和手机APP,vue需要借助weex进行手机APP的开发
  • 前端三大主流框架:Vue.js Angular.js React.js
  • vue.js是一套构建用户界面的框架,只关注视图层

框架和库的区别

  • 框架:是一套完整的解决方案,对项目的侵入性较大,项目如果需要更换框架,则需要重新架构整个项目

    • node 中的 express
  • 库 (插件):提供某一个小功能,对项目的侵入性较小,如果某个库无法完成某些需求,可以很容易切换到其他库实现需求。

    • 1.从jquery切换到 Zepto
    • 2.从EJS 切换到 art-template

Node(后端)中的MVC与前端中的MVVM之间的区别

  • mvc是后端的分层开发概念
    • 后端的分层开发概念:为了保证模块的职能单一
      • 项目入口模块(app.js):一切的请求,都要先进入这里进行处理(注意:此模块并没有路由分发的功能,需要调用,路由模块进行路由的分发处理)
      • 路由模块(router.js):只负责分发路由,不负责具体业务逻辑的处理
      • 业务逻辑模块(controller):封装了一些具体的业务逻辑处理的逻辑代码,只负责处理业务,不负责处理数据的CRUD。,如果涉及到了CRUD,则需要调用Model层
      • Model层:只负责操作数据库,执行对应的js等语句,进行数据的CRUD:增删改查
        • C:create R:Read U:update D:Delete
      • View 视图层(请求过程):每当用户操作了界面,如果需要进行业务处理,就会通过网络请求,去请求后端的服务器,此时,我们的这个请求,就会被后端的App.js监听到
      • app.js \ router.js \ controller \ Model层就是我们的处理过程;View 视图层就是请求过程
      • router.js \ controller 是controller 层 、 Model层 、View 视图层 (MVC)
  • mvvm是前端视图层的概念,主要关注于视图层分离,也就是说:mvvm把前端的视图层分成了三部分 Model,View,VM ViewModel
    • mvvm是前端视图层的分层开发思想,主要把每个页面分成了 m、v、和vm ,其中,vm是mvvm思想的核心:因为vm是m和v之间的调度者
      • m (数据):这里的m保存的是每个页面中单独的数据
      • vm:它是一个调度者,分割了m和v(每当v层想要获取活保存数据的时候,都要由vm做中间的处理)
      • v(视图):就是每个页面中的html结构
  • 前端页面中使用mvvm的思想,主要是为了让我们的开发更加方便,因为mvvm提供了数据的双向绑定;数据的双向绑定是由vm提供的。

vue.js基本代码和mvvm之间的对应关系

  • <!-- 将来new的vue实例,会控制这个元素的所有内容 -->
    <!-- vue 实例所控制的这个元素区域  就是我们的v -->
    <div id="app">
            <p id="content">{{msg}}</p>
    </div>
    <script>
            // 2,创建一个vue的实例
            // 当我们导入包之后,在浏览器的内存中,就多了一个vue 构造函数
            // 注意:我们new出来的这个vm对象,就是我们mvvm中的vm调度者
            var vm = new Vue({
                el: '#app', //表示,当前我们new的这个vue实例,要控制页面上的哪个区域
                // 这里的data就是mvvm中的m,专门用来保存每个页面的数据的
                data: { //data属性中,存放的是el中要用到的数据
                    msg: '欢迎学习vue', //通过vue 提供的指令,很方便的就能把数据渲染到页面上,程序员不用手动操作dom元素了[前端的vue之类的框架,不提倡我们去手动操作dom元素了]
                }
            })
    </script>
    

    vue.js的语法结构

    <div id = "app">
    </div>
    
    //创建vue实例
    var vm = new Vue({
               el:'#app',   //绑定页面
               props:{ //进行组件之间的传值操作
                   
               }
               data:{  //这个 data 属性中定义了当前vue实例所有可用的数据
                   msg:'123',
                   msg2:'<h1>哈哈,我是一个大大的h1</h1>',
                   mytitle:'这是一个自己定义的title',
               },
               methods:{  //这个 methods 属性中定义了当前vue实例所有可用的方法
                  show:function(){
                      alert('Hello')
                  } 
               },   
                filters:{
                    //定制私有的过滤器
                },
               directives:{
                   //定制私有的指令
               },
               components:{
                   //定制实例内部私有的组件
               },    
              watch:{// 主要用于监听事件。使用这个属性,可以监听data中指定数据的变化,然后触发这个watch中对应的function处理函数
                  
              },
              computed:{ // 计算属性
                  
              },
              created(){ // 实例创建完成,还没有挂载在页面上
                 
              },
              mounted(){ // 挂载完成
                  
              }
               beforeCreate(){},
               created(){},
               beforeMount(){},
               mounted(){},
               beforeUpdate(){},
               updated(){},
               beforeDestroy(){},
               destoryed(){}   
       
           })
    
    
    
    
***vue.js相关的注意点
  1. 注意:在vm实例中,如果想要获取data上的数据,或者想要调用methods中的放法,必须通过this.数据属性名 或 this.方法名 来进行访问,这里的this 就表示我们new出来的vm实例对象
  2. 注意:vm实例,会监听自己身上data中所有数据的改变,只要数据一发生变化,就会自动把最新的数据,从data上同步到页面中去;[好处:程序员只需要关心数据,不需要考虑如何重新渲染DOM页面]
  3. 定时器中的this指向window。匿名函数的this指向window。箭头函数解决了函数中this指向的问题,使内部的this始终预外部的this保持一致

vue指令

vue之-基本代码结构和插值表达式、v-cloak

  • 使用v-cloak能够解决插值表达式的闪烁问题
    • 使用方法:

      +++++++ {{msg}} ----------


      使用的时候必须加,不加的话没用

vue指令之v-textv-html

  • 进行数据绑定
    • 默认v-text是没有闪烁问题的,v-text会覆盖元素中原本的内容,但是插值表达式只会替换自己的这个占位符,不会把整个元素的内容清空
    • v-html可以绑定的html格式的数据,会自动解析html格式的数据。v-text只能绑定纯文本形式的数据,不会解析html语法。

vue指令之v-bind的三种用法

  • 绑定属性的指令
    • v-on vue提供的属性绑定机制 缩写是
    • 使用方法
      第一种:<input type="button" value="按钮" v-bind:title="mytitle">
      第二种:<input type="button" value="按钮" v-bind:title="mytitle + '123'">
      第三种:<input type="button" value="按钮" :title="mytitle + '123'">
    • v-bind:是vue中提供的用于绑定属性的指令
    • 注意:v-bind指令可以被简写为:要绑定的属性
    • v-bind中,可以写合法的js表达式

vue指令之v-on和跑马灯效果

  • 绑定事件的指令
    • v-on vue提供的事件绑定机制 缩写是@
    • 使用方法
      <input type="button" value="按钮" :title="mytitle + '123'" v-on:click = "alert('hello')">
      上面这个是错误的写法:会把后面的当成变量来执行
      第一种:<input type="button" value="按钮" v-on:click = "show">
      第二种:<input type="button" value="按钮" @click = "show">
  • 跑马灯效果
  1. HTML结构
       <div id="app">
               <input type="button" value="浪起来" @click = "lang">
               <input type="button" value="低调" @click = "stop">
               <h4>{{msg}}</h4>
        </div>
  1. javascript代码
      var vm = new Vue({
              el:"#app",
              data:{
                  msg:'猥琐发育,别浪~',
                  intervalId:null,  //在data上定义 定时器Id
              },
              methods:{
                  lang(){
                      if(this.intervalId != null) return;
                      // console.log(this.msg)
                      // var _this = this;                
                      // 定时器中的this指向window.匿名函数的this指向window.箭头函数解决了函数中this指向的问题,使内部的this始终预外部的this保持一致
                      this.intervalId = setInterval(() => {
                          // 获取到头的第一个字符
                      var start = this.msg.substring(0,1);
                      // 获取到后面的所有字符
                      var end = this.msg.substring(1);
                      // 重新拼接得到新的字符串,并赋值给this.msg
                      this.msg = end + start
                      },400)              
                      // 注意:vm实例,会监听自己身上data中所有数据的改变,只要数据一发生变化,就会自动把最新的数据,从data上同步到页面中去;[好处:程序员只需要关心数据,不需要考虑如何重新渲染DOM页面]
                  },
                  stop(){ //停止定时器
                  clearInterval(this.intervalId)
                  // 每当清除了定时器之后,需要重新把intervalId 置为null
                  this.intervalId = null;
                  }
      
              }
          })        

vue指令之v-on的缩写和事件修饰符

事件修饰符:

  • .stop 阻止事件冒泡
  • .prevent 阻止默认行为
  • .capture 添加事件侦听器时使用事件捕获模式
  • .self只当事件在该元素本身(比如不是子元素) 触发时触发回调
  • .once 事件只触发一次
  • 使用方法:
       <!-- 使用.stop  阻止事件冒泡 -->
      <div class="inner" @click = "div1Handler">
                  <input type="button" value="戳他" @click.stop = "btnHandler">
      </div>
      <!-- 使用.prevent阻止默认行为 -->
      <a href="http://www.baidu.com" @click.prevent = "linkClick">有问题,先去百度</a>
      <!-- 使用.capture实现捕获触发事件的机制 -->
      <!-- 冒泡机制:从里向外触发 -->
      <!-- 捕获机制:从外向里面触发 -->
      <div class="inner" @click.capture = "div1Handler">
                      <input type="button" value="戳他" @click = "btnHandler">
      </div>
      <!-- 使用.self实现只有点击当前元素后才会触发事件处理函数 -->
      <!-- 使用.once只触发一次事件 -->
      <!-- .stop和.self的区别:  .self只会阻止自己身上冒泡行为的触发,并不会真正的阻止冒泡的行为 -->
      

vue指令之v-model和双向数据绑定

  • v-bind 只能实现数据的单向绑定,从m 自动绑定到 v,无法实现数据的双向绑定
  • 使用v-model指令可以实现表单元素和 model 中数据的双向数据绑定
  • 注意: v-model只能运用在表单元素中
  • input{redio, text, address, email...} select checkbox textarea
  • 使用方法:

简易计算器案例

  1. HTML代码
       <div id="app">
               <input type="text" v-model = "n1">
               <select v-model = "opt">
                   <option value="+">+</option>
                   <option value="-">-</option>
                   <option value="*">*</option>
                   <option value="/">/</option>
               </select>
               <input type="text" v-model = "n2">
               <input type="button" value="=" @click="calc">
               <input type="text" v-model = "result"> 
        </div>

.2 Vue实例代码

      var vm = new Vue({
               el:"#app",
               data:{
                   n1:0,
                   n2:0,
                   result:0,
                   opt:'+'
               },
               methods:{
                   calc(){  //计算器算数的方法
                   // 逻辑
                   // switch(this.opt){
                   //     case '+':
                   //       this.result = parseInt(this.n1) + parseInt(this.n2)
                   //       break;
                   //     case '-':
                   //       this.result = parseInt(this.n1) - parseInt(this.n2)
                   //       break;
                   //     case '*':
                   //       this.result = parseInt(this.n1) * parseInt(this.n2)
                   //       break;
                   //     case '/':
                   //       this.result = parseInt(this.n1) / parseInt(this.n2)
                   //       break;
                   //   }
                   
                   // 注意:这是投机取巧的方式,正式开发中尽量少用
                   var codestr = 'parseInt(this.n1)' + this.opt + 'parseInt(this.n2)'
                   this.result = eval(codestr);
                   }
               }
           })
       
在vue中使用样式
使用class样式
  1. 数组
        <!-- 第一种使用方式,直接传递一个数组,注意:这里的class需要使用v-bind做数据绑定 -->
      <h1 :class="['red','thin']">这是一个很大的h1,大到你无法想象</h1> 
  1. 数组中使用三元表达式
       <!-- 在数组中使用三元表达式 -->
       <h1 :class="['red','thin',flag ? 'active':'']">这是一个很大的h1,大到你无法想象</h1>
  1. 数组中嵌套对象
       <!-- 在数组中使用对象来代替三元表达式,提高代码的可读性 -->
       <h1 :class="['red','thin',{'active':flag}]">这是一个很大的h1,大到你无法想象</h1>
  1. 直接使用对象
        <!-- 在为class使用v-bind绑定对象的时候,对象的属性是类名,由于对象的属性可带引号,也可不带引号,所以这里没写引号 : 属性的值,是一个标识符 -->
       <h1 :class="{red:true,thin:true,active:false,italic:true}">这是一个很大的h1,大到你无法想象</h1>
       
使用内联样式
  1. 直接在元素上通过:style 的形式,书写样式对象
    <h1 :style="{color:'red','font-weight':200}">这是一个h1</h1>

  2. 将样式对象,定义到 data 中,并直接引用到 :style 中

    • 在data上定义样式
      data:{styleObj1:{color:'red','font-weight':200}}

    • 在元素上,通过属性绑定的形式,将样式对象应用到元素中
      <h1 :style="styleObj1">这是一个h1</h1>

  3. 在:style中通过数组,引用多个data上的样式对象

    • 在data上定义样式

      data:{
                        styleObj1:{color:'red','font-weight':200},
                        styleObj2:{'font-style':'italic'}
                    },
      
    • 在元素上,通过属性绑定的形式,将样式对象应用到元素中
      <h1 :style="[styleObj1,styleObj2]">这是一个h1</h1>

vue指令之v-for和key属性

  1. 迭代数组

    • 循环普通数组

      索引值:{{i}}----------每一项:{{item}}

      var vm = new Vue({
                  el:'#app',
                  data:{
                      list:[1,2,3,4,5,6]
                  },
                  methods:{}
              })
      
    • 循环对象数组

      ID:{{user.id}}-------Name:{{user.name}}-----索引:{{i}}

      data:{
                      list:[
                          {id:1,name:'zs1'},
                          {id:2,name:'zs2'},
                          {id:3,name:'zs3'},
                          {id:4,name:'zs4'},
                      ]
                  }
      
  2. 迭代对象中的属性

    • 循环对象

      值是:{{val}}----键是:{{key}}----索引是:{{i}}

       data: {
                      user: {
                          id: 1,
                          name: '托尼',
                          gender: '男'
                      }
                  }
      
  3. 迭代数字

     <!-- in后面我们放过  普通数组,对象数组,对象,还可以放数字 -->
               <!-- 注意:如果使用v-for迭代数字的话,前面的count值从1开始 -->
              <p v-for = "count in 10">这是第 {{count}} 次循环</p>

2.2.0+ 的版本里,当在组件中使用 v-for 时,key现在是必须的

当vue.js用v-for正在更新已渲染过的元素列表时,它默认用"就地复用"策略。如果数据项的数据被改变,vue将不是移动DOM元素来匹配数据项的顺序,而是简单复用此处每个元素,并且确保他在特定索引下显示已被渲染过的每个元素。

为了给vue一个提示,以使他能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一key属性。

  • 例子:
             <div>
                    <label for="">
                        ID:
                        <input type="text" v-model="id">
                    </label>
                    <label for="">
                        Name:
                        <input type="text" v-model="name">
                    </label>
                    <label for="">
                        <input type="button" value="添加" @click = "add">
                    </label>
                </div>
        
        
                <!-- 注意:v-for 循环的时候,key属性只能使用number获取string -->
                <!-- 注意:key在使用的时候,必须使用v-bind属性绑定的形式,指定key的值 -->
                <!-- 在组件中,使用v-for循环的时候,或者在一些特殊情况中,如果使用v-for有问题,必须在使用v-for的同时,指定唯一的字符串/数字 类型  :key值-->
                <p v-for="item in list" :key = "item.id">
                    <input type="checkbox" name="" id="">
                    {{item.id}}-------{{item.name}}
                </p>
        
        var vm = new Vue({
                    el: '#app',
                    data: {
                        id:'',
                        name:'',
                        list: [
                            { id: 1, name: '李斯' },
                            { id: 2, name: '嬴政' },
                            { id: 3, name: '赵高' },
                            { id: 4, name: '韩非' },
                            { id: 5, name: '荀子' }
                        ]
                    },
                    methods: {
                        add(){ //添加方法
                            this.list.unshift({id:this.id,name:this.name})
                        }
                    }
                })
        
    
    

vue指令之v-if 和v-show

一般来说,v-if有更高的切换消耗。而v-show有更高的初始渲染消耗。因此,如果需要频繁切换,v-show较好。如果在运行时条件不大可能改变 v-if 较好。

<!-- <input type="button" value="toggle" @click="toggle"> -->
        <input type="button" value="toggle" @click="flag = !flag">
        <!-- v-if的特点:每次都会重新删除或创建元素 -->
        <!-- v-show的特点:每次不会重新进行DOM的删除和创建操作,只是切换了元素的display:none样式 -->
        
        <!-- v-if有较高的切换消耗 -->
        <!-- v-show有较高的初始渲染消耗 -->

        <!-- 如果元素涉及到频繁的切换,最好不要使用v-if,而是推荐使用v-show -->
        <!-- 如果元素可能永远也不会被显示出来给用户看到,则推荐使用v-if -->
        <h3 v-if = "flag">这是用v-if控制的元素</h3>
        <h3 v-show = "flag">这是用v-show控制的元素</h3>

vue调试工具vue-devtools的安装步骤和使用

Vue.js devtools - 翻墙安装方式 - 推荐

另一种安装方式:打开谷歌浏览器设置—>扩展程序–》勾选开发者模式—》加载已解压的扩展程序—》选择“chrome扩展”文件夹,至此恭喜已经安装成功!!!

过滤器

概念:Vue.js 允许你自定义过滤器,可被用作一些常见的文本格式化。过滤器可以用在两个地方:mustache 插值和 v-bind 表达式。过滤器应该被添加在 JavaScript 表达式的尾部,由“管道”符指示;

私有过滤器
  1. HTML元素:

    <td>{{item.ctime | dataFormat('yyyy-mm-dd')}}</td>

  2. 私有 filters 定义方式:

    filters: { // 私有局部过滤器,只能在 当前 VM 对象所控制的 View 区域进行使用
    
        dataFormat(input, pattern = "") { // 在参数列表中 通过 pattern="" 来指定形参默认值,防止报错
    
          var dt = new Date(input);
    
          // 获取年月日
    
          var y = dt.getFullYear();
    
          var m = (dt.getMonth() + 1).toString().padStart(2, '0');
    
          var d = dt.getDate().toString().padStart(2, '0');
    
    
    
          // 如果 传递进来的字符串类型,转为小写之后,等于 yyyy-mm-dd,那么就返回 年-月-日
    
          // 否则,就返回  年-月-日 时:分:秒
    
          if (pattern.toLowerCase() === 'yyyy-mm-dd') {
    
            return `${y}-${m}-${d}`;
    
          } else {
    
            // 获取时分秒
    
            var hh = dt.getHours().toString().padStart(2, '0');
    
            var mm = dt.getMinutes().toString().padStart(2, '0');
    
            var ss = dt.getSeconds().toString().padStart(2, '0');
    
    
    
            return `${y}-${m}-${d} ${hh}:${mm}:${ss}`;
    
          }
    
        }
    
      }
    
    

使用ES6中的字符串新方法 String.prototype.padStart(maxLength, fillString=’’) 或 String.prototype.padEnd(maxLength, fillString=’’)来填充字符串;

全局过滤器
// 定义一个全局过滤器

Vue.filter('dataFormat', function (input, pattern = '') {

  var dt = new Date(input);

  // 获取年月日

  var y = dt.getFullYear();

  var m = (dt.getMonth() + 1).toString().padStart(2, '0');

  var d = dt.getDate().toString().padStart(2, '0');



  // 如果 传递进来的字符串类型,转为小写之后,等于 yyyy-mm-dd,那么就返回 年-月-日

  // 否则,就返回  年-月-日 时:分:秒

  if (pattern.toLowerCase() === 'yyyy-mm-dd') {

    return `${y}-${m}-${d}`;

  } else {

    // 获取时分秒

    var hh = dt.getHours().toString().padStart(2, '0');

    var mm = dt.getMinutes().toString().padStart(2, '0');

    var ss = dt.getSeconds().toString().padStart(2, '0');



    return `${y}-${m}-${d} ${hh}:${mm}:${ss}`;

  }

});

注意:当有局部和全局两个名称相同的过滤器时候,会以就近原则进行调用,即:局部过滤器优先于全局过滤器被调用!

键盘修饰符以及自定义键盘修饰符

1.x中自定义键盘修饰符【了解即可】

Vue.directive('on').keyCodes.f2 = 113;

2.x中自定义键盘修饰符

  1. 通过Vue.config.keyCodes.名称 = 按键值来自定义案件修饰符的别名:

    Vue.config.keyCodes.f2 = 113;

  2. 使用自定义的按键修饰符:

    <input type="text" v-model="name" @keyup.f2="add">

自定义指令

  1. 自定义全局和局部的 自定义指令:

     // 自定义全局指令 v-focus,为绑定的元素自动获取焦点:
    
     Vue.directive('focus', {
    
       inserted: function (el) { // inserted 表示被绑定元素插入父节点时调用
    
         el.focus();
    
       }
    
     });
    
    
    
     // 自定义局部指令 v-color 和 v-font-weight,为绑定的元素设置指定的字体颜色 和 字体粗细:
    
       directives: {
    
         color: { // 为元素设置指定的字体颜色
    
           bind(el, binding) {
    
             el.style.color = binding.value;
    
           }
    
         },
    
         'font-weight': function (el, binding2) { // 自定义指令的简写形式,等同于定义了 bind 和 update 两个钩子函数
    
           el.style.fontWeight = binding2.value;
    
         }
    
       }
    
  2. 自定义指令的使用方式:

    <input type="text" v-model="searchName" v-focus v-color="'red'" v-font-weight="900">

    Vue 1.x 中 自定义元素指令【已废弃,了解即可】

    Vue.elementDirective('red-color', {
       bind: function () {
         this.el.style.color = 'red';
       }
     });
    

    使用方式:

    <red-color>1232</red-color>

vue实例的生命周期

  • 什么是生命周期:从Vue实例创建、运行、到销毁期间,总是伴随着各种各样的事件,这些事件,统称为生命周期!
  • 生命周期钩子:就是生命周期事件的别名而已;
  • 生命周期钩子 = 生命周期函数 = 生命周期事件
  • 主要的生命周期函数分类:
  • 创建期间的生命周期函数:
  • beforeCreate:实例刚在内存中被创建出来,此时,还没有初始化好 data 和 methods 属性
  • created:实例已经在内存中创建OK,此时 data 和 methods 已经创建OK,此时还没有开始 编译模板
  • beforeMount:此时已经完成了模板的编译,但是还没有挂载到页面中
  • mounted:此时,已经将编译好的模板,挂载到了页面指定的容器中显示
  • 运行期间的生命周期函数:
  • beforeUpdate:状态更新之前执行此函数, 此时 data 中的状态值是最新的,但是界面上显示的 数据还是旧的,因为此时还没有开始重新渲染DOM节点
  • updated:实例更新完毕之后调用此函数,此时 data 中的状态值 和 界面上显示的数据,都已经完成了更新,界面已经被重新渲染好了!
  • 销毁期间的生命周期函数:
  • beforeDestroy:实例销毁之前调用。在这一步,实例仍然完全可用。
  • destroyed:Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。

vue-resource 实现 get, post, jsonp请求

除了 vue-resource 之外,还可以使用 axios 的第三方包实现实现数据的请求

  1. 常见的数据请求类型? get post jsonp

  2. JSONP的实现原理

  • 由于浏览器的安全性限制,不允许AJAX访问 协议不同、域名不同、端口号不同的 数据接口,浏览器认为这种访问不安全;

  • 可以通过动态创建script标签的形式,把script标签的src属性,指向数据接口的地址,因为script标签不存在跨域限制,这种数据获取方式,称作JSONP(注意:根据JSONP的实现原理,知晓,JSONP只支持Get请求);

  • 具体实现过程:

  • 先在客户端定义一个回调方法,预定义对数据的操作;

  • 再把这个回调方法的名称,通过URL传参的形式,提交到服务器的数据接口;

  • 服务器数据接口组织好要发送给客户端的数据,再拿着客户端传递过来的回调方法名称,拼接出一个调用这个方法的字符串,发送给客户端去解析执行;

  • 客户端拿到服务器返回的字符串之后,当作Script脚本去解析执行,这样就能够拿到JSONP的数据了;

  • 带大家通过 Node.js ,来手动实现一个JSONP的请求例子;

      const http = require('http');
      // 导入解析 URL 地址的核心模块
      const urlModule = require('url');
    
      const server = http.createServer();
      // 监听 服务器的 request 请求事件,处理每个请求
      server.on('request', (req, res) => {
        const url = req.url;
    
        // 解析客户端请求的URL地址
        var info = urlModule.parse(url, true);
    
        // 如果请求的 URL 地址是 /getjsonp ,则表示要获取JSONP类型的数据
        if (info.pathname === '/getjsonp') {
          // 获取客户端指定的回调函数的名称
          var cbName = info.query.callback;
          // 手动拼接要返回给客户端的数据对象
          var data = {
            name: 'zs',
            age: 22,
            gender: '男',
            hobby: ['吃饭', '睡觉', '运动']
          }
          // 拼接出一个方法的调用,在调用这个方法的时候,把要发送给客户端的数据,序列化为字符串,作为参数传递给这个调用的方法:
          var result = `${cbName}(${JSON.stringify(data)})`;
          // 将拼接好的方法的调用,返回给客户端去解析执行
          res.end(result);
        } else {
          res.end('404');
        }
      });
    
      server.listen(3000, () => {
        console.log('server running at http://127.0.0.1:3000');
      });
    
  1. vue-resource的配置步骤:
  • 直接在页面中,通过script标签,引入vue-resource 的脚本文件;
  • 注意:引用的先后顺序是:先引用 Vue 的脚本文件,再引用 vue-resource 的脚本文件;
  1. 发送get请求:
    getInfo() { // get 方式获取数据
      this.$http.get('http://127.0.0.1:8899/api/getlunbo').then(res => {
        console.log(res.body);
      })
    }
  1. 发送post请求:
    postInfo() {
      var url = 'http://127.0.0.1:8899/api/post';
      // post 方法接收三个参数:
      // 参数1: 要请求的URL地址
      // 参数2: 要发送的数据对象
      // 参数3: 指定post提交的编码类型为 application/x-www-form-urlencoded
      this.$http.post(url, { name: 'zs' }, { emulateJSON: true }).then(res => {
        console.log(res.body);
      });
    }
  1. 发送JSONP请求获取数据:
    jsonpInfo() { // JSONP形式从服务器获取数据
      var url = 'http://127.0.0.1:8899/api/jsonp';
      this.$http.jsonp(url).then(res => {
        console.log(res.body);
      });
    }
配置本地数据库和数据接口API
  1. 先解压安装 PHPStudy;
  2. 解压安装 Navicat 这个数据库可视化工具,并激活;
  3. 打开 Navicat 工具,新建空白数据库,名为 dtcmsdb4;
  4. 双击新建的数据库,连接上这个空白数据库,在新建的数据库上右键 -> 运行SQL文件,选择并执行 dtcmsdb4.sql 这个数据库脚本文件;如果执行不报错,则数据库导入完成;
  5. 进入文件夹 vuecms3_nodejsapi 内部,执行 npm i 安装所有的依赖项;
  6. 先确保本机安装了 nodemon, 没有安装,则运行 npm i nodemon -g 进行全局安装,安装完毕后,进入到 vuecms3_nodejsapi目录 -> src目录 -> 双击运行 start.bat
  7. 如果API启动失败,请检查 PHPStudy 是否正常开启,同时,检查 app.js 中第 14行 中数据库连接配置字符串是否正确;PHPStudy 中默认的 用户名是root,默认的密码也是root

Vue中的动画

为什么要有动画:动画能够提高用户的体验,帮助用户更好的理解页面中的功能;

使用过渡类名
  1. HTML结构:
    <div id="app">
        <input type="button" value="动起来" @click="myAnimate">
        <!-- 使用 transition 将需要过渡的元素包裹起来 -->
        <transition name="fade">
          <div v-show="isshow">动画哦</div>
        </transition>
      </div>
  1. VM 实例:
    // 创建 Vue 实例,得到 ViewModel
    var vm = new Vue({
      el: '#app',
      data: {
        isshow: false
      },
      methods: {
        myAnimate() {
          this.isshow = !this.isshow;
        }
      }
    });
    
  1. 定义两组类样式:
    /* 定义进入和离开时候的过渡状态 */
        .fade-enter-active,
        .fade-leave-active {
          transition: all 0.2s ease;
          position: absolute;
        }
    
        /* 定义进入过渡的开始状态 和 离开过渡的结束状态 */
        .fade-enter,
        .fade-leave-to {
          opacity: 0;
          transform: translateX(100px);
        }
    
使用第三方 CSS 动画库
  1. 导入动画类库:

    <link rel="stylesheet" type="text/css" href="./lib/animate.css">

  2. 定义transition 及属性:

    <transition
    	enter-active-class="fadeInRight"
        leave-active-class="fadeOutRight"
        :duration="{ enter: 500, leave: 800 }">
      	<div class="animated" v-show="isshow">动画哦</div>
    </transition>
    

使用动画钩子函数

  1. 定义transition组件以及三个钩子函数:
    <div id="app">
        <input type="button" value="切换动画" @click="isshow = !isshow">
        <transition
        @before-enter="beforeEnter"
        @enter="enter"
        @after-enter="afterEnter">
          <div v-if="isshow" class="show">OK</div>
        </transition>
      </div>
    
  1. 定义三个 methods 钩子方法:
    methods: {
            beforeEnter(el) { // 动画进入之前的回调
              el.style.transform = 'translateX(500px)';
            },
            enter(el, done) { // 动画进入完成时候的回调
              el.offsetWidth;
              el.style.transform = 'translateX(0px)';
              done();
            },
            afterEnter(el) { // 动画进入完成之后的回调
              this.isshow = !this.isshow;
            }
          }
    
  1. 定义动画过渡时长和样式:
    .show{
          transition: all 0.4s ease;
        }
    

v-for 的列表过渡

  1. 定义过渡样式:
    <style>
        .list-enter,
        .list-leave-to {
          opacity: 0;
          transform: translateY(10px);
        }
    
        .list-enter-active,
        .list-leave-active {
          transition: all 0.3s ease;
        }
    </style>
  1. 定义DOM结构,其中,需要使用transition-group 组件把v-for循环的列表包裹起来:
      <div id="app">
        <input type="text" v-model="txt" @keyup.enter="add">
    
        <transition-group tag="ul" name="list">
          <li v-for="(item, i) in list" :key="i">{{item}}</li>
        </transition-group>
      </div>
  1. 定义 VM中的结构:
        // 创建 Vue 实例,得到 ViewModel
        var vm = new Vue({
          el: '#app',
          data: {
            txt: '',
            list: [1, 2, 3, 4]
          },
          methods: {
            add() {
              this.list.push(this.txt);
              this.txt = '';
            }
          }
        });
    

列表的排序过渡

<transition-group> 组件还有一个特殊之处。不仅可以进入和离开动画,还可以改变定位。要使用这个新功能只需了解新增的v-move 特性,它会在元素的改变定位的过程中应用。

  • v-movev-leave-active结合使用,能够让列表的过渡更加平缓柔和:
    .v-move{
      transition: all 0.8s ease;
    }
    .v-leave-active{
      position: absolute;
    }

vue组件

定义Vue组件

什么是组件: 组件的出现,就是为了拆分Vue实例的代码量的,能够让我们以不同的组件,来划分不同的功能模块,将来我们需要什么样的功能,就可以去调用对应的组件即可;
组件化和模块化的不同:

  • 模块化: 是从代码逻辑的角度进行划分的;方便代码分层开发,保证每个功能模块的职能单一;
  • 组件化: 是从UI界面的角度进行划分的;前端的组件化,方便UI组件的重用;

全局组件定义的三种方式

  1. 使用 Vue.extend配合Vue.component 方法:
    var login = Vue.extend({
          template: '<h1>登录</h1>'
        });
        Vue.component('login', login);
    
  1. 直接使用 Vue.component 方法:
    Vue.component('register', {
          template: '<h1>注册</h1>'
        });
  1. 将模板字符串,定义到script标签种:
    <script id="tmpl" type="x-template">
          <div><a href="#">登录</a> | <a href="#">注册</a></div>
        </script>
    

同时,需要使用 Vue.component 来定义组件:

    Vue.component('account', {
          template: '#tmpl'
        });

注意: 组件中的DOM结构,有且只能有唯一的根元素(Root Element)来进行包裹!

组件中展示数据和响应事件

  1. 在组件中,data需要被定义为一个方法,例如:
    Vue.component('account', {
          template: '#tmpl',
          data() {
            return {
              msg: '大家好!'
            }
          },
          methods:{
            login(){
              alert('点击了登录按钮');
            }
          }
        });
  1. 在子组件中,如果将模板字符串,定义到了script标签中,那么,要访问子组件身上的data属性中的值,需要使用this来访问;

** 【重点】**为什么组件中的data属性必须定义为一个方法并返回一个对象

  1. 通过计数器案例演示
  2. 不能返回一个外部定义好的一个对象,因为对象是引入进来的,所以如果多次使用此组件,每次指向的都是同一个对象,会出现一个组件中的数据改变,其他地方引入此组件的数据也会改变,所以return{}必须要在里面写。
使用components属性定义局部子组件
  1. 组件实例定义方式:
    <script>
        // 创建 Vue 实例,得到 ViewModel
        var vm = new Vue({
          el: '#app',
          data: {},
          methods: {},
          components: { // 定义子组件
            account: { // account 组件
              template: '<div><h1>这是Account组件{{name}}</h1><login></login></div>', // 在这里使用定义的子组件
              components: { // 定义子组件的子组件
                login: { // login 组件
                  template: "<h3>这是登录组件</h3>"
                }
              }
            }
          }
        });
      </script>
    
  1. 引用组件:
    <div id="app">
        <account></account>
      </div>
    

使用flag标识符结合v-ifv-else切换组件

  1. 页面结构:
    <div id="app">
        <input type="button" value="toggle" @click="flag=!flag">
        <my-com1 v-if="flag"></my-com1>
        <my-com2 v-else="flag"></my-com2>
      </div>
    
  1. Vue实例定义:
    <script>
        Vue.component('myCom1', {
          template: '<h3>奔波霸</h3>'
        })
    
        Vue.component('myCom2', {
          template: '<h3>霸波奔</h3>'
        })
    
        // 创建 Vue 实例,得到 ViewModel
        var vm = new Vue({
          el: '#app',
          data: {
            flag: true
          },
          methods: {}
        });
      </script>
    

使用:is属性来切换不同的子组件,并添加切换动画

  1. 组件实例定义方式:
      // 登录组件
        const login = Vue.extend({
          template: `<div>
            <h3>登录组件</h3>
          </div>`
        });
        Vue.component('login', login);
    
        // 注册组件
        const register = Vue.extend({
          template: `<div>
            <h3>注册组件</h3>
          </div>`
        });
        Vue.component('register', register);
    
        // 创建 Vue 实例,得到 ViewModel
        var vm = new Vue({
          el: '#app',
          data: { comName: 'login' },
          methods: {}
        });
    
  1. 使用component标签,来引用组件,并通过:is属性来指定要加载的组件:
      <div id="app">
        <a href="#" @click.prevent="comName='login'">登录</a>
        <a href="#" @click.prevent="comName='register'">注册</a>
        <hr>
        <transition mode="out-in">
          <component :is="comName"></component>
        </transition>
      </div>
    
  1. 添加切换样式:
      <style>
        .v-enter,
        .v-leave-to {
          opacity: 0;
          transform: translateX(30px);
        }
    
        .v-enter-active,
        .v-leave-active {
          position: absolute;
          transition: all 0.3s ease;
        }
    
        h3{
          margin: 0;
        }
      </style>
    

父组件向子组件传值

  1. 组件实例定义方式,注意:一定要使用props属性来定义父组件传递过来的数据
    <script>
        // 创建 Vue 实例,得到 ViewModel
        var vm = new Vue({
          el: '#app',
          data: {
            msg: '这是父组件中的消息'
          },
          components: {
            son: {
              template: '<h1>这是子组件 --- {{finfo}}</h1>',
              props: ['finfo']
            }
          }
        });
      </script>
  1. 使用v-bind或简化指令,将数据传递到子组件中:
    <div id="app">
        <son :finfo="msg"></son>
      </div>

子组件向父组件传值

  1. 原理:父组件将方法的引用,传递到子组件内部,子组件在内部调用父组件传递过来的方法,同时把要发送给父组件的数据,在调用方法的时候当作参数传递进去;
  2. 父组件将方法的引用传递给子组件,其中,getMsg是父组件中methods中定义的方法名称,func是子组件调用传递过来方法时候的方法名称
    <son @func="getMsg"></son>
  1. 子组件内部通过this.$emit('方法名', 要传递的数据)方式,来调用父组件中的方法,同时把数据传递给父组件使用
      <div id="app">
        <!-- 引用父组件 -->
        <son @func="getMsg"></son>
    
        <!-- 组件模板定义 -->
        <script type="x-template" id="son">
          <div>
            <input type="button" value="向父组件传值" @click="sendMsg" />
          </div>
        </script>
      </div>
    
      <script>
        // 子组件的定义方式
        Vue.component('son', {
          template: '#son', // 组件模板Id
          methods: {
            sendMsg() { // 按钮的点击事件
              this.$emit('func', 'OK'); // 调用父组件传递过来的方法,同时把数据传递出去
            }
          }
        });
    
        // 创建 Vue 实例,得到 ViewModel
        var vm = new Vue({
          el: '#app',
          data: {},
          methods: {
            getMsg(val){ // 子组件中,通过 this.$emit() 实际调用的方法,在此进行定义
              alert(val);
            }
          }
        });
      </script>
    

评论列表案例

目标:主要练习父子组件之间传值

使用 this.$refs来获取元素和组件

  <div id="app">
    <div>
      <input type="button" value="获取元素内容" @click="getElement" />
      <!-- 使用 ref 获取元素 -->
      <h1 ref="myh1">这是一个大大的H1</h1>

      <hr>
      <!-- 使用 ref 获取子组件 -->
      <my-com ref="mycom"></my-com>
    </div>
  </div>

  <script>
    Vue.component('my-com', {
      template: '<h5>这是一个子组件</h5>',
      data() {
        return {
          name: '子组件'
        }
      }
    });

    // 创建 Vue 实例,得到 ViewModel
    var vm = new Vue({
      el: '#app',
      data: {},
      methods: {
        getElement() {
          // 通过 this.$refs 来获取元素
          console.log(this.$refs.myh1.innerText);
          // 通过 this.$refs 来获取组件
          console.log(this.$refs.mycom.name);
        }
      }
    });
  </script>

什么是路由

  1. 对于普通的网站,所有的超链接都是URL地址,所有的URL地址都对应服务器上对应的资源;
  2. 对于单页面应用程序来说,主要通过URL中的hash(#号)来实现不同页面之间的切换,同时,hash有一个特点:HTTP请求中不会包含hash相关的内容;所以,单页面程序中的页面跳转主要用hash实现;
  3. 在单页面应用程序中,这种通过hash改变来切换页面的方式,称作前端路由(区别于后端路由);

在 vue 中使用 vue-router

  1. 导入vue-router组件类库:
    <!-- 1. 导入 vue-router 组件类库 -->
      <script src="./lib/vue-router-2.7.0.js"></script>
  1. 使用router-link 组件来导航
    <!-- 2. 使用 router-link 组件来导航 -->
    <router-link to="/login">登录</router-link>
    <router-link to="/register">注册</router-link>
  1. 使用 router-view 组件来显示匹配到的组件
    <!-- 3. 使用 router-view 组件来显示匹配到的组件 -->
    <router-view></router-view>
  1. 创建使用Vue.extend创建组件
        // 4.1 使用 Vue.extend 来创建登录组件
        var login = Vue.extend({
          template: '<h1>登录组件</h1>'
        });
    
        // 4.2 使用 Vue.extend 来创建注册组件
        var register = Vue.extend({
          template: '<h1>注册组件</h1>'
        });
  1. 创建一个路由 router 实例,通过 routers 属性来定义路由匹配规则
    // 5. 创建一个路由 router 实例,通过 routers 属性来定义路由匹配规则
        var router = new VueRouter({
          routes: [
            { path: '/login', component: login },
            { path: '/register', component: register }
          ]
        });
  1. 使用 router 属性来使用路由规则
    // 6. 创建 Vue 实例,得到 ViewModel
        var vm = new Vue({
          el: '#app',
          router: router // 使用 router 属性来使用路由规则
        });

设置路由高亮

设置路由切换动效

在路由规则中定义参数

  1. 在规则中定义参数:

    { path: '/register/:id', component: register }

  2. 通过 this.$route.params来获取路由中的参数:

    var register = Vue.extend({
          template: '<h1>注册组件 --- {{this.$route.params.id}}</h1>'
        });

使用children 属性实现路由嵌套

  <div id="app">
    <router-link to="/account">Account</router-link>

    <router-view></router-view>
  </div>

  <script>
    // 父路由中的组件
    const account = Vue.extend({
      template: `<div>
        这是account组件
        <router-link to="/account/login">login</router-link> | 
        <router-link to="/account/register">register</router-link>
        <router-view></router-view>
      </div>`
    });

    // 子路由中的 login 组件
    const login = Vue.extend({
      template: '<div>登录组件</div>'
    });

    // 子路由中的 register 组件
    const register = Vue.extend({
      template: '<div>注册组件</div>'
    });

    // 路由实例
    var router = new VueRouter({
      routes: [
        { path: '/', redirect: '/account/login' }, // 使用 redirect 实现路由重定向
        {
          path: '/account',
          component: account,
          children: [ // 通过 children 数组属性,来实现路由的嵌套
            { path: 'login', component: login }, // 注意,子路由的开头位置,不要加 / 路径符
            { path: 'register', component: register }
          ]
        }
      ]
    });

    // 创建 Vue 实例,得到 ViewModel
    var vm = new Vue({
      el: '#app',
      data: {},
      methods: {},
      components: {
        account
      },
      router: router
    });
  </script>

命名视图实现经典布局

  1. 标签代码结构:
    <div id="app">
        <router-view></router-view>
        <div class="content">
          <router-view name="a"></router-view>
          <router-view name="b"></router-view>
        </div>
      </div>
  1. JS代码:
    <script>
        var header = Vue.component('header', {
          template: '<div class="header">header</div>'
        });
    
        var sidebar = Vue.component('sidebar', {
          template: '<div class="sidebar">sidebar</div>'
        });
    
        var mainbox = Vue.component('mainbox', {
          template: '<div class="mainbox">mainbox</div>'
        });
    
        // 创建路由对象
        var router = new VueRouter({
          routes: [
            {
              path: '/', components: {
                default: header,
                a: sidebar,
                b: mainbox
              }
            }
          ]
        });
    
        // 创建 Vue 实例,得到 ViewModel
        var vm = new Vue({
          el: '#app',
          data: {},
          methods: {},
          router
        });
      </script>
    
  1. CSS 样式:
      <style>
        .header {
          border: 1px solid red;
        }
    
        .content{
          display: flex;
        }
        .sidebar {
          flex: 2;
          border: 1px solid green;
          height: 500px;
        }
        .mainbox{
          flex: 8;
          border: 1px solid blue;
          height: 500px;
        }
      </style>
    

watch属性的使用

考虑一个问题:想要实现 名 和 姓 两个文本框的内容改变,则全名的文本框中的值也跟着改变;(用以前的知识如何实现???)

  1. 监听data中属性的改变:
    <div id="app">
        <input type="text" v-model="firstName"> +
        <input type="text" v-model="lastName"> =
        <span>{{fullName}}</span>
      </div>
    
      <script>
        // 创建 Vue 实例,得到 ViewModel
        var vm = new Vue({
          el: '#app',
          data: {
            firstName: 'jack',
            lastName: 'chen',
            fullName: 'jack - chen'
          },
          methods: {},
          watch: {
            'firstName': function (newVal, oldVal) { // 第一个参数是新数据,第二个参数是旧数据
              this.fullName = newVal + ' - ' + this.lastName;
            },
            'lastName': function (newVal, oldVal) {
              this.fullName = this.firstName + ' - ' + newVal;
            }
          }
        });
      </script>
    
  1. 监听路由对象的改变:
    <div id="app">
        <router-link to="/login">登录</router-link>
        <router-link to="/register">注册</router-link>
    
        <router-view></router-view>
      </div>
    
      <script>
        var login = Vue.extend({
          template: '<h1>登录组件</h1>'
        });
    
        var register = Vue.extend({
          template: '<h1>注册组件</h1>'
        });
    
        var router = new VueRouter({
          routes: [
            { path: "/login", component: login },
            { path: "/register", component: register }
          ]
        });
    
        // 创建 Vue 实例,得到 ViewModel
        var vm = new Vue({
          el: '#app',
          data: {},
          methods: {},
          router: router,
          watch: {
            '$route': function (newVal, oldVal) {
              if (newVal.path === '/login') {
                console.log('这是登录组件');
              }
            }
          }
        });
      </script>
    

computed计算属性的使用

  1. 默认只有getter的计算属性:
    <div id="app">
        <input type="text" v-model="firstName"> +
        <input type="text" v-model="lastName"> =
        <span>{{fullName}}</span>
      </div>
    
      <script>
        // 创建 Vue 实例,得到 ViewModel
        var vm = new Vue({
          el: '#app',
          data: {
            firstName: 'jack',
            lastName: 'chen'
          },
          methods: {},
          computed: { // 计算属性; 特点:当计算属性中的任何一个 data 属性改变之后,都会重新触发 本计算属性 的重新计算,从而更新 fullName 的值
            fullName() {
              return this.firstName + ' - ' + this.lastName;
            }
          }
        });
      </script>
    
  1. 定义有getter和setter的计算属性:
    <div id="app">
        <input type="text" v-model="firstName">
        <input type="text" v-model="lastName">
        <!-- 点击按钮重新为 计算属性 fullName 赋值 -->
        <input type="button" value="修改fullName" @click="changeName">
    
        <span>{{fullName}}</span>
      </div>
    
      <script>
        // 创建 Vue 实例,得到 ViewModel
        var vm = new Vue({
          el: '#app',
          data: {
            firstName: 'jack',
            lastName: 'chen'
          },
          methods: {
            changeName() {
              this.fullName = 'TOM - chen2';
            }
          },
          computed: {
            fullName: {
              get: function () {
                return this.firstName + ' - ' + this.lastName;
              },
              set: function (newVal) {
                var parts = newVal.split(' - ');
                this.firstName = parts[0];
                this.lastName = parts[1];
              }
            }
          }
        });
      </script>
    
watch、computed和methods之间的对比
  1. computed属性的结果会被缓存,除非依赖的响应式属性变化才会重新计算。主要当作属性来使用;
  2. methods方法表示一个具体的操作,主要书写业务逻辑;
  3. watch一个对象,键是需要观察的表达式,值是对应回调函数。主要用来监听某些特定数据的变化,从而进行某些具体的业务逻辑操作;可以看作是computed和methods的结合体;

nrm的安装使用

作用:提供了一些最常用的NPM包镜像地址,能够让我们快速的切换安装包时候的服务器地址;
什么是镜像:原来包刚一开始是只存在于国外的NPM服务器,但是由于网络原因,经常访问不到,这时候,我们可以在国内,创建一个和官网完全一样的NPM服务器,只不过,数据都是从人家那里拿过来的,除此之外,使用方式完全一样;

  1. 运行npm i nrm -g全局安装nrm包;
  2. 使用nrm ls查看当前所有可用的镜像源地址以及当前所使用的镜像源地址;
  3. 使用nrm use npmnrm use taobao切换不同的镜像源地址;

注意:nrm只是单纯的提供了几个常用的下载包的URL地址,并能够让我们在这几个地址之间,很方便地进行切换,但是,我们每次装包的时候,使用的装包工具,都是npm

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值