Vue study 入门前端万字笔记

Vue study 入门前端万字笔记

什么是vue js

  1. vue.js 是前端的主流框架之一,和Angular.js React.js ,前端的三大框架
  2. Vue.js是一套构建用户界面的框架,只关注视屏层,
  3. 主要负责 M(数据)V(视图)C(业务逻辑) 中的V这一层,主要工作就是和界面打交道
  4. 让开发人员只需要关注业务逻辑,不再化很多的精力关心DOM操作,提高开发效率
  5. 官网:https://cn.vuejs.org/v2/guide/transitions.html

框架和库的区别

  1. 框架,是一套完整的解决方案,对项目的倾入性较大,项目如果需要更换框架,则需要重新j架构整个项目
  2. 库(插件):提供某个小的功能,对项目的倾入性较少,如果某个项目无法完成某些需求,可以很容易切换

后端MVC和前端MVVM

  1. 后端MVC
  2. 前端MVVM

Vue 实例

  1. helloVUe

    <body>
        <div id="app">
            <p>{{massage}}</p>
        </div>
        <script src='../js/vue.js'></script>
        <script>
            var vm = new Vue({
                el:'#app',
                data:{
                    massage:"hello 小毅"
                }
            })
        </script>
    </body>
    
  2. M 层:数据操作层

    data:{
        massage:"hello 小毅"
    }
    
  3. V 层:视图展示{{massage}}

    <div id="app">
       <p>{{massage}}</p>
    </div
    
  4. VM:数据处理:

    var vm = new Vue({
       el:'#app',
       data:{
           massage:"hello 小毅",
           text:"我是小毅",
           html:'<h4>这是一个标题</h4>'
       }
    })
    
  5. 在差值表达式是,数据没事下载完之前出现{{massage}}的闪烁问题

  6. v-cloak,可以解决差值闪烁的问题,在数据没有加载完之前,p 加载之前:display:none,加载完之后display:block

    <p v-cloak>--{{massage}}--</p> 	//输出:--hello 小毅--
    
  7. v-text,可以将msssage,绑定在一个标签中展示,默认没有闪烁问题,会覆盖掉以前的内容

    <p v-text='text'>who are you</p> 	//输出:我是小毅
    
  8. v-html,可以将内容解析成HTML格式

    <p v-html='html'>这是一个html</p> 	//输出:这是一个标题
    
  9. 总结

闪烁问题 是否替换掉以前的内容 是否转义输出
差值表达式 有(用 v-cloak解决) 否,只是在占位的地方显示 否,原文输出
v-text 是,v-text会覆盖以前的内容 否,原文输出
v-html 是,v-html会覆盖以前的内容 是,如果有标签

v-bind

  1. v-bind属性告诉浏览器,这个一个变量,

    <input type="button" v-bind:value="title"> 
    <input type="button" :value="'hello'+title">//简写模式,既然是变量,就可以进行变量的增加
    

v-on

  1. v-on 邦定事件,在data,同级的methods下声明函数

    <input type="button" v-bind:value="title" v-on:click='show'>
    <input type="button" v-bind:value="title" v-on:mouseover='show'>
    <input type="button" :value="'hello'+title" v-on:click = 'show()'>
    
    methods:{
        show:function(){
            alert("hello 小毅")
        }
    }
    
  2. 做一个实例,把字符串最前的一个字,放到字符串尾部,不停循环,

    //html
    <div id="app">
        <input type="button" value="runing" v-on:click="run">
        <input type="button" value="stop" v-on:click="stop">
        <!-- <input type="button" value="stop" > -->
        <h4>{{message}}</h4>
    </div>  
    
    <script>
            var vm = new Vue({
                el: "#app",
                data: {
                    message: "家强牛逼,家强牛!",
                    intervalId:null
                },
                methods: {
                    run() {
                        if(this.intervalId != null){return;}
    						//箭头函数,这样解决普通函数this指向问题
                        this.intervalId = setInterval(()=>{   
                            var start = this.message.substring(0, 1)//截取第一个字符
                            var end = this.message.substring(1)//截取第一个字符到最后的一个字符
                            this.message = end + start  //把最后的字符和第一字符相加
                        } ,300)
                    },
                    
                    stop(){
                        clearInterval(this.intervalId)//停止定时函数
                        this.intervalId=null
                    }
                }
            })
        </script>
    

v-model 双向数据绑定

  1. v-bing 只能实现数据的单向绑定

  2. v-model 可以实现数据的双向绑定,实现的用户的交互

    <div id="app">
        <p>{{message}}</p>
        <input type="text" v-model:value="message">
    </div>
    
  3. v-model 只能运用在表单元素中

    input(radio,text,address,emaill)
    select
    checkbox
    textarea
    
  4. 例子

    <div id="app">
        <input type="text" v-model='number1'> //数字1
        <select v-model="option">   //选择操作符
            <option value="+">+</option>
            <option value="-">-</option>
            <option value="*">*</option>
            <option value="/">/</option>
        </select>
        <input type="text" v-model="number2"> //数字1
        <input type="button" value="=" @click="conputer"> //计算
        <input type="text" v-model="result">  //显示结果
        <p>number1:{{number1}}</p>
        <p>number2:{{number2}}</p>
        <p>结果:{{result}}</p>
    </div>
    
    // javascript 
    <script>
            var vm = new Vue({
                el: "#app",
                data: {
                    number1: 0,
                    number2: 0,
                    result: 0,
                    option: '+',
                },
                methods: {
                    conputer() {
                        switch (this.option) {
                            case '+':
                                this.result = parseInt(this.number1) + parseInt(this.number2)
                                break;
                            case '-':
                                this.result = parseInt(this.number1) - parseInt(this.number2)
                                break;
                            case '*':
                                this.result = parseInt(this.number1) * parseInt(this.number2)
                                break;
                            case '/':
                                this.result = parseInt(this.number1) / parseInt(this.number2)
                                break;
                        }
                    }
                }
    
            })
        </script>
    
  5. 对以上计算函数进行改进,利用 eval()方法对字符串解析执行

    conputer() {
      var codestr = 'parseInt(this.number1) ' + this.option + 'parseInt(this.number2)'
       this.result = eval(codestr)
    }
    
  6. 在对以上例子进行改进,要求如下:

    1、在鼠标进入输入框,清空默认数字 0,
    2、当两个输入框改变或者操作符改变,自动输出结果
    

v-on的缩写和事件修饰符

  1. 事件修饰符

    1、.stop	阻止冒泡
    2、.prevent	阻止默认事件
    3、.capture	添加2020年7月9日14:56:13侦听器时使用事件捕获模式
    4、.selt 	只当事件在该元素(比如不是子元素)触发时触发回调
    5、.once		事件只触发一次
    
  2. 先定义几个函数,和简单的html代码

    methods:{
                div1Handler(){
                    console.log("触发了 inner div 的点击事件")
                },
                btnHandler(){
                    console.log("触发了 btn 按钮 的点击事件")
                },
                linkClick(){
                    console.log('触发了连接的点击事件')
                }
            }
    
  3. 事件的冒泡机制,点击button,会触发button 的事件,再冒泡触发父级元素的div 的事件

    <div id="app">
        <div class="inner" @click="div1Handler">
            <input type="button" value="按钮" @click="btnHandler">
        </div>
    </div>
    
  4. 使用.stop阻止冒泡,只触发 button 的事件,div的事件没有触发

    <div class="inner" @click="div1Handler">
        <input type="button" value="按钮" @click.stop="btnHandler">
    </div>
    
  5. 使用.self 实现只有点击当前元素(div)的时候,才会触发事件的处理函数(通过冒泡和捕获不会再触发事件),点击button 是不会触发的事件的 div 的事件的。

    <div class="inner" @click.self="div1Handler">
        <input type="button" value="按钮" @click.stop="btnHandler">
    </div>
    
  6. 使用.prevent阻止默认事件,只触发绑定的事件,阻止了跳转,from表单也可以使用这个方法

    <a href="http://www.baidu.com" @click.prevent='linkClick'>百度一下</a>
    
  7. 使用.capture捕获机制,点击按钮时,先触发 div的事件,在触发button 的事件,由外而内

    <div class="inner" @click.capture="div1Handler">
        <input type="button" value="按钮" @click.stop="btnHandler">
    </div>
    
  8. 使用.once,只触发一次事件

    <a href="http://www.baidu.com" @click.prevent.once='linkClick'>百度一下</a>
    

通过属性绑定设置样式class

  1. 定义几个样式

    <style>
        .color {
            color: brown;
        }
        .thin{
            font-weight: 200;
        }
        .italic{
            font-style: italic;
        }
        .active{
            letter-spacing: 0.5em;
        }
    </style>
    
  2. 数组,利用v-bind数据绑定,不需要在data{}里面声明class Name

    <h2 v-bind:class="['color','active','thin']">这是一个标题</h2>
    <h2 :class="['color','active','thin']">这是一个标题</h2>
    
  3. 数组中使用三元表达式

    <h2 :class="[1<2?'color':'']">这是一个标题</h2>
    
  4. 数组中嵌套对象

    <h2 :class="['color',{'active':true}]">这是一个标题</h2>
    <h2 :class="['color',{'active':flase}]">这是一个标题</h2>
    
  5. 直接使用对象

    <h2 v-bind:class="{color:false,thin:true,italic:'true',active:true}">这是一个标题</h2>
    <h2 v-bind:class="calssObj">这是一个标题</h2>
    
    data: {//在data声明一个对象
      calssObj:{color:false,thin:true,italic:'true',active:true}
    }
    

绑定style行内样式

  1. 直接在元素上通过 :style 的形式,书写样式对象

    <h2 v-bind:style="{'font-style':'italic','font-weight':200}">行内样式style</h2>
    <h2 :style="{'font-style':'italic','font-weight':200}">行内样式style</h2>
    
  2. 将样式对象,定义到data中,并直接引用:style中

    <h2 :style='H2Style'>行内样式style</h2>
    
    data: {
        H2Style: {
            color: 'pink',
            'font-style': 'italic',
        },
        H2Style2: {
            'font-weight': 200
        },
    }
    
  3. 在:style 中,引用多个data上的样式

    <h2 :style="[H2Style,H2Style2]">行内样式style</h2>
    

v-for

  1. 迭代数字

    <p v-for = "(i,index,b) in 10"> {{index}}这是第{{i}}次循环</p>
    
  2. 循环普通数组

    <p v-for="(item,index) in list">{{index}}号索引:{{item}}</p>
    
    data: {
    	list: [1, 2, 3, 4, 5]
    }
    
  3. 循环对象数组

    <p v-for="(user,index) in list">{{index}}---{{user.id}}----{{user.name}}</p>
    
    data: {
       list:[
           {id:1,name:'小毅'},
           {id:2,name:'小花'},
           {id:3,name:'小狗'},
           {id:4,name:'小猫'}
       ]
    }
    
  4. 循环对象

    <p v-for="(value,key) in user">{{key}}:{{value}}</p>
    
    data: {
       user:{
           id:1,
           name:"小毅",
           gender:'男',
           age:18
       }  
    }
    
  5. 循环嵌套对象

    
    data: {
       users:{
           小毅:{
               height:170,
               love:'running'
           },
           小猫:{
               height:20,
               love:'sleep'
           },
           小狗:{
               height:40,
               love:"抓老鼠"
           }
       }  
    }
    
  6. 案列,如果没有指定 :key ,那么选定的框只是选中第 N个,意思就是说,当添加的一个对象的还是,还是选中第N个,那么如果,在对象数组前面添加的时候,就会出现问题。

    <div id="app">
        <div>
            <label>Id<input type="text" v-model="id"></label>
            <label>Name<input type="text" v-model="name"></label>
            <input type="button" value="添加" @click='add'>
        </div>
    		//如果没有:key 在数组前面添加元素的是好会有bug
      		 <p v-for="item in list"  :key="item.id">
                {{item.id}}---{{item.name}}
                <input type="checkbox">
            </p>
        </p>
    </div>
    
    data: {
        id: '',
        name: '',
        list: [
            {id: 1, name: "小毅"},
            {id: 2, name: "小花"},
            {id: 3, name: "小猫"},
            {id: 4, name: "小狗"}
        ]
    },
    methods: {
        add() {
            // this.list.push({id:this.id,name:this.name})
            this.list.unshift({id:this.id,name:this.name})
        }
    }
    

v-if 和 v-show

  1. 如果为ture: v-show 和v-if 都是display:block

    <div id="app">
        <p v-show="true">这是v-show</p>
        <p v-if = "true">这是v-if</p>
    </div>
    
  2. 如果为false: v-show 状态是:display:none ,v-if 是直接删掉元素

    <div id="app">
        <p v-show="false">这是v-show</p>
        <p v-if = "false">这是v-if</p>
    </div>
    
  3. v-show 的特点:不会每次重新进行DOM的元素删除和创建,知识切换了元素的display:none样式,有较高的初始渲染消耗

  4. v-if的特点:每次直接删除和创建DOM元素,有较高的切换消耗

定义全局过滤器

  1. 定义一个全局过滤器

    Vue.filter('dateFormat',function(dateStr,pattern){
        //根据给定的字符串,得到特定的时间
        var dt = new Date(dateStr)
        //yyyy-mm-dd
        var y = dt.getFullYear();
        var m = dt.getMonth() + 1;
        var d = dt.getDate();
    
        if(pattern.toLowerCase() === 'yyyy-mm-dd'){
            return `${y}-${m}-${d}`
        }else{
            var hh = dt.getHours()
            var mm = dt.getMinutes()
            var ss = dt.getSeconds()
    
            return `${y}-${m}-${d} ${hh}:${mm}:${ss}` 
        }
    })
    Vue.filter('dateFormat',function(dateStr,pattern){
        //根据给定的字符串,得到特定的时间
        var dt = new Date(dateStr)
        //yyyy-mm-dd
        var y = dt.getFullYear();
        var m = dt.getMonth() + 1;
        var d = dt.getDate();
    
        if(pattern.toLowerCase() === 'yyyy-mm-dd'){
            return `${y}-${m}-${d}`
        }else{
            var hh = dt.getHours()
            var mm = dt.getMinutes()
            var ss = dt.getSeconds()
    
            return `${y}-${m}-${d} ${hh}:${mm}:${ss}` 
        }
    })
    
    

字符串填充:padStar()

  1. String.prototype.padStart(maxLength, fillString=’’)

  2. String.prototype.padEnd(maxLength, fillString=’’)

  3. 第一个参数是填充完之后的最大长度,第二个参数是用什么来填充

    <div id="app">
        <input type="button" value="填充" @click='test'>
        <p v-for="item in list">{{item}}</p>
        <p v-for="item in newList">{{item}}</p>
    </div>
    
    <script>
        var vm =  new Vue({
            el:"#app",
            data:{
                list:[
                    1,3,5,69
                ],
                newList:[]
            },
            methods:{
                test(){
                this.list.forEach(item=>{
                    this.newList.push(item.toString().padStart(2,'0'))
                })
                }                
            }
        })
    </script>
    

键盘事件和自定义按键修饰符

  1. 系统自带的按键修饰符

    .enter
    .tab
    .delete
    .esc
    .up
    .down
    .left
    .right
    
  2. 注册键盘事件

    <input type="button" value="添加" @keyup.enter= "add"></input>
    <input type="button" value="添加" @keyup.113= "add"></input>
    
  3. 自定义全局按键修饰符

    Vue.config.keyCodes.f2 =113 //配置f2按键修饰符
    //如果没有配置,那么就不会触发事件,因为没有系统没有这个按键修饰符
    <input type="button" value="添加" @keyup.f2= "add"></input>
    
  4. 键盘弹起事件,如果没有指定那个键或者键盘码,那么随便按哪个键盘,都会触发事件

    <input type="button" value="添加" @keyup= "add"></input>
    

自定义指令

  1. 使用 Vue.directive() 定义全局指令, v-focus

  2. 参数1:指令的名称,在定义的时候不用加上前缀 v- ,直接focus,但是在调用搞定时候,一定要加 v-

  3. 参数2:是一个对象,这个对象身上,有一些 指令相关的函数,这些函数可以在特定的阶段,执行相关的操作

  4. 自定义全局指令案例,可以在两个地放定义指令,一个是在一个新的script标签里(不是和new Vue 在同一个script),另一地方是,在创建Vue实例的new Vue 同一个script 标签里面,全局定义的

    <div id='app'>
        <input type="text" v-model="value" v-focus v-model="value">
    </div>
    <div id='app2'>
        <!-- <input type="text" v-model="value" v-focus v-model="value"> -->
    </div>
    //自定义全局指令,不是和创建Vue实例同一个script
    <script>
         Vue.directive('focus',{
            bind:function(el){ 
                console.log(el)
            },
            inserted:function(el){
                el.focus()
            },
            update:function(el){
                console.log("数据更新了")
            }      
        })
    </script>
    //自定义全局指令,和创建Vue实例同一个script
    <script>//自定义全局指令
         Vue.directive('focus',{
            bind:function(el){
                console.log(el)
            },
            inserted:function(el){
                el.focus()
            },
            update:function(){//当数据更新时触发
                console.log("数据更新了")
            }      
        }) 
    var vm = new Vue({
        el:'#app',
        data: {
            value:"哈哈"
        },
     })
     var vm = new Vue({
        el:'#app2',
        data: {
            value:"嘿嘿"
        }
     })
    </script>
    
  5. 自定义字体颜色指令

    <div id='app'>
        <input type="text"  v-model="message" v-color>
    </div>
    
    <script>
      Vue.directive('color',{
          bind:function(el){
            el.style.color='red'
          },
          inserted:function(el){
            el.style.color='red'
        }
      })  
    </script>
    
  6. 钩子函数,一个指令定义对象可以提供如下几个钩子函数 (均为可选):

    Vue.directive('focus',{
        bind:function(el){//只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置
            console.log(el)
        },
        inserted:function(el){//被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)
            el.focus()
        },
        update:function(){//所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有
            console.log("数据更新了")
        }      
    }) 
    
  7. 钩子函数的binding参数

    <div id='app'>
        <input type="text"  v-model="message" v-color ="'blue'">
    </div>
    
    <script>
      Vue.directive('color',{
          bind:function(el,binding){
            el.style.color = binding.value
            console.log(binding.name) // 指令的名字:color
            console.log(binding.value)    //指令的value:blue
            console.log(binding.expression)    //指令的表达式:'blue'
              
        }
      })  
    var vm = new Vue({
        el:'#app',
        data: {
            message:"哈哈"
        },
     })
    </script>
    
  8. 自定义私有指令

    //有效果
    <div id='app'><p v-fontweight="900">这是app1</p></div>
    //没有效果
    <div id='app2'><p v-fontweight="900" v-fontcolor = "'red'">这是app2</p></div>
    <script>
     var vm2 = new Vue({
        el:'#app2', //绑定 app2 的div
        directives:{//注意:这是多了一个 "s"
            'fontweight':{  //自定义字体粗细的私有指令
                bind:function(el,binding){
                    el.style.fontWeight = binding.value
                }
            },
            'fontcolor':{  //自定字体颜色的指令
                    bind:function(el,binding){
                        el.style.color = binding.value
                    }
                }
        }
     })
    </script>
    
  9. 函数简写,你可能想在 bindupdate 时触发相同行为,而不关心其它的钩子

    <div id='app'>
        <p v-fontsize='32'>hello 小毅!</p>
    </div>
    
    <script>
    var vm = new Vue({
        el:'#app',
        directives:{//注意:这是多了一个 "s"
            'fontsize':function(el,binding){ //这里相当于同时把函数现在 bind 和 updat的钩子函数中
                el.style.fontSize = parseInt(binding.value)+"px"
            }
        }
     })
    </script>
    

生命周期函数-组件创建期间的4个钩子函数

  1. 四个类型的函数

    //创建
    beforeCreate(){},
    create(){},
    //挂载
    beforeMount(){},
    mounted(){},
    //数据更新
    beforeUpdate(){},
    update(){},
    //销毁
    deforeDestroy(){},
    destroyed(){}
    
  2. 学习过属性

    <script>
    var vm = new Vue({
        el:'#app',
        data: {},
        methods: {},
        filters:{},
        directive:{},
        components:{},
    
        beforeCreate(){},
        create(){},
        beforeMount(){},
        mounted(){},
        beforeUpdate(){},
        update(){},
        deforeDestroy(){},
        destroyed(){}
     })
    </script>
    

vue-resource 发起get post jsonp 请求

  1. 案列

    <script src="https://cdn.staticfile.org/vue/2.4.2/vue.min.js"></script>
    <script src="https://cdn.staticfile.org/vue-resource/1.5.1/vue-resource.min.js"></script>
    <div id="app">
        请输入关键字:<input type="text" v-model="keyword" @keyup="sendJsonP(keyword)">
        <ul>
            <li v-for="r in result">{{r}}</li>
        </ul>
    </div>
    <script>
    window.onload = function () {
        new Vue({
          el: '#app',
          data: {
            keyword: '',
            result: ''
          },
          methods: {
            sendJsonP(keyword) {
              let url = 'https://www.baidu.com/sugrec?pre=1&p=3&ie=utf-8&json=1&prod=pc&from=pc_web';
    
              this.$http.jsonp(url, {
                params: {
                  wd: keyword
                },
                jsonp: 'cb'//jsonp默认是callback,百度缩写成了cb,所以需要指定下                     }
              }).then(res => {
                if (res.data.g) {
                  this.result = res.data.g.map(x => x['q']);
                } else {
                  this.result = [];
                }
              });
            }
          }
        });
      }
    </script>
    

结合Node手写JSONP服务器剖析JSONP原理

  1. 客户端 click.html

    <body>
        <script>
            function showInfo(data){
                console.log(data)
            }
        </script>
        <script scr="http://127.0.0.1:3000/getscript?callback=showInfo"></script>
    </body>
    
  2. 服务端 app.js cmd中,输入node app.js

    // 导入 http 内置模块
    const http = require('http')
    // 这个核心模块,能够帮我们解析 URL地址,从而拿到  pathname  query 
    const urlModule = require('url')
    
    // 创建一个 http 服务器
    const server = http.createServer()
    // 监听 http 服务器的 request 请求
    server.on('request', function (req, res) {
    
      // const url = req.url
      const { pathname: url, query } = urlModule.parse(req.url, true)
    
      if (url === '/getscript') {
        // 拼接一个合法的JS脚本,这里拼接的是一个方法的调用
        // var scriptStr = 'show()'
    
        var data = {
          name: 'xjj',
          age: 18,
          gender: '女孩子'
        }
    
        var scriptStr = `${query.callback}(${JSON.stringify(data)})`
        // res.end 发送给 客户端, 客户端去把 这个 字符串,当作JS代码去解析执行
        res.end(scriptStr)
      } else {
        res.end('404')
      }
    })
    
    // 指定端口号并启动服务器监听
    server.listen(3000, function () {
      console.log('server listen at http://127.0.0.1:3000')
    })
    

Vue 过度动画

  1. 实现动画的过渡类名class

    .v-enter,是开始动画之前,还没有开始
    
    . v-leave-to 是动画结束之后的状态,已经结束
    
    .v-enter-active,是动画入场的过程
    
    .v-leave-active 是动画离场的过程
    
  2. 案例:通过过渡类名实现动画,transition 标签的内容,会响应过渡类名class,transition元素,是vue官方提供的。

    <style>
        .v-enter, 
        .v-leave-to {
            opacity: 0;
            transform:translateX(300px)//设置动画入场开始之前和离场结束之后的位置
        }
        .v-enter-active,
        .v-leave-active {
            transition: all 0.4s ease;//设置入场和离场的过程中的动画效果
        }
    </style>
    
    <div id='app'>
        <input type="button" value="toggle" @click="flag= !flag">
        <transition>
            <h3 v-if="flag">这是一个H3</h4>
        </transition>
    </div>
    
    <script>
        var vm = new Vue({
            el: '#app',
            data: {
                flag:false
            }
        })
    
    </script>
    
  3. 可以定义不同的动画

    <style>
    //第二个动画,前缀是 v-
        .v-enter, 
        .v-leave-to {
            opacity: 0;
            transform:translateX(300px)/*
            设置动画入场开始之前和离场结束之后的位置*/
        }
        .v-enter-active,
        .v-leave-active {
            /*设置入场和离场的过程中的动画效果*/
            transition: all 0.4s ease;
        }
    
    //第二个动画,前缀我my-
        .my-enter,
        .my-leave-to{
             opacity: 0;
            transform:translateY(300px)
        }
    
        .my-enter-active,
        .my-leave-active{
            transition: all 0.8s ease;
        }
    </style>
    
  4. transition 标签 name属性,调用不同的动画

    <div id='app'>
        这是调用 v- 前缀的动画
        <input type="button" value="toggle" @click="flag= !flag">
        <transition><h3 v-if="flag">这是一个h3</h3></transition>
    	<hr>
     	//这是调用 my- 前缀的动画
    	<input type="button" value="toggle2" @click="flag2= !flag2"> 
    	<transition name='my'><h3 v-if="flag2">这是一个h6</h3></transition>
    </div>
    <script>
    var vm = new Vue({
        el:'#app',
        data: { 
            flag:false,
            flag2:false
        }
     })
    </script>
    

使用第三方库animate.css实现动画

  1. animate.css:https://animate.style/

  2. 实现动画

    <link rel="stylesheet" href="../js/animate.css">
        
    <div id='app'>
        <input type="button" value="toggle" @click="flag=!flag">
         <transition enter-active-class="bounceIn" leave-active-class="bounceOut">
            <h3 v-if="flag" class="animated">v-if h3</h3>
         </transition>
    </div>  
    

钩子函数

  1. JavaScript 钩子

    <transition
      v-on:before-enter="beforeEnter"    //动画开始之前
      v-on:enter="enter"                 //动画开始的过程
      v-on:after-enter="afterEnter"      //动画开始结束后 
      v-on:enter-cancelled="enterCancelled"  
    
      v-on:before-leave="beforeLeave"   //动画开始之前
      v-on:leave="leave"				//动画离场的过程
      v-on:after-leave="afterLeave"     // 动画离场之后
      v-on:leave-cancelled="leaveCancelled"
    >
    </transition>
    
  2. 可以在methods中定义JavaScript函数

    methods: {
      // --------
      // 进入中
      // --------
    
      beforeEnter: function (el) {
        // ...
      },
      // 当与 CSS 结合使用时
      // 回调函数 done 是可选的
      enter: function (el, done) {
        // ...
        done()
      },
      afterEnter: function (el) {
        // ...
      },
      enterCancelled: function (el) {
        // ...
      },
    
      // --------
      // 离开时
      // --------
    
      beforeLeave: function (el) {
        // ...
      },
      // 当与 CSS 结合使用时
      // 回调函数 done 是可选的
      leave: function (el, done) {
        // ...
        done()
      },
      afterLeave: function (el) {
        // ...
      },
      // leaveCancelled 只用于 v-show 中
      leaveCancelled: function (el) {
        // ...
      }
    }
    
  3. 当只用 JavaScript 过渡的时候,在 enter 和 leave 中必须使用 done 进行回调。否则,它们将被同步调用,过渡会立即完成。

JavaScript钩子函数,实现半场动画案例

  1. html部分

    <style>
    .ball{
        width:15px;
        height: 15px;
        background-color: chocolate;
        border-radius:50%
    }
    
    </style>
    <body>
    <div id='app'>
        <input type="button" value="加入购物车" @click="flag=!flag">
        <transition
         @before-enter="beforeEnter"
         @enter="enter"
         @after-enter="afterEnter">
            <div class="ball" v-show="flag"></div>
        </transition>
    </div>
    </body>
    
  2. javaScript 部分,构子函数

    <script>
    var vm = new Vue({
        el:'#app',
        data: {
            flag:false
        },
        methods: {
            beforeEnter(el){
                console.log("before")
                //beforeEnter  表示动画入场之前,此时,动画未开始,可以在beforeEnter中
                //设置元素开始动画之前的前始位置
                el.style.transform = "translate(0,0)"
            },
            enter(el,done){
                //enter 表示动画,开始之后的样式,可以设置小球完成动画之后的,结束状态
                el.offsetWidth//没有什么意义,el.offsetWidth,会强制刷新
                el.style.transform = "translate(250px,250px)"
                el.style.transition = "all 1s ease"
                done() //done是afterEnter函数的引用,要应用,不然有延迟
                console.log("enter")
            },
            afterEnter(el){
                //动画完成之后,会调用
                this.flag = !this.flag
            }
        }
     })
    </script>
    

transition-group元素实现列表动画

  1. 使用transition-group 包裹住要循环的li

    <transition-group>
        <li v-for='item in list' :key="item.id">
            {{item.id}} ---- {{item.name}}
        </li>
    </transition>>
    
  2. 案例,实现列表的页面的刷新入场,删除和添加的动画效果

    appear 属性,实现页面展现出来的时候,入场的效果

    tag 属性,指定循环的元素,默认是 span

    <style>
        /* 动画开始前和结束后元素的位置 */
        .v-enter,
        .v-leave-to{
            opacity:0;
            transform: translateY(100px);
        }
    
        /* 动画开始入场和离场的过程的动画效果*/
        .v-enter-active,
        .v-leave-active{
            transition:all 0.8s ease;
        }
    
        /* 使用后续的元素,在删除的时候,有动画的效果*/
        .v-move{
            transition: all 0.6s ease;
        }
        .v-leave-active{
            position: absolute;
        }
    </style>
    
    <div id='app'>
        <input type="text" v-model="id">
        <input type="text" v-model="name">
        <input type="button" @click="add" value="添加">
        <transition-group appear tag='ul'>
            <li v-for='(item,i) in list' :key="item.id" @click="del">
                {{item.id}} ---- {{item.name}}
            </li>
        </transition>>
    </div>
    
    
    data: {
        id:'',
        name:'',
        list: [ {id: 1,name: '小毅'},
                {id: 2,name: '小黄'},
                {id: 3, name: '小俞'},
                {id: 4, name: '小陈' },]},
    methods: {
        add(){
            this.list.push({id:this.id,name:this.name})
        },
        del(id){
            this.list.splice(id,1)
        }
    }
    

组件化

  1. 组件的创建,这些都是公有的组件,在不同的Vue实例都可以使用

    <div id='app'>
        <mycoml></mycoml>
        <mycoml2></mycoml2>
        <mycoml3></mycoml3>
        <mycoml4></mycoml4>
    </div>
    
    //引用的外部代码,不可子div#app 里面写,不然写的代码直接响应在html页面上
    <template id="teml"> 
        <div>
            <h2>这是使用template 元素,在外部定义的组件结构</h2>
            <h4>这个方法有代码提示和高亮</h4>
        </div>
    </template>
    
    <script>
        const coml = Vue.extend({ //第一种
            template: "<h3>这是使用Vue.extend 创建的组件</h3>"
        })
        Vue.component('mycoml', coml)
    
        Vue.component('mycoml2',Vue.extend({//第二种
            template: "<h3>这是使用Vue.extend 不用中间变量接受创建的组件</h3>"
        }))
    
        Vue.component("mycoml3",{//第三种,可以直接放一个对象,或者对像的名字
            template: "<h3>这是使用Vue.component直接创建的组件</h3>"
        })
    
    //引用的外部代码,不可子div#app 里面写,不然写的代码直接响应在html页面上
        Vue.component('mycoml4',{//第四种
            template:'#teml'
        })
    </script>
    
  2. 组件的模板只能有一个根元素,不能有两个平级的元素

    <template id="teml"> 
        <div> //div 包裹着两个标题
            <h2>这是使用template 元素,在外部定义的组件结构</h2>
            <h4>这个方法有代码提示和高亮</h4>
        </div>
    </template>
    

##使用components定义私有组件

  1. 使用components定义私有组件,只能在定义自身的Vue实例中调用

    <template id="teml">
        <div>
            <h3>这是一个私有组件</h3>
            <h5>通过引用外部的template</h5>
        </div>
    </template>
    //定义一个私有组件
    var vm = new Vue({
        el:'#app',
        components:{
            login:{
                template:"#teml"
            }
        },
    </script>
    

组件中的data 和 methods

  1. 在组件,data是一个function,return 回来的是一个对象

    <div id='app'> <mycoml></mycoml></div>
        
    Vue.component('mycoml',{
        template:'<h1>这是组件中的data---id:{{id}}--name:{{name}}</h1>',
        data:function(){ //一个function return 一个对象
            return{
                id:1,
                name:"小毅"
            }
        }
    })
    
  2. 利用组件的data 和methods 做一个计数器,组件中methods中定义一个increment函数

    <div id='app'>
        <counter></counter>
        <hr>
        <counter></counter>
        <hr>
        <counter></counter>
    </div>
    <template id="templ"> 
        <div>
            <input type="button" value="加 1 " @click="increment"><br>
            {{count}}
        </div>
    </template>
    
    <script>
        var dataObj = {count:0}//在外面顶定义一个对象
        Vue.component('counter',{
            template:'#templ',
            data:function(){
                //return dataObj ,如果返回的是在外面定义的对象,因为它的引用是同一个地址,所有的count会同时加 1
                return{count:0}//返回这里的count,每一个组件的实例,调用的都是自己的count,他们是不同的地址,所以,不会同时加 1 
            },
            methods:{increment(){this.count++}}
        })
    var vm = new Vue({el:'#app', })
    </script>
    
    

组件切换

  1. 利用v-if 和v-else ,显示登陆或注册的组件

    <div id='app'>
        <a href="#" @click.prevent="flag=true">登录</a>
        <a href="#" @click.prevent="flag=false">注册</a>
        <login v-if="flag"></login>
        <register v-else="flag"></register>
    </div>
    <script>
      //创建两个组件
        Vue.component('login', {
            template: "<h3>登录组件</h3>"
        })
    
        Vue.component('register', {
            template: "<h3>注册组件</h3>"
        })
        var vm = new Vue({ el: '#app',data:{flag:false} })
    </script>
    
  2. 利用Vue提供的标签 component占位, :is =“组件名” ,实现组件的切换

    <style>
        .v-enter,
        .v-leave-to{
            opacity: 0;
            transform: translateY(250px);
        }
    
        .v-enter-active,
        .v-leave-active{
            transition: all 0.5s ease;
        }
    </style>
    
    <div id='app'>
        <a href="#" @click.prevent="comName='login'">登录</a>
        <a href="#" @click.prevent="comName='register'">注册</a>
        <transition mode="out-in">  // mode 模式,先out再in
            <component :is='comName'></component>
        </transition>
    </div>
    
    <script>
        Vue.component('login', {
            template: "<h3>登录组件</h3>"
        })
    
        Vue.component('register', {
            template: "<h3>注册组件</h3>"
        })
        var vm = new Vue({ el: '#app',data:{comName:'login'} })
    </script>
    

子组件的使用父组件的data和本身的data

  1. 在组件中,默认无法访问到父组件中data 上的数据和methods 中的方法

  2. 可以使用,利用属性绑定机制:v-bind: 自定义一个属性,绑定父组件中data的,再在子组件的props:[]的数组中那个定义,这样就可以在子组件中使用父组件data中的数据了

  3. 子组件的所有props 中的数据都是通过父组件传递给子组件的

  4. 子组件的data,是一个function ,返回的是一个对象。

  5. 子组件的data,是子组件私有的,比如:子组件通过Ajax,请求回来的数据,都可以放到data身上

  6. 子组件的props中的数据,都是只可读的,不能写

  7. 父组件中的data 都是可读可写的

    <div id='app'> 
        //v-bind: 一个自定义的属性,再把父组件的的 msg 赋值给这个自定义组件 
        <coml v-bind:parent="msg"></coml>
    </div>
    
    var vm = new Vue({
        el:'#app',
        data: {
            msg:"hello,我是爸爸"
        },
        components:{
            coml:{
                template:"<h1>这是子组件 --   {{ parent }}</h1>",
                props:['parent'] //要把自定义的组件放在props:[] 才可以在子组件中使用
            },
        }
     })
    

子组件通过事件调用向父组件传值

  1. 父组件向子组件传递方法,使用的是事件的绑定机制,v-on,自定义一个事件属性之后,把父组件的方法挂在这个事件属性上,子组件就能过通过某些方式来调用

  2. 下面是子组件通过用自身的事件myclick,利用emit()方法 触发自定义的事件属性,并传入子组件的sonMsg作为参数,这样,就通过自定义的事件属性调用了父组件的方法,并且把子组件的sonMsg传给了父组件的function。

    <div id='app'>
        <com @func="show"></com>
        {{dataFormSon}}
    </div>
    
    <template id="template">
        <div>
            <h2>这是子组件</h2>
            <input type="button" value="触发父组件传递的function" @click='myclick'>
        </div>
    </template>
    
    <script>
        var com = {
            template: '#template',
            data() {
                return{
                    sonMsg:{name:'小毅',age:20}
                }
            },
            methods: {
              myclick(){
                  this.$emit('func',this.sonMsg)
              }
            }
        }
    
        var vm = new Vue({
            el: '#app',
            data: {      
               dataFormSon:null
            },
            methods: {
                show(data){
                    this.dataFormSon = data;
                }
            },
            components: {
                com
            }
        })
    </script>
    

组件的案例

  1. 可以发表评论,可以展示评论列表



## ref获取DOM元素和组件引用

1. javaScript 获取元素

```javascript
<div id='app'>
    <input type="button" value="获取元素" @click="getElement">
    <h3 id="h3">hello,小毅</h3>
</div>
// 通过id 获取h3 的元素
document.getElementById('h3')
  1. 在创建的Vue实例vm 中,有一个ref属性,默认是空的,如果个标签 ref 属性,就可以通过ref获取元素

    vm.$refs 返回一个对象,面里有使用了ref 属性的元素和组件

    我们可以通过 ’ . ’ 的方式,获取 refs对象中元素和组件的data 和方法

    <div id='app'>
        <input type="button" value="获取元素" @click="getElement">
        <h3 id="h3" ref="h3">hello,小毅</h3>
        <h4 id="h4" ref="h4">hello</h4>
        <login ref="login"><login>
    </div>
    
    <script>
        var login = {
            data(){
                return{
                    msg:"子组件的 msg "
                }
            },
            methods:{
                show(){
                    alert("调用了子组件的方法show()")
                }
            },
            template:"<h1>这是一个组件</h1>"
        }
    var vm = new Vue({
        el:'#app', 
        methods: {
            getElement(){
    			//通过ref 获取元素
                console.log(this.$refs)//3个对象{h3,h4,login}
                console.log(this.$refs.h3.innerText)// 通过ref获取h3中的内容
    
                //通过 ref 获取子组件的data 和 方法
                console.log(this.$refs.login.msg)
                this.$refs.login.show()
            }
        } ,
        components:{
            login
        }  
     })
    </script>
    

vue-router安装和基本使用

  1. vue-router 依赖vue,所以要先导入vue.js 再导入vue-router.js

  2. 创建一个vue-router 对象,对象里有一个属性是 routes(注意没有‘R’),是一个数组,用来定义router的规则,这个routes 数组中可以放多个对象,每个对象就一个路由规则

  3. 每一个路由规测有两个必须的参数,path:路由链接地址,component:对应的组件

  4. vue-router 提供一个标签‘router-view’,当作占位符,由路由规测匹配到的组件,就会再这里展示

    <div id='app'>
        <!-- 展示匹配路由URL成功的组件 -->
        <router-view></router-view>  
    </div>
    <script src='../js/vue.js'></script>
    <script src='../js/vue-router-3.0.1.js'></script>
    <script>
        //创建两个组件对象
        var login = {
            template:"<h3>登录组件</h3>"
        } 
        var register = {
            template:"<h3>注册组件</h3>"
        }
    
        var routerObj = new VueRouter({
            routes:[//路由规测数组
                {path:'/login',component:login}, //一个路由规测对象
                {path:'/register',component:register},
            ]
        })
    var vm = new Vue({
        el:'#app',
        router:routerObj //把路由对像挂到Vue的router,属性中
     })
    </script>
    

router-link 和重定向

  1. router-link

  2. 重定向

  3. tag标签

    <style> 
        /* .router-link-active, */
        .active{
            color:bisque;
        }
    </style>
    <body>
        <div id='app'>
            <router-link to="/login" tag="span">登录</router-link>
            <router-link to="/register">注册</router-link>
            <router-view></router-view>
        </div>
        <script src='../js/vue.js'></script>
        <script src='../js/vue-router-3.0.1.js'></script>
        <script>
            var login = {template: '<h3>登录组件</h3>' }
            var register = {template: '<h3>注册组件</h3>'}
    
            var routerObj = new VueRouter({
                routes: [
                    {path: '/', redirect: '/login'},
                    { path: '/login',component: login },
                    {  path: '/register', component: register}
                ],
                //linkActiveClass 默认为:router-link-active
                linkActiveClass:'active'
            })
            var vm = new Vue({ el: '#app',router:routerObj})
        </script>
    

router 动画

  1. 动画

    <style> 
        /* .router-link-active, */
        .active{
            color:bisque;
        }
    
        .v-enter,
        .v-leave-to{
            opicity:0;
            transform: translateX(250px);
        }
    
        .v-enter-active,
        .v-leave-active{
            transition:all 0.8s ease;    
        }
    </style>
    <body>
    <div id='app'>
        <router-link to="/login" tag="span">登录</router-link>
        <router-link to="/register">注册</router-link>
        <transition mode="out-in">
            <router-view></router-view>
        </transition>
    </div>
    

路由的两种获取参数的方法

  1. query

  2. params

    <div id='app'>
        <router-link to="/login?id=10&name='小毅'">登录</router-link>
        <router-link to="/register/11/'小花'">注册</router-link>
        <router-view></router-view>
    </div>
    
    <script>
    //方法一
    var login = {
        template:'<h2>登录 使用query获取参数:--id:{{$route.query.id}}--用户:{{$route.query.name}} </h2>',
    
    }
    //方法二
    var register = {
        template:'<h2>注册 使用params 获取参数:--id:{{this.$route.params.id}}--用户:{{this.$route.params.name}}</h2>',
    }
    
    var routerObj = new VueRouter({
        routes:[
            {path:'/',redirect:'login'},
            {path:'/login',component:login},
            {path:'/register/:id/:name',component:register}
            ]
    })
    var vm = new Vue({el:'#app', router:routerObj})
    </script>
    

使用children 属性实现路由的嵌套

  1. 在路由对象中,使用children属性实现路由的嵌套

    <style>
        .tem{ height: 500px; width:800px; background-color: bisque;
        }
        h3{ height:400px; background-color: blue;}
    </style>
    
    <div id='app'>
        <router-view></router-view>
    </div>
    
    <template id="template">
        <div class= 'tem'>
            <h2>这个root 组件</h2>
            <router-link to='/root/children1'>登录(children1)</router-link>
            <router-link to='/root/children2'>注册(children2)</router-link>
            <router-view></router-view>
        </div>
    </template>
    
    <script>
        var root = {template:"#template"}
        var children1 = {template:'<h3>登录</h3>'}
        var children2 = {template:'<h3>注册</h3>'}
        var routerObj = new VueRouter({
            routes:[
                {path:'/',redirect:'root'},
                {path:'/root',
                 component:root,
                  children:[
                        {path:'children1',component:children1},
                        {path:'children2',component:children2}
                    ]
                },]
            })
        var vm = new Vue({el:'#app',router:routerObj })
    </script>
    

路由命名视图实现经典布局

  1. 给 router-view 添加一个那么 属性

    <style>
        html,body,h1{margin:0;padding:0;}
        .header{background-color: magenta;}
        .container{display: flex;height:600px;}
        .left{ background-color: lightcoral; flex:2;}
        .main{ background-color:lightseagreen;flex:8;}
    </style>
    <div id='app'>
        <router-view></router-view>
        <div class="container">
            <router-view name = 'left'></router-view>
            <router-view name = 'main'></router-view>    
        </div>
    </div>
    <script>
        var header = {template:'<h1 class="header">header</h1>'}
        var leftBox = {template:'<h1 class="left">Left</h1>'}
        var mainBox = {template:'<h1 class="main">main</h1>'}
        var routerObj = new VueRouter({
            routes:[
                {path:'/',components:{
                    'default':header,
                    'left':leftBox,
                    'main':mainBox
                }}
            ]
        })    
    	var vm = new Vue({el:'#app',router:routerObj})
    </script>
    

webpack的基本使用方法

  1. 新建项目的文件夹

    webpack  //项目名
        dist  //文件夹
        src   //文件夹
            images        // src 下的文件夹
            css		      // src 下的文件夹
            js		      // src 下的文件夹
            index.html  // src 下的html文件
            main.js     // src 下的js 文件
    
  2. 初始化项目

    npm init -y
    
  3. 安装

    //全局安装
    npm i webpack -g
    //安装到项目依赖中
    npm i webpack --save-dev
    
  4. 在main .js 文件中,导入其他文件(js.css),比如jquery.js 文件

    // 这是main.js 文件
    import $ from 'Jquery'
    
    //利用jquery 使列表隔行变色
    $(function(){
        $("li:odd").css('backgroundColor','lightblue')
        $("li:even").css('backgroundColor','green')
        // $('li').css('backgroundColor','red')
    
    })
    
  5. 运行webpack,运行下面的代码,在dist下有一个bundle.js 文件

    webpack .\src\main.js -o .\dist\bundle.js
    
  6. 在index.html中,写一个ul>li*10,在导入dist下的bundle.js 文件,在浏览器打开index.html 即可

    // 这是index.html
    
    <script src="../dist/bundle.js"></script>
      
    <ul>
        <li>这是第1个li</li>
        <li>这是第2个li</li>
        <li>这是第3个li</li>
        <li>这是第4个li</li>
        <li>这是第5个li</li>
        <li>这是第6个li</li>
        <li>这是第7个li</li>
        <li>这是第8个li</li>
        <li>这是第9个li</li>
        <li>这是第10个li</li>
    </ul>
    

webpack 配置文件

  1. 如果每一次修改js ,css 文件都需要用命令形式(webpack .\src\main.js -o .\dist\bundle.js)指定入口和出口文件太麻烦

  2. 我们可以在项目的跟目录,创建一个配置文件:webpack.config.js,在控制台运行:webpack 即可得到bundle.js,文件

    const path = require('path')
    module.exports = {
        //入口,表示要使用webpack 打包那个文件
        entry:path.join(__dirname,'./src/main.js'),
        //输出文件的配置,输出文件的目录,和文件名
        output:{
            path:path.join(__dirname,'./dist'),
            filename:'bundle.js'
        }
    }
    
  3. webpack 工作过程

    // 当在控制台运行: webpack
    1、webpack发现没有通过命令行的形式指定入口和出口
    2、找到配置文件,webpack.config.js 
    3、解析执行配置文件,导出配置对象
    4、当webpack拿到配置对象后,根据入口和出口进行打包构建
    

webpack-dev-server的基本使用

  1. 每一次修改代码,要重新看效果,都需要运行webpack,很麻烦,所以我们使用webpack-dev-server

  2. webpack-dev-server这个工具,可以实现自动打包编译的动能(和nodemon类似),不仅可以打包编辑项目,还可以使项目通过localhost本地的方式进行访问我们的项目,这一点和apache类似

  3. 安装,这个工具只能安装在项目中,不能进行全局的安装

    cnpm i webpack-dev-server -D
    
  4. webpack-dev-server 这个工具,如果想要正常运行,一定要在本地的项目中安装webpack,即使我们已经在全局中安装过了webpack

    cnpm i webpack -D
    
  5. 在package.json 文件中配置webpack-dev-server ,注意在json 文件中不能写注释,字符串要用双引号

     "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "dev": "webpack-dev-server"
      },
    
  6. 安装脚手架

    cnpm i webpack-cli -D 
    
  7. 运行

    npm run dev
    
  8. 默认访问loclhsot:8080即可访问我们的项目

  9. 生成的bundle.js在 根目录下,在内存中,所以在html 文件中引入这个js文件的路径一定要修改

    <script src="/bundle.js"></script>
    

webpack-dev-server 的常用命令

  1. 第一种方法,也是推荐的一种,在package,中配置webpacke-dev-server

    // --open	=>	运行完命令后打开浏览器
    // --oprt 3000	=>	设置端口
    // --contentBase	=>	访问的文件路径	默认是 根目录 /
    // --hot	=> 	不重新生成bundle.js 文件,只是在这个基础上加载修改的部分,而且可以同步到浏览器,不用					手动刷新
    
    
    "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "dev": "webpack-dev-server --open --port 3000 --contentBase  src --hot"
      }
    
  2. 第二种方法:在webpack.config.js 文件中配置我webpack-dev-server

    // 第一步  在package.json 文件下的script 中添加 dev2
    "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "dev": "webpack-dev-server --open --port 3001 --contentBase  src --hot",
        "dev2": "webpack-dev-server"
      },
          
    //第二步  在webpack.config.js 文件下配置webpack-dev-server    
    const path = require('path')
    //启动热更新的 第二步
    const webpack = require('webpack')
    module.exports = {
    //入口,表示要使用webpack 打包那个文件
    entry:path.join(__dirname,'./src/main.js'),
    //输出文件的配置,输出文件的目录,和文件名
    output:{
        path:path.join(__dirname,'./dist'),
        filename:'bundle.js'
    },
    devServer:{
        open:true,
        port:3000,
        contentBase:'src',
        hot:true   //启动热更新的  第一步
    },
    plugins:[
        new webpack.HotModuleReplacementPlugin()  启动热更新的  第三步
    ]
    }
    

html-webpack-plugin

  1. 在内存中生成html

  2. 安装

    cnpm i html-webpack-plugin -D
    
  3. 配置,在webpack.config.js 文件中配置

    //导入插件
    const htmlWebpaPlugin = require('html-webpack-plugin')
    
    // 在plugins 中添加插件配置
    plugins:[
        new webpack.HotModuleReplacementPlugin(),  启动热更新的  第三步
        new htmlWebpaPlugin({
            template:path.join(__dirname,'./src/index.html'), //把哪个文件生成到内存中
            filename:'index.html' // 生成到内存中的文件的文件名
        })
    ]
    
  4. 当使用了html-webpack-plugin 之后,就不需要手动处理bundle.js 的引用路径了,因为这个插件,会自动帮我们创建一个合适的 script 并且引用了正确的路径

css-loader处理css文件

  1. webpack默认只能处理JS类型的文件,如果需要处理非JS类型的文件,我们需要手动安装一些合适的第三方加载器

  2. 安装style-loader 和 css-loader

    cnpm i style-loader css-loader -D
    
  3. 在webpack.config.js 配置文件,新增一个配置节点module,他是一个对象,在这个module对象中,有个rules 属性,这个rules 属性是一个数组,这个数组中,存放了所有第三方文件的匹配和处理规则

    //这是webpack.config.js 配置文件
    module:{// 这个节点,用于配置 所有的第三方模块  加载器
        rules:[//所有第三方模块的 匹配规则  
            {test:/\.css$/,use:['style-loader','css-loader'],
        ]
    }
    
    // css目录下,新建一个index.css 文件,并写入样式
    li{
    	list-style: none;
    }
         
    // 在main.js 中导入css样式文件
    import './css/index.css'       
    
  4. 第三方loader的调用过程

    1、wenbpack发现,我们并没有通过命令的形式,给他指定入口和出口
    2、webpack就去根目录中,查找一个叫做"webpack.config.js"的配置wenjian
    3、webpack 解析配置文件,当解析完配置文件之后,就得到了配置文件中导出的配置对象
    4、webpack 拿到配置对象后,就拿到了配置对象中,指定的入口和出口,然后 进行打包和构建
    

配置处理less文件的loader

  1. 安装

    cnpm i less-loader -D
    cnpm i less -D   // less 是less-loader 的内部依赖文件
    
  2. 配置使用

    //配置
    module:{// 这个节点,用于配置 所有的第三方模块  加载器
        rules:[//所有第三方模块的 匹配规则  
            {test:/\.css$/,use:['style-loader','css-loader']},
            {test:/\.less$/,use:['style-loader','css-loader','less-loader']}
        ]
    // 在css 目录先创建一个index.less文件并写入内容
    ul{
        margin:0;
        padding: 0;
    }
        
    // 在main.js 中导入.less 文件
    import './css/index.less'
    
    

配置处理scss文件的loader

  1. 安装

    cnpm i sass-loader -D
    cnpm i node-sass -D //node-sass 是sass-loader 的内部依赖
    
  2. 配置使用

    //配置
    module:{// 这个节点,用于配置 所有的第三方模块  加载器
        rules:[//所有第三方模块的 匹配规则  
            {test:/\.css$/,use:['style-loader','css-loader']},
            {test:/\.less$/,use:['style-loader','css-loader','less-loader']},
    	    {test:/\.scss$/,use:['style-loader','css-loader','sass-loader']}
        ]
    // 在css 目录先创建一个index.scss文件并写入内容
    html,body{
        margin:0;
        padding:0;
    }
    
    li{
        font-size: 12px;
        line-height: 30px;
    }
        
    // 在main.js 中导入.less 文件
    import './css/index.scss'
    

webpack 项目初始化

  1. 简单的描述一下webpack 的配置

    npm init -y
    webpack ./src/main.js ./dist/bundle.js   //全局安装了wepback,但是这个办法太麻烦
    cnpm i webpack-dev-server -D   //安装一个工具,可以实时打包
    cnpm i webpack -D  //本地安装一个webpacn
    新建一个webpack.config.js 配置文件配置入口,和出口
    在pakage.json的script节点下配置dev
    	第一种方法:"dev":"webpack-dev-server --open --port 3000 --contentBase src --hot"
    cnpm i html-webpack-plugin -D  //可以在内存中生成html 的工具
    配置 html-webpack-plugin 
    	plugins:[
            template:path.jion(__dirname,'./src/index.html'),
            filename:'index.html'
        ]
        
    // 处理样式的 loader
    cnpm i style-loader css-loader -D //处理.css文件
    cnpm i less-loader less -D //处理.less文件
    cnpm i sass-loader node-sass -D //处理.less文件
    
    配置所有第三方某块
    module:{
        rules:[
            {test:/\.css$/,use:['style-loader','css-loader'},
       		{test:/\.less$/,use:['style-loader','css-loader','less-loader'},
            {test:/\.scss$/,use:['style-loader','css-loader','sass-loader'}
        ]
    }
    //在main.js 中引入样式文件
    import './css/index.css'
    import './css/index.less'
    import './css/index.scss'
    

webpack中url-loader 的使用 处理图片和字体图标

  1. webpack 默认是无法处理css文件中的 url地址,不管是图片和还是字体库,只要是URL 都处理不了

  2. 安装配置url-loader

    //安装
    cnpm i url-loader file-loader -D
    //配置
    module:{// 这个节点,用于配置 所有的第三方模块  加载器
            rules:[//所有第三方模块的 匹配规则  
                {test:/\.css$/,use:['style-loader','css-loader']},
                {test:/\.(jpg|png|gif|bmp|jpeg)$/,use:'url-loader?limit=30&name=[name].[ext]'},//处理图片 URL
                {test:/\.(ttf|eot|svg|woff|woff2)$/,use:'url-loader'}// 处理图标
            ]
                
        }
    

webpack中bable 的配置

  1. webpack中,默认只能处理一部分的ES6的新语法,一些更高级的ES6语法或ES7语法webpack就无能为力。

  2. 可以通过第三方loader 把更高级的语法转为低级的语之后,把结果交给webpack去打包到bundle.js中

  3. 通过第三方loader,Babel ,可以帮我们把高级的语法转换为低级的语法。

  4. 可能会版本不对应

    babel-loader 8.x对应babel-core 7.x
    babel-loader 7.x对应babel-core 6.x
    
  5. 安装

    cnpm i babel-core babel-loader babel-plugin-transform-runtime -D
    
    cnpm i babel-preset-env babel-preset-stage-0 -D
    
    cnpm i --save-dev babel-loader@7.1.5 //如果版本不对应,可以降低babel-loader的版本
    
  6. 配置

    //在webpack.config.js
    module:{
        rules:[
            {test:/\.js$/,use:'babel-loader',exclude:/node_modules/}
        ]
    }
    
    //在跟目录新建一个.babelrc 的文件,并写入
    {
        "presets":["env","stage-0"],
        "plugins":["transform-runtime"]
    }    
    
  7. babel-preset-env,是比较新的ES6语法,他包含了所有和ES*相关的语法

使用vue实例render 方法渲染组件

  1. 使用conponents

    <div id='app'>
        <login></login>
    </div> 
    
    <script>
        var login = {
            template:'<h1>这是登录组件</h1>'
        }
    var vm = new Vue({
        el:'#app',
        components:{
            login
        }
     })
    </script>
    
  2. 使用render

    <div id='app'>
    
    </div>
    <script>
        var login = {
            template:'<h1>这是登录组件</h1>'
        }
    	var vm = new Vue({
        el:'#app',
        render:function(createElements){//createElements 是一个方法,调用它,可以把指定的组件模板渲染为html结构
            return createElements(login)
        }
     })
    </script>
    
  3. 这两者的区别

    // 1、render会替换页面中el 指定的那个容器,容器的全部东西都会消失,只有组件的内容
    // 2、components就像差值表达式一样,只是插入这个组件
    

如何在webpack构建的项目中使用vue开发

  1. 在网页中

    1、使用script标签,引用vue的包
    2、在index页面中,创建一个 id 为 app 的div 容器
    3、通过 new Vue 得到一个vm 的实例
    
  2. 在webpack的项目中

  3. 按装Vue

     cnpm i vue -S
    
  4. 在webpack中,在main.js 使用import Vue from ‘vue’ 导入的Vue 构造函数,功能不完整,只能提供

    import Vue from 'vue'
    
  5. 包的查找过程

    1、在项目根目录中有没有node_modules的文件夹
    2、在node_modules中,找对应的vue文件夹
    3、在vue 文件夹的package.json 的配置文件中,有一个main 属性
    4、main属性指定了这个包在被加载时候的入口文件,默认: "main": "dist/vue.runtime.common.js",
    
  6. 在main.js 中导入VUE,创建一个实例

    //导入vue 的第一种方法
    import Vue from 'vue'//这是阉割版的vue.js(vue.runtime.common.js)
    
    //导入vue 的第二种方法
    import Vue from '../node_modules/vue/dist/vue.js'// 这是完全版的vue.js
    
    //导入vue 的第三种方法  是对第二种方法的一个改进
    import Vue from 'vue' // 先在main.js 导入vue
    //再在webpack.config.js 中和entry,output,module,plugins,平级再建一个配置节点,resolve
    resolve:{
        alias:{// 修改Vue被导入时候包的路径
            "vue$":"/node_modules/vue/dist/vue.js"
        }
    }
    -------------------------------------------------------------------------------------
    //在main.js中创建Vue实例
    var vm = new Vue({
        el:'#app',
        data:{
            a:"在webpack 中使用vue"
        }
    })
    -------------------------------------------------------------------------------------
    
    // 在index.html 中创建一个 id=app 的div容器
    
    <div id="app">
        <p> hello{{a}}</p> 
    </div>
    

在webpach 中使用vue 结合render渲染组件到指定的容器中

  1. 默认webpack 无法打包 .vue 文件,需要相关的loader

  2. 安装配置

    //安装
    cnpm i vue-loader vue-template-compiler -D
    //配置,在webpack.config.js的
    
    {test:/\.vue$/,use:"vue-loader"}
    
    
    const VueLoaderPlugin = require('vue-loader/lib/plugin');
    plugins:[
        new VueLoaderPlugin()// 把VueLoaderPlugin放到plugins中
    ],
    
  3. 定义一个login.vue 文件

    <template>
        <div>
            <h1 @click="show">这是登录组件,是使用.vue 文件定义的 {{msg}}</h1>
        </div>
    </template>
    
    <script>
    export default{
        data(){
            return {
                msg:"家强牛逼"
            }
        },
        methods:{
            show(){
                console.log('调用了 login.vue 中的show 方法'),
            }
        }
    }
    </script>
    
    
    <style>
    
    </style>
    
  4. 在main.js中,导入vue并创建一个实例,用render 的方法,渲染 login.vue组件

    //导入vue ,这是在only runtime 的模式下的vue
    import Vue from 'vue'
    import login from './login.vue'
    var vm = new Vue({
        el:'#app',
        // render:function(createElements){  
        //     return createElements(login)
        // }
        render:c=>c(login)// 这是render渲染用箭头函数的简写
    })
    
  5. 在html中创建一个容器,render 方法渲染的组件,会把这个容器里面的内容全部替换

        <div id="app">
            <p> hello{{a}}</p> 
        </div>
    

export default 和export 导入和导出

  1. 在node.js中,向外暴露成员的形式和导入。

    module.exports = {}
    exports {}
    var test =require('test')
    
  2. 在ES6 中,用export default 和export 向外暴露成员

//这个test.js 文件
export default { // export default 一个文件只能暴露一个对象
    name:"小毅",
    age:20
}

export var title ="家强牛逼"
export var content ="小毅牛逼"
  1. 接收,export default 和 export 暴露的对象

    //这是main.js 文件
    import test,{title,content} from './test'
    console.log(test)
    console.log(title+"----"+content)
    

webpack 使用vue-router

  1. 中文官方文档:https://router.vuejs.org/zh/

  2. 下载,安装,使用

    cnmp i vue-router -S//下载
    
    import Vue from 'vue'
    
    import VueRouter from 'vue-router'// 导入vue-router 包
    
    Vue.use(VueRouter)  // 手动安装 VueRouter
    
  3. 新建3 个.vue 文件的组件

    //App.vue  ------------------------------------------
        <template>
          <div>
            <h1>这是 App 组件</h1>
            <router-link to="/account">Account</router-link>
            <router-link to="/goodslist">Goodslist</router-link>
            <router-view></router-view>
          </div>
        </template>
        <script>
        </script>
        <style>
        </style>
    
    //account.vue   ----------------------------------------
    <template>
      <div>
        <h1>这是 Account 组件</h1>
      </div>
    </template>
    <script>
    </script>
    <style>
    </style>
    
    //goodslist.vue  ------------------------------------------
    <template>
      <div>
        <h1>这是 GoodsList 组件</h1>
      </div>
    </template>
    <script>
    </script>
    <style>
    </style>
    
  4. 导入.vue文件的组件

    // 导入组件
    import app from './App.vue'
    import account from './main/account.vue'
    import goodslist from './main/goodslist.vue'
    
  5. 使用vue-router

    //创建路由对象
    var router = new VueRouter({
        routes:[
            {path:'/account',component:account},
            {path:'/goodslist',component:goodslist},   
        ]
        })
    //将路由挂载到 Vue 实例中
    var vm = new Vue({
        el:'#app',
        render:c=>c(app),
        router
    })
    
  6. 注意:

    // 因为.vue 文件的组件的中,有style的标签,所以要处理样式的loader
    {test:/\.css$/,use:['style-loader','css-loader']},    
    

vue-router实现路由的嵌套

  1. 再建两个.vue 文件的子组件,并嵌套在account 路由下

  2. 在mian.js 中导入新建的两个子组件

    // 导入 Account的两个子组件
    import login from './suboom/login.vue'
    import register from './suboom/register.vue'
    
  3. 在account 路由对象中,添加children 属性,设置子路由,实现路由的嵌套

    var router = new VueRouter({
        routes:[
            {path:'/account',
            component:account,
            children:[
                {path:'login',component:login},
                {path:'register',component:register},
            ]    
        },
            {path:'/goodslist',component:goodslist},   
        ]
        })
    

组件中scoped属性和lang属性

  1. 样式的scoped 属性是通过css 的属性选择器实现的,因为一旦加了scoped属性,那么就回给这个组件的最外层的容器,添加一个data- 开头的属性,在渲染的时候,就只会选择这个属性。不会全局渲染。

    //全局的字体都变成了红色
    <style>
        div{
            color:red;
        }    
    </style>
    
    //只有当前组件的字体都变成了红色
    <style scoped>
        div{
            color:red;
        }    
    </style>
    
  2. 普通的style 标签只支持普通的css样式,如果想要启用 scss 或 less ,需要为style 元素,设置lang属性

    <style scoped lang="scss">
        div{
            font-style:italic;
        }    
    </style>
    

Mint UI中按钮组件的使用

  1. 中文官方文档:http://mint-ui.github.io/#!/zh-cn

  2. 安装

    cnpm install mint-ui -S
    

Promise 处理回调地狱问题

  1. 回调地狱,就是多层嵌套

    // 顺序读取的 1 2 3 文件的内容
    const fs = require('fs')
    const path = require('path')
    
    // 封装一个读取文件内容信息的方法
    function getFileByPath(fpath, succCb, errCb) {
        fs.readFile(fpath, 'utf-8', (err, dataStr) => {
            if (err) return errCb(err)
            succCb(dataStr)
        })
    }
    
    // 调用 getFileByPath 方法读取文件
    getFileByPath(path.join(__dirname, './files/1.txt'), function (data) {
        console.log(data)
      
        getFileByPath(path.join(__dirname, './files/2.txt'), function (data) {
            console.log(data)
      
            getFileByPath(path.join(__dirname, './files/3.txt'), function (data) {
                console.log(data)
                
             })
         })
    
    })
    
  2. Promise 是一个构造函数,表示异步操作。

    var poromise = new Promise()
    
  3. 在Promise 上有两个函数

    resolve // 成功之后的回调函数  resolve(决定)
    reject  // 失败之后的回调函数  reject(拒绝)
    
  4. Promise 是一个异步操作,所以,内部拿到操作结果后,无法使用return 把结果返回给调用者,,这个时候只能使用回调函数的形式,把成功或失败的的结果,返回给调用者

    1、异步执行成功,需要在内部调用 成功的回调函数, resoleve 把结果返回给调用者
    2、异步执行失败,需要在内部调用 失败的回调函数, reject 把结果返回给调用者
    
  5. 在Promise 构造函数的Prototype属性上,有一个.then()方法,也就是说,只要是Promise 构造函数创建的实例,都可以访问.then()方法。调用.then() 方法,为这个异步操作,指定成功(resolve) 和 失败(reject)回调函数

    // 使用.then()方法
    function getFileByPath(fpath) {
        var promise = new Promise(function(resolve,reject){
        fs.readFile(fpath,'utf-8',(err,dataStr)=>{
           if(err) return reject(err)
           resolve (dataStr)
          })
        })
        return promise// 放回promise对象
    }
    
    //调用读取文件的方法
    var p = getFileByPath("./files/1.txt")
    p.then(function(data){
            console.log(data)
        },function(err){
            console.log(err.message)
        }
    )
    

Promise 实例的创建,且创建就会立即执行

  1. Promise 实例的创建

    var promise = new Promise(function(){
        fs.readFile('./files/1.txt','utf-8',(err,dataStr)=>{
            if(err) throw err
            console.log(dataStr)
        })
    })
    
  2. Promise 的实例,一旦创建,就会立即调用,那么可以 创Promise 封装在一个function 中,调用function的时候在执行创建Promise 实例。

    const fs = require('fs')
    
    // 封装一个读取文件内容信息的方法
    function getFileByPath(fpath) {
        var promise = new Promise(function(){
        fs.readFile(fpath,'utf-8',(err,dataStr)=>{
            if(err) throw err
            console.log(dataStr)
          })
        })
    }
    //调用读取文件的方法
    getFileByPath("./files/1.txt")
    

利用Promise 解决回调地狱的问题

  1. 对顺序读取多个文件,利用Promise,可以提高代码的可读性,和速度

    // 使用.then()方法
    function getFileByPath(fpath) {
        return new Promise(function (resolve, reject) {
            fs.readFile(fpath, 'utf-8', (err, dataStr) => {
                if (err) return reject(err)
                resolve(dataStr)
            })
        })
    
    }
    //调用读取文件的方法
    getFileByPath("./files/1.txt")
        .then(function (data) {
            console.log(data)
            return getFileByPath('./files/2.txt')
        })
        .then(function(data){
            console.log(data)
            return getFileByPath('./files/3.txt')
        })
        .then(function(data){
            console.log(data)
        })
    

Promise 捕获异常

  1. .them()方法里面有两个回调函数,一个是成功,resolve ,成功之后的回调函数 reject 失败之后的回调函数 ,在读取第一个文件的时候,以为没有13333.txe的文件,所以调用了失败的的回调函数,然后继续执行,读取文件2 ,和文件3 的内容。

    //调用读取文件的方法
    getFileByPath("./files/13333.txt")
        .then(
        function (data) {// 成功的回调函数
            console.log(data)// 没有执行
            return getFileByPath('./files/2.txt')
        },
        function(err){ // 失败的的回调函数
            console.log("这是失败的结果:"+err.message)
            return getFileByPath('./files/2.txt')
        }
      )
    // 就算上的读取文件失败,也可以执行下面的代码
        .then(function(data){
            console.log(data)// 执行成功
            return getFileByPath('./files/3.txt')
        })
        .then(function(data){
            console.log(data)// 执行成功
        })
    
  2. 使用catch 捕获异常,在.then() 方法后面,加catch() 方法。如果在catch() 前面,有任何的Promise 执行失败,则立即终止所有的Promise 的执行,并马上进入catch 中去处理Promise 中抛出的异常。

    //调用读取文件的方法
    getFileByPath("./files/1.txt")
        .then(function (data) {
            console.log(data)// 执行成功
            return getFileByPath('./files/3333.txt')//执行失败,进入catch 处理异常
        },function(err){
            console.log("这是失败的结果:"+err.message)  // 不执行
            return getFileByPath('./files/2.txt')
        })
        .then(function(data){// 不执行
            console.log(data)  
            return getFileByPath('./files/3.txt')
        })
        .then(function(data){// 不执行
            console.log(data)
        })
        .catch(function(err){// 执行
            console.log("第二个文件读取失败:"+err.message)
        })
    
    

Promise-Jquery Ajax的使用

  1. 是用Promise 替代Ajax 成功的的方法

    <script>
        $('input').on('click',function(){
            $.ajax({
                url:'./data.json',
                type:'get',
                dataType:'json',
                // success:function(data){
                //     console.log(data)
                // }
            })
            .then(function(data){
                console.log(data)
            })
        })
    </script>
    

s.readFile(fpath,‘utf-8’,(err,dataStr)=>{
if(err) throw err
console.log(dataStr)
})
})
}
//调用读取文件的方法
getFileByPath("./files/1.txt")


1. 

##  利用Promise 解决回调地狱的问题

1. 对顺序读取多个文件,利用Promise,可以提高代码的可读性,和速度

```javascript
// 使用.then()方法
function getFileByPath(fpath) {
    return new Promise(function (resolve, reject) {
        fs.readFile(fpath, 'utf-8', (err, dataStr) => {
            if (err) return reject(err)
            resolve(dataStr)
        })
    })

}
//调用读取文件的方法
getFileByPath("./files/1.txt")
    .then(function (data) {
        console.log(data)
        return getFileByPath('./files/2.txt')
    })
    .then(function(data){
        console.log(data)
        return getFileByPath('./files/3.txt')
    })
    .then(function(data){
        console.log(data)
    })

Promise 捕获异常

  1. .them()方法里面有两个回调函数,一个是成功,resolve ,成功之后的回调函数 reject 失败之后的回调函数 ,在读取第一个文件的时候,以为没有13333.txe的文件,所以调用了失败的的回调函数,然后继续执行,读取文件2 ,和文件3 的内容。

    //调用读取文件的方法
    getFileByPath("./files/13333.txt")
        .then(
        function (data) {// 成功的回调函数
            console.log(data)// 没有执行
            return getFileByPath('./files/2.txt')
        },
        function(err){ // 失败的的回调函数
            console.log("这是失败的结果:"+err.message)
            return getFileByPath('./files/2.txt')
        }
      )
    // 就算上的读取文件失败,也可以执行下面的代码
        .then(function(data){
            console.log(data)// 执行成功
            return getFileByPath('./files/3.txt')
        })
        .then(function(data){
            console.log(data)// 执行成功
        })
    
  2. 使用catch 捕获异常,在.then() 方法后面,加catch() 方法。如果在catch() 前面,有任何的Promise 执行失败,则立即终止所有的Promise 的执行,并马上进入catch 中去处理Promise 中抛出的异常。

    //调用读取文件的方法
    getFileByPath("./files/1.txt")
        .then(function (data) {
            console.log(data)// 执行成功
            return getFileByPath('./files/3333.txt')//执行失败,进入catch 处理异常
        },function(err){
            console.log("这是失败的结果:"+err.message)  // 不执行
            return getFileByPath('./files/2.txt')
        })
        .then(function(data){// 不执行
            console.log(data)  
            return getFileByPath('./files/3.txt')
        })
        .then(function(data){// 不执行
            console.log(data)
        })
        .catch(function(err){// 执行
            console.log("第二个文件读取失败:"+err.message)
        })
    
    

Promise-Jquery Ajax的使用

  1. 是用Promise 替代Ajax 成功的的方法

    <script>
        $('input').on('click',function(){
            $.ajax({
                url:'./data.json',
                type:'get',
                dataType:'json',
                // success:function(data){
                //     console.log(data)
                // }
            })
            .then(function(data){
                console.log(data)
            })
        })
    </script>
    
上一篇:R study day01 — 简介、基本操作


下一篇:Nginx基础环境搭建