关于程序员:vue学习笔记

VUE学习笔记

意识Vue

    <body>
        <!-- 
            初识Vue:
                1.想让Vue工作,就必须创立一个Vue实例,且要传入一个配置对象;
                2.root容器里的代码仍然合乎html标准,只不过混入了一些非凡的Vue语法;
                3.root容器里的代码被称为【Vue模板】;
                4.Vue实例和容器是一一对应的;
                5.实在开发中只有一个Vue实例,并且会配合着组件一起应用;
                6.{{xxx}}中的xxx要写js表达式,且xxx能够主动读取到data中的所有属性;
                7.一旦data中的数据产生扭转,那么页面中用到该数据的中央也会自动更新;

                留神辨别:js表达式 和 js代码(语句)
                        1.表达式:一个表达式会产生一个值,能够放在任何一个须要值的中央:
                                    (1). a
                                    (2). a+b
                                    (3). demo(1)
                                    (4). x === y ? 'a' : 'b'

                        2.js代码(语句)
                                    (1). if(){}
                                    (2). for(){}
        -->

        <!-- 筹备好一个容器 -->
        <div id="demo">
            <h1>Hello,{{name.toUpperCase()}},{{address}}</h1>
        </div>

        <script type="text/javascript" >
            Vue.config.productionTip = false //阻止 vue 在启动时生成生产提醒。

            //创立Vue实例
            new Vue({
                el:'#demo', //el用于指定以后Vue实例为哪个容器服务,值通常为css选择器字符串。
                data:{ //data中用于存储数据,数据供el所指定的容器去应用,值咱们临时先写成一个对象。
                    name:'atguigu',
                    address:'北京'
                }
            })

        </script>
    </body>

1、Vue的模板语法

重点阐明

如果在标签中应用属性绑定值,是字符串,动静绑定则是会去解析表达式。例如

//字符串 
<h1 value="1"></h1> 
//动静绑定是解析表达式 数字1
 <h1 :value="1"></h1> 
Vue模板语法有2大类:
            1.插值语法:
                    性能:用于解析标签体内容
                    写法:{{xxxx}},xxx会作为表达式去解析,且能够主动读取到data中的属性
            2.指令语法:
                    性能:用于解析标签(包含:标签属性、标签体内容、绑定事件.....)
                    举例:v-bind:href="xxxxxx" 或  简写为:
                    备注:Vue中有很多的指令,此处咱们只是拿v-bind举个例子
<body>
    <div id="root">
        <h2>插值语法</h2>
        <h4>{{msg}}</h4>
        <h4>{{msg.toUpperCase()}}</h4>
        <h2>指令语法</h2>
        <!-- 动态属性间接写 或者绑定应用v-bind后应用字符串 -->
        <a :href="'http://www.baidu.com'">动静绑定属性是字符串</a>
        <!-- 属性是动静的必须要应用v-bind:href="" 双引号中的内容是data中的变量-->
        <a v-bind:href="url">百度一下</a>
    </div>
    <script>      
        new Vue({           
            el:"#root", 
            data:{
                msg:"插值语法Insert",
                url:"http://www.baidu.com",
            },
        })
    </script>
</body>

2、数据绑定及双向绑定原理

Vue中有2种数据绑定的形式:
                    1.单向绑定(v-bind):数据只能从data流向页面。
                    2.双向绑定(v-model):数据不仅能从data流向页面,还能够从页面流向data。
                        备注:
                                1.双向绑定个别都利用在表单类元素上(如:input、select等)
                                2.v-model:value 能够简写为 v-model,因为v-model默认收集的就是value值。
 <div id="root">
        <p>{{msg}}</p>
       单项数据绑定(v-bind):<input type="text" :value="msg"><br>
       <!-- v-model:value="msg" 针对表单类元素-->
       双向数据绑定(v-model):<input type="text" v-model="msg"><br>
       双向数据绑定(v-model):<input type="text" v-model:value="msg">
    </div>
    <script>
        new Vue({
            el:"#root",
            data:{
                msg:"",
            }
        });

v-model的底层原理:

v-model指令在表单input、textarea、select等元素上创立双向数据绑定,实质是语法糖,v-model在外部为不同的输出元素应用不同的属性并抛出不同的事件:
    text和textarea元素应用value属性和input事件
    checkbox和radio应用checked属性和change事件
    select字段将value作为prop并将change作为事件
以input表单作为案例
<!-- v-model 的底层原理  通过vm.msg向input标签的value单向传递   反向传递:通过input事件对msg进行赋值 $event为事件的对象 target.value获取输出的值-->
   
        <!-- :value动静绑定value值  触发input事件 -->
       <input type="text" v-bind:value="msg" v-on:input="msg=$event.target.value">
       <textarea  cols="30" rows="10" :value="msg" @input='msg=$event.target.value'></textarea>
       <!-- :checked动静绑定 触发change事件 -->
        <input type="checkbox" :checked='msg' @change="msg=$event.target.value">
        <input type="radio" :checked='msg' @change="msg=$event.target.value">
        <input type="radio" :checked='!msg' @change="msg=!$event.target.value">

        <!-- :value值  触发change事件 -->
        <select :value="msg" @change="msg=$event.target.value">
            <option value="0">0</option>
            <option value="1">1</option>
        </select>
    </div>
    <script>
        var app = new Vue({
            el:"#app",
            data:{
                msg:"",
            },

如果在自定义组件中,v-model默认会利用名为value的prop和名为input的事件

<div id="app">
        <p>{{msg}}</p>
        <!-- 默认是给my-input 动静绑定value值  并增加一个input事件 -->
        <!-- <my-input :value="msg" v-on:input="msg=$event"></my-input> -->
        <my-input v-model="msg"></my-input>
    </div>
    

    <script>
        Vue.component("my-input",{
            props:["value"],
            template:`
            <div>
                <p>我是组件</p>
                <input type="text" :value="value" v-on:input="$emit('input',$event.target.value)">
            </div>
            `
        });
        var app =new Vue({
            el:"#app",
            data:{
                msg:"初始值",
            }
        })

3、data和el的两种写法

data与el的2种写法:
                    1.el有2种写法:
                            (1).new Vue时候间接传递el属性 ---- 罕用
                            (2).先new Vue 再通过vm.$mount('#root')指定el属性 ---- 不罕用 
                    //写template会代替el中的全部内容,替换时必须有根节点蕴含。如果没有template会默认el中的内容为渲染对象
                    2.data有2种写法:
                            (1).对象式: 非组件化编码时能够写对象,也能够写函数。
                            (2).函数式:组件化编码必须应用函数式的data,组件数据能够复用。
            Vue中的一个最最重要的准则:
                    由Vue所调用的函数,都不要写成箭头函数,一旦写了箭头函数,this就不对了(或者是undefined,或者是Window)
<script>
        // 第一种写法
        const vm = new Vue({
            el:"#root",
            data:{
                msg:"MVVM",
            },
        });       
        // 第二种写法
        const vm = new Vue({
             data(){
                return {
                    msg:"MVVM"
                }
            },
            template:`
            <div>
                <h1>{{msg}}</h1>    
            </div>
            `
        })
        vm.$mount('#root')
        
        setTimeout(()=>vm.msg="hello",1000)

        // data的第一种写法  对象
        // data的第二种写法  函数 返回一个对象(组件中写的多)
    </script>

4、MVVM模型

MVVM模型
                        1. M:模型(Model) :data中的数据
                        2. V:视图(View) :模板代码
                        3. VM:视图模型(ViewModel):Vue实例
            察看发现:
                        1.data中所有的属性,最初都呈现在了vm身上。
                        2.vm身上所有的属性 及 Vue原型上所有属性,在Vue模板中都能够间接应用。

5、数据代理

5.1 Object.defineProperty办法

Object.defineProperty() 办法会间接在一个对象上定义一个新属性,或者批改一个对象的现有属性,并返回此对象。

备注:该当间接在 Object 结构器对象上调用此办法,而不是在任意一个 Object 类型的实例上调用。

语法:Object.defineProperty(obj, prop, descriptor)

obj:要定义属性的对象

prop:要定义或批改的属性的名称或 Symbol

descriptor:要定义或批改的属性描述符,简写就是默认的value值。

描述符默认值汇总

  • 领有布尔值的键 configurableenumerable(调用Object.keys()获取不到) 和 writable 的默认值都是 false
  • 属性值和函数的键 valuegetset 字段的默认值为 undefined
        let _data = { msg: "小明" };
        let vm = {};
//通过对象办法给vm对象赋值属性msg
        Object.defineProperty(vm, "msg", {
            set(value) {
                // value值就是内部赋值的值
                console.log(value);
                // this指向vm对象
                console.log(this);
               // 调用一次进行赋值会有限递归
                this.msg = value;
            },
            get() {
                return _data.msg;
            }
        })

        vm.msg = "123"
<!-- 数据代理:通过一个对象代理对另一个对象中属性的操作(读/写)-->
        <script type="text/javascript" >
            let obj = {x:100}
            let obj2 = {y:200}
//通过Getter读取obj.x的值,批改obj2的新增x属性是,理论调用Setter是对obj.x的赋值
            Object.defineProperty(obj2,'x',{
                get(){
                    return obj.x
                },
                set(value){
                    obj.x = value
                }
            })
        </script>

5.2对于Vue中的数据代理:

1.什么是数据代理?
(1).配置对象data中的数据,会被收集到vm._data中,而后通过,Object.defineProperty让vm上领有data中所有的属性。
(2).当拜访vm的msg时,返回的是_data当中同名属性的值
(3).当批改vm的msg时,批改的是_data当中同名属性的值
2.为什么要数据代理?
为了更加不便的读取和批改_data中的数据,不做数据代理,就要:vm._data.xxx拜访数据
3.扩大思考?—— 为什么要先收集在_data中,而后再代理进来呢?
更高效的监督数据(间接收集到vm上会导致监督效率太低)
4.基本原理:
通过Object.defineProperty()把data对象中所有属性增加到vm上。
为每一个增加到vm上的属性,都指定一个getter/setter。
在getter/setter外部去操作(读/写)data中对应的属性。
vue底层,当data的数据变动,去更新dom,双向绑定dom元素的data变动也更新dom,实质是数据变动

验证data中的数据就是vm下的_data

 const data = {
      name: "尚硅谷",
      address: "宏福科技园",
    };

    const vm = new Vue({
      el: "#root",
      data
    });
//管制台上
vm._data === data //true

数据代理的原理

// 当初获取msg只能通过vm._data获取
// 如何实现通过vm.msg进行获取,将data下的键值挂载到vm下,每扭转data中msg的值,vm.msg也能同步扭转?

        // 模仿Vue实例下vm的_data参数对象,配置对象data中的数据,会被收集到vm._data中
        let _data = { msg: "小明" };
        // vm模仿Vue实例化的对象
        let vm = {};
        // 实现形式:为vm对象增加属性值
        Object.defineProperty(vm, "msg", {
            set(value) {
                // value值就是内部赋值的值
                console.log(value);
                // this指向vm对象
                console.log(this);
                //实现双向绑定 批改任意的一个值 两个都会产生扭转
                _data.msg=value;
            },
            get() {
                return _data.msg;
            }
        })
        // 内部扭转_data.msg的值
        _data.msg = "123"
        console.log(vm.msg);

6、事件处理

事件的根本应用:
                            1.应用v-on:xxx 或 @xxx 绑定事件,其中xxx是事件名;
                            2.事件的回调须要配置在methods对象中,最终会在vm上;
                            3.methods中配置的函数,不要用箭头函数!否则this就不是vm了;
                            4.methods中配置的函数,都是被Vue所治理的函数,this的指向是vm 或 组件实例对象;
                            5.@click="demo" 和 @click="demo($event)" 成果统一,但后者能够传参;

6.1事件的修饰符

Vue中的事件修饰符:

​ 1.prevent:阻止默认事件(罕用);

​ 2.stop:阻止事件冒泡(罕用);

​ 3.once:事件只触发一次(罕用);

​ 4.capture:应用事件的捕捉模式,默认是事件冒泡形式

​ 5.self:只有event.target是以后操作的元素时才触发事件;

​ 6.passive:事件的默认行为立刻执行,无需期待事件回调执行结束;

1.Vue中罕用的按键别名:

​ 回车 => enter

​ 删除 => delete (捕捉“删除”和“退格”键)

​ 退出 => esc

​ 空格 => space

​ 换行 => tab (非凡,必须配合keydown去应用)

​ 上 => up

​ 下 => down

​ 左 => left

​ 右 => right

​ 2.Vue未提供别名的按键,能够应用按键原始的key值去绑定,但留神要转为kebab-case(短横线命名)

​ 3.零碎润饰键(用法非凡):ctrl、alt、shift、meta

​ (1).配合keyup应用:按下润饰键的同时,再按下其余键,随后开释其余键,事件才被触发。

​ (2).配合keydown应用:失常触发事件。

​ 4.也能够应用keyCode去指定具体的按键(不举荐)

​ 5.Vue.config.keyCodes.自定义键名 = 键码,能够去定制按键别名

应用修饰符时,程序很重要;相应的代码会以同样的程序产生。因而,用 v-on:click.prevent.self 会阻止所有的点击,而 v-on:click.self.prevent 只会阻止对元素本身的点击。

不要把 .passive.prevent 一起应用,因为 .prevent 将会被疏忽,同时浏览器可能会向你展现一个正告。请记住,.passive 会通知浏览器你想阻止事件的默认行为

<div id="root">
        <h2>欢送来到{{school}}学习</h2>

        <!-- 绑定事件---规范形式 -->
        <button v-on:click="show1">点我提醒:信息1(v-on绑定)</button> <br /><br />

        <!-- 绑定事件---简写形式 -->
        <button @click="show1">点我提醒:信息1(@绑定)</button> <br /><br />

        <!-- 绑定事件---传递参数 -->
        <button @click="show2($event,666)">点我提醒:信息2 + 传递的参数</button> <br /><br />

        <!-- 绑定事件---阻止默认行为,prevent叫事件修饰符 -->
        <a href="https://www.baidu.com" @click.prevent="show3">点我提醒:信息3 (阻止默认行为)</a> <br /><br />

        <!-- 绑定事件---阻止冒泡,事件修饰符能够连写,且程序能够随便扭转 -->
        <div @click="show4">
            <a href="https://www.baidu.com" @click.stop.prevent="show4">点我提醒:信息4 (阻止冒泡)</a>
        </div><br />
                
                <!-- 只有event.target是以后操作的元素时才触发事件; 点击外面时不会触发外层事件,阻止冒泡 -->
            <div class="demo1" @click.self="showInfo">
                <button @click="showInfo">点我提示信息</button>
            </div>
//组合键
<input type="text" placeholder="按下回车提醒输出" @keydown.ctrl.13="showInfo">
        <!-- 键盘事件 -->
        <input @keyup.enter="show5" type="text" placeholder="按下回车提醒数据">
        <!-- <input @keyup.13="show5" type="text" placeholder="按下回车提醒数据"> -->
        <!-- <input @keyup.37="show5" type="text" placeholder="按下左箭头提醒数据"> -->
        <!-- <input @keyup.arrow-left="show5" type="text" placeholder="按下左箭头提醒数据"> -->
        <!-- <input @keyup.left="show5" type="text" placeholder="按下左箭头提醒数据"> -->
        <!-- <input @keyup.16="show5" type="text" placeholder="按下shift提醒数据"> -->

    </div>

    <script type="text/javascript">
        new Vue({
            el: '#root',
            data: { //配置数据
                school: '尚硅谷',
            },
            methods: { //用于配置办法
                show1(event) { //此处的show1肯定肯定不要写成箭头函数,否则this就是Window了
                    //console.log(this) //this是vm
                    //console.log('信息1',event.target.innerText)
                    alert('信息1')
                },
                show2(event, number) {
                    console.log(event)
                    alert('信息2---' + number)
                },
                show3(event) {
                    //event.preventDefault(); //靠程序员手动阻止默认行为
                    alert('信息3')
                },
                show4(event) {
                    // event.stopPropagation(); //靠程序员手动阻止冒泡
                    alert('信息4')
                },
                show5(event) {
                    // if(event.keyCode !== 13) return //靠程序员本人判断按键
                    // console.log(event.keyCode) //输入按键编码值
                    // console.log(event.key) //输入按键名称
                    alert(event.target.value)
                }
            }
        })
    </script>

7、计算属性computed和数据监督watch

7.1 计算属性

计算属性:

​ 1.定义:要用的属性不存在,要通过已有属性计算得来,默认是getter读取

​ 2.原理:底层借助了Objcet.defineproperty办法提供的getter和setter。

​ 3.get函数什么时候执行?

​ (1).首次读取时会执行一次。

​ (2).当依赖的数据产生扭转时会被再次调用。

​ 4.劣势:与methods实现相比,外部有缓存机制(复用),效率更高,调试不便。

​ 5.备注:

​ 1.计算属性最终会呈现在vm上,间接读取应用即可。

​ 2.如果计算属性要被批改,那必须写set函数去响应批改,且set中要引起计算时依赖的数据产生扭转。

姓名案例:

  1. 应用插值语法实现

    <div id="root">
                姓:<input type="text" v-model="firstName"> <br/>
                名:<input type="text" v-model="lastName"><br/>
                <span>全名:{{firstName + '-' + lastName}}</span>
            </div>
    
            <script type="text/javascript" >
                new Vue({
                    el:'#root',
                    data:{
                        firstName:'张',
                        lastName:'三'
                    }
                })
            </script>
  2. methods办法实现

            <div id="root">
                姓:<input type="text" v-model="firstName"> <br/>
                名:<input type="text" v-model="lastName"><br/>
                <span>全名:{{getFullName()}}</span>
            </div>
    
            <script type="text/javascript" >
                new Vue({
                    el:'#root',
                    data:{
                        firstName:'张',
                        lastName:'三'
                    },
                    methods:{
                        getFullName(){
                            console.log('getFullName被调用了')
                            return this.firstName + '-' + this.lastName
                        }
                    }
                })
            </script>
  3. computed办法实现

            <div id="root">
                姓:<input type="text" v-model="firstName"> <br/><br/>
                名:<input type="text" v-model="lastName"><br/><br/>
                <span>全名:{{fullName}}</span><br/><br/>
                全名: <input type="text" v-model="fullName">
            </div>
    
            <script type="text/javascript" >
                const vm = new Vue({
                    el:'#root',
                    data:{
                        firstName:'张',
                        lastName:'三',
                    },
                    computed:{
                        /* 
                            1.fullName是谁在调用?---Vue
                            2.fullName什么时候调用?首次渲染会调用、当依赖的属性值发生变化
                        */
                        //简写---相当与只指定了get,没有指定set   只能实现单向数据绑定由fullName--》全名的input
                        fullName(){ 
                            console.log('fullName')
                            return this.firstName + '-' + this.lastName
                        }
                        
                        //残缺写法----set和get都指定了   实现双向数据绑定
                        /* fullName:{
                            set(value){ //fullName被批改时set被调用,set中的this是vm,set会收到批改的值
                                const arr = value.split('-')
                                this.firstName = arr[0]
                                this.lastName = arr[1]
                            },
                            get(){ //fullName被读取时get被调用,get中的this是vm
                                console.log('get')
                                return this.firstName + '-' + this.lastName
                            }
                        } */
                    }
                })
                
                console.log(vm)
            </script>

methods和computed比照

        <div id="root">
            <h2>{{x}}</h2>
            <h2>{{y()}}</h2>
            <h2>{{z}}</h2>
            <button @click="y">点我调用y办法</button> <br/><br/>
            <button @click="y()">点我调用y办法</button> <br/><br/>
            展现x的值:<input type="text" v-model="x">
        </div>
        
        <script type="text/javascript" >
            const vm = new Vue({
                el:'#root', //指定vm为哪个容器服务
                data:{ //驱动页面显示的数据都放在这里
                    x:100 //x最终会通过数据代理的形式放在vm身上
                },
                methods:{ //所有用到的函数都配置在这里
                    y(){ //y间接被放在vm身上
                        console.log('y被调用了')
                        return 200
                    }
                },
                computed:{
                    z:{ //z间接被放在vm身上了
                        set(value){ //z的值被扭转时,set执行,set中的this是vm,set会收到批改的值
                            console.log('有人批改z了,批改的值为:',value)
                        },
                        get(){ //z的值被读取时,或z依赖的值发生变化时,get执行,get中的this是vm,前提是:页面中要用到z
                            console.log('get被调用了')
                            return this.x*1 +1
                        }
                    }
                }
            })

            console.log(vm)
        </script>

7.2 监督办法

  1. watch办法实现

    监督属性watch:
                1.当被监督的属性变动时, 回调函数主动调用, 进行相干操作
                2.属性必须存在,能力进行监督!!
                3.监督的两种写法:
                    (1).new Vue时传入watch配置
                    (2).通过vm.$watch监督
        深度监督:
                            (1).Vue中的watch默认不监测对象外部值的扭转(一层)。
                            (2).配置deep:true能够监测对象外部值扭转(多层)。
                    备注:
                            (1).Vue本身能够监测对象外部值的扭转,但Vue提供的watch默认不能够!
                            (2).应用watch时依据数据的具体构造,决定是否采纳深度监督。
    
    <div id="root">
       <input type="text" v-model="firstName"> <br>
       <input type="text" v-model="lastName"><br>
        <span>全名:{{fullName}}</span><br>
    </div>
    <script>
       const vm = new Vue({
           el:"#root",
           data:{
               firstName:'张',
               lastName:'三',
               fullName:''
           },
           watch:{
            /* 
                        1.watch中的firstName什么时候调用?data中的firstName被扭转的时调用
                        2.watch中的firstName的this是谁?---vm
            */
            // 监测姓-----精简写法
            //    firstName(newVal,oldVal){
            //        console.log('firstName被批改',newVal,oldVal);
            //        this.fullName = newVal+'-'+this.lastName;
            //    },
            //监测名-----精简写法
            //    lastName(newVal,oldVal){
            //        console.log('lastName被批改',newVal,oldVal);
            //        this.fullName=this.firstName+'-'+newVal
            //    },
            //监测姓-----残缺写法  
            //    残缺写法
               firstName:{
                   immediate:true,
                    handler(newVal,oldVal){
                        this.fullName=newVal+'-'+this.lastName
                    }
               }

           }

       });
       //监测名-----残缺写法
       vm.$watch('lastName',{
           immediate:true,//若immediate为true则handler在初始化时,就会调用一次,当前就看firstName的扭转了
           handler(newVal,oldVal){
               setTimeout(()=>{
                   this.fullName = this.firstName+'-'+newVal;
               },2000)
           },
           deep:true
       })
//简写
      vm.$watch('lastName',(newVal,oldVal)=>{
               setTimeout(()=>{
                   this.fullName = this.firstName+'-'+newVal;
               },2000)
           }
       })
    </script>
    computed和watch之间的区别:
        1.只有是computed能实现的性能,watch都能够实现
        2.watch能实现的性能,computed不肯定能实现,例如:watch能够进行异步操作
    备注:
        1.所有被Vue所调用(治理)的函数,都不要写箭头函数 ----- 例如:watch中的函数、computed中的函数
        2.所有不是被Vue所调(治理)的函数,都要写成箭头函数 --- 例如:定时器的回调、ajax的回调等等
        3.watch就是Vue给我提供的一个监测数据扭转的伎俩,至于数据产生扭转后,要做什么,得看具体的业务了逻辑。
            例如:
                须要新的值、旧的值作比拟,决定接下来要干什么
                不要值,只有数据扭转了,就要发申请等等

8、绑定款式

    绑定款式:
                    1. class款式
                                写法:class="xxx" xxx能够是字符串、对象、数组。
                                        字符串写法实用于:类名不确定,要动静获取。
                                        对象写法实用于:要绑定多个款式,个数不确定,名字也不确定。
                                        数组写法实用于:要绑定多个款式,个数确定,名字也确定,但不确定用不必。
                    2. style款式
                                :style="{fontSize: xxx}"其中xxx是动静值。
                                :style="[a,b]"其中a、b是款式对象。
<div id="root">
        <!-- class的字符串写法,类名不确定动静获取 -->
        <h2 class="box" :class="myStyle">{{title}}</h2>
        <!-- 对象 -->
        <h2 class="box" :class="{classB:hasB,classC:hasC}">{{title}}</h2>
        <!-- 三元 -->
        <h2 class="box" :class="hasB?'classB':''">{{title}}</h2>
        <!-- 数组 -->
        <h2 class="box" :class="[a,b,c]">{{title}}</h2>
        <!-- 绑定style -->
        <h2 class="box" :class="[a,b,c]" :style="{fontSize:size+'px'}">{{title}}</h2>
        <h2 class="box" :class="[a,b,c]" :style="obj">354563</h2>
        <h2 class="box" :class="[a,b,c]" :style="style">354563</h2>

    </div>
    <script>
        new Vue({
            el:"#root",
            data:{
                title:"2021-07-11",
                myStyle:'classA',
                hasB:true,
                hasC:true,
                a:"classA",
                b:"classB",
                c:"classC",
                size:40,
                style:"border:10px solid",
                obj:{
                    fontSize:"16px",
                    color:"blue",
                }

            }
        })
    </script>

9、条件渲染

条件渲染:
1.v-if
写法:
(1).v-if="表达式" 
(2).v-else-if="表达式"
(3).v-else="表达式"
实用于:切换频率较低的场景。
特点:不展现的DOM元素间接被移除。
留神:v-if能够和:v-else-if、v-else一起应用,但要求构造不能被“打断”。

2.v-show
写法:v-show="表达式"
实用于:切换频率较高的场景。
特点:不展现的DOM元素未被移除,仅仅是应用款式暗藏掉

3.备注:应用v-if的时,元素可能无奈获取到,而应用v-show肯定能够获取到。
<body>
    <div id="root">
        <h2>今天天气很{{isHot ? '酷热':'凉快'}}</h2>
        <button @click="isHot=!isHot">切换天气</button>
    <!-- v-show 条件渲染 -->
        <div v-show="isHot">
            <img src="https://s3.ax1x.com/2020/12/13/reC1IA.jpg" alt="">
            <span>倡议:心情天然就会凉</span>
        </div>
        <div v-show="!isHot">
            <img src="https://s3.ax1x.com/2020/12/13/reCaqg.jpg" alt="">
            <span>倡议:妈妈通知你要穿秋裤了</span>
        </div>

            <!-- v-if  v-else-if v-else 必须是间断的-->
        <div v-if="isHot">
                <img src="https://s3.ax1x.com/2020/12/13/reC1IA.jpg" alt=""><br/>
                <span>倡议:心情天然就会凉</span>
            </div>

        <div v-else>
                <img src="https://s3.ax1x.com/2020/12/13/reCaqg.jpg" alt=""><br/>
                <span>倡议:妈妈通知你要穿秋裤了</span>
            </div>

    </div>
    <script>
    const vm = new Vue({
            el:"#root",
            data:{
               isHot:true,

            }
        })
    </script>
</body>

10、列表渲染

10.1 根本列表

v-for指令:
                        1.用于展现列表数据
                        2.语法:v-for="(item, index) in xxx" :key="yyy"
                        3.可遍历:数组、对象、字符串(用的很少)、指定次数(用的很少)
<body>
    <div id="root">
        <!-- v-for遍历数组 -->
        <ul>
            <li v-for="(p,index) in persons" :key="p.id">{{p.name}}--{{p.sex}}--{{p.age}}</li>
        </ul>
        <!-- v-for遍历对象 -->
        <ol>
            <li v-for="(value,key) in car" :key="value">{{value}}</li>
        </ol>
        <!-- v-for遍历字符串 -->
        <ol>
            <li v-for="(value,index) in str" :key="value">{{value}}---{{index}}</li>
        </ol>
        <!-- v-for遍历数字 -->
        <ol>
            <li v-for="(value,index) in num" :key="value">{{value}}---{{index}}</li>
        </ol>
    </div>
    <script>
        const vm = new Vue({
            el: "#root",
            data: {
                persons: [{
                    id: '001',
                    name: '老刘',
                    age: 20,
                    sex: '男'
                },
                {
                    id: '002',
                    name: '老李',
                    age: 19,
                    sex: '女'
                },
                {
                    id: '003',
                    name: '老王',
                    age: 18,
                    sex: '男'
                },
                {
                    id: '004',
                    name: '老张',
                    age: 17,
                    sex: '女'
                },
                ],
                car: {
                    name: '飞驰c63',
                    price: '60万',
                    color: '灰色'
                },
                str: 'abcde',
                num:5,

            }
        })
    </script>
</body>

应用template进行v-for遍历:template会不显示

[v-forv-if 一起应用]:

当它们处于同一节点,v-for 的优先级比 v-if 更高,这意味着 v-if 将别离反复运行于每个 v-for 循环中

   <div id="app">
        <template v-for="n in 5">
            <p>{{n}}------你好</p>    
        </template>
    </div>    

    <script>
        var app = new Vue({
            el:"#app",
        });
    </script>

10.2 key的原理

面试题:react、vue中的key有什么作用?(key的外部原理)
                        
1. 虚构DOM中key的作用:
key是虚构DOM对象的标识,当数据发生变化时,Vue会依据【新数据】生成【新的虚构DOM】, 
随后Vue进行【新虚构DOM】与【旧虚构DOM】的差别比拟,比拟规定如下:

2.比照规定:
(1).旧虚构DOM中找到了与新虚构DOM雷同的key:
①.若虚构DOM中内容没变, 间接应用之前的实在DOM!
②.若虚构DOM中内容变了, 则生成新的实在DOM,随后替换掉页面中之前的实在DOM。

(2).旧虚构DOM中未找到与新虚构DOM雷同的key
创立新的实在DOM,随后渲染到到页面。

3. 用index作为key可能会引发的问题:
1. 若对数据进行:逆序增加、逆序删除等毁坏程序操作:
会产生没有必要的实在DOM更新 ==> 界面成果没问题, 但效率低。

2. 如果构造中还蕴含输出类的DOM:
会产生谬误DOM更新 ==> 界面有问题。

4. 开发中如何抉择key?:
1.最好应用每条数据的惟一标识作为key, 比方id、手机号、身份证号、学号等惟一值。
2.如果不存在对数据的逆序增加、逆序删除等毁坏程序操作,仅用于渲染列表用于展现,
应用index作为key是没有问题的。

如果input输入框不加key属性,input输入框会复用,呈现凌乱的景象

<div id="root">
            <!-- 遍历数组 -->
            <h2>人员列表(遍历数组)</h2>
            <button @click.once="add">增加一个老刘</button>
            <ul>
                <li v-for="(p,index) of persons" :key="index">
                    {{p.name}}-{{p.age}}
                    <input type="text">
                </li>
            </ul>
        </div>

        <script type="text/javascript">
            Vue.config.productionTip = false
            
            new Vue({
                el:'#root',
                data:{
                    persons:[
                        {id:'001',name:'张三',age:18},
                        {id:'002',name:'李四',age:19},
                        {id:'003',name:'王五',age:20}
                    ]
                },
                methods: {
                    add(){
                        const p = {id:'004',name:'老刘',age:40}
                        this.persons.unshift(p)
                    }
                },
            })
        </script>

10.3 列表过滤

<body>
    <!-- 
        想要对数据加工后再展现,且不想毁坏原数据,最好用计算属性。
    -->
    <!-- 筹备好一个容器-->
    <div id="root">
        <h2>人员列表</h2>
        <input v-model="keyWord" type="text" placeholder="请输出姓名">
        <ul>
            <li v-for="(p,index) in fmtPersons" :key="p.id">
                {{p.name}}--{{p.sex}}--{{p.age}}岁
            </li>
        </ul>
    </div>

    <script type="text/javascript">
        var app = new Vue({
            el: '#root',
            data: {
                keyWord: '',
                persons: [{
                        id: '001',
                        name: '马冬梅',
                        age: 35,
                        sex: '女'
                    },
                    {
                        id: '002',
                        name: '周冬雨',
                        age: 20,
                        sex: '女'
                    },
                    {
                        id: '003',
                        name: '周杰伦',
                        age: 41,
                        sex: '男'
                    },
                    {
                        id: '004',
                        name: '温兆伦',
                        age: 25,
                        sex: '男'
                    },
                ]
            },

            //应用computed过滤,劣势:不影响原数据
            computed: {
                //fmtPersons是挂载在Vue实例上的属性
                fmtPersons() {
                    const {
                        persons,
                        keyWord
                    } = this
                    return persons.filter(p => p.name.indexOf(keyWord) !== -1)
                }
            }

            //在watch批改原数据,会导致原数据的失落
            /* watch:{
                keyWord(value){
                    const arr = this.persons.filter( p => p.name.indexOf(value) !== -1)
                    this.persons = arr
                }
            } */
        })
    </script>

显示过滤排序后的后果

1、能够应用计算属性
2、应用办法v-for=‘item in set(data)’
<ul v-for="set in sets">
  <li v-for="n in even(set)">{{ n }}</li>
</ul>
//数组中嵌套数组不适宜应用计算属性
data: {
  sets: [[ 1, 2, 3, 4, 5 ], [6, 7, 8, 9, 10]]
},
methods: {
  even: function (numbers) {
    return numbers.filter(function (number) {
      return number % 2 === 0
    })
  }
}

10.4 列表排序

<body>
    <div id="root">
        <!-- 
        想要对数据加工后再展现,且不想毁坏原数据,最好用计算属性。
    -->
        <input type="text" v-model="keyWord" placeholder="请输出姓名">
        <button @click="sortType=1">年龄升序↑</button>
        <button @click="sortType=2">年龄降序↓</button>
        <button @click="sortType=0">原程序</button>
        <ul>
            <li v-for="(p,index) in fmtPersons" :key="p.id">
                {{p.name}}---{{p.sex}}---{{p.age}}
            </li>
        </ul>
    </div>
    <script>
        var vm = new Vue({
            el:"#root",
           
            data:{
                keyWord:'',
                sortType:0, //0原程序 1升序 2降序
                persons: [{
                        id: '001',
                        name: '马冬梅',
                        age: 35,
                        sex: '女'
                    },
                    {
                        id: '002',
                        name: '周冬雨',
                        age: 20,
                        sex: '女'
                    },
                    {
                        id: '003',
                        name: '周杰伦',
                        age: 41,
                        sex: '男'
                    },
                    {
                        id: '004',
                        name: '温兆伦',
                        age: 25,
                        sex: '男'
                    },
                ]
            },
            computed:{
                fmtPersons(){
                    // 1.获取data中的数据
                    const {
                        persons,
                        keyWord,
                        sortType
                    }=this;
                    // 2.依据关键词过滤
                    let arr = persons.filter(p=>p.name.indexOf(keyWord)!==-1)

                    // 3.按须要排序为0时不进行排序
                    if(sortType){
                        arr.sort((a,b)=>{
                            // 排序时进行判断如果为1则升序
                            if(sortType===1){
                                return a.age-b.age;
                            //为2进行降序 
                            }else{
                                return b.age-a.age;
                            }
                        })
                    }
                    return arr;
                }
            },
        });
    </script>
</body>

10.5 列表更新的问题

v-for 遍历数组或对象,VUE无奈监测数组或对象中的值的变动,失常状况批改数组元素的值,vue不能动静的更新。起因是:简单数据类型保留的是对象的援用,当扭转对象的键或值,对象的援用并没有发生变化。
vue对于数组的办法作出一层封装,能够扭转原数组的办法,vue是能够监测到变动,有push pop  shift unshift reverse splice sort
对于非变更的办法,如filter concat slice 返回新数组 将新的值赋给原数组即可
// 管制台上间接批改app.list[]元素,不会动静刷新
            // 解决方案
            // 1.调用splice办法,Vue进行包裹可间接动静刷新
            // 2.调用$forceUpdate()办法强制进行刷新
            // 3.Vue.set(app.list,indexOf,newValue)
            // 4.app.$set(app.list,indexOf,newValue)
<body>
    <!-- 
        Vue数据绑定的原理
            1. vue会监督data中所有档次对象的属性
            2. 对象中的属性数据通过增加set办法来来实现监督
            3. 数组中也实现了监督: 重写数组一系列更新元素的办法,做了两件事:
                1).调用原生对应的办法对数组进行解决
                2).去更新界面
    -->
    <!-- 筹备好一个容器-->
    <div id="root">
        <h2>人员列表</h2>
        <input v-model="keyWord" type="text" placeholder="请输出姓名">
        <button @click="sortType = 1">年龄升序↓</button>
        <button @click="sortType = 2">年龄降序↓</button>
        <button @click="sortType = 0">原程序</button>
        <button @click="updateMei">更改马冬梅的信息</button>
        <ul>
            <li v-for="(p,index) in fmtPersons" :key="p.id">
                {{p.name}}--{{p.sex}}--{{p.age}}岁
            </li>
        </ul>
    </div>

    <script type="text/javascript">
        const vm = new Vue({
            el: '#root',
            data: {
                keyWord: '',
                sortType: 0, //0原程序 1升序  2降序
                persons: [{
                        id: '001',
                        name: '马冬梅',
                        age: 35,
                        sex: '女',
                        a: {
                            b: {
                                c: {
                                    d: {
                                        e: 1
                                    }
                                }
                            }
                        }
                    },
                    {
                        id: '002',
                        name: '周冬雨',
                        age: 20,
                        sex: '女'
                    },
                    {
                        id: '003',
                        name: '周杰伦',
                        age: 41,
                        sex: '男'
                    },
                    {
                        id: '004',
                        name: '温兆伦',
                        age: 25,
                        sex: '男'
                    },
                ]
            },

            methods: {
                updateMei() {
                    console.log(this)
                    // 为每个属性增加了get set函数 
                    // this.persons[0].name = '小佩奇' //代码见效
                    // this.persons[0].age = 99 //代码见效
                    // this.persons[0].sex = '男' //代码见效
                    this.persons[0] = {
                        name: '小佩奇',
                        age: 99,
                        sex: '男'
                    } //不见效
                }
            },

            //应用computed过滤,劣势:不影响原数据
            computed: {
                fmtPersons() {
                    const {
                        persons,
                        keyWord,
                        sortType
                    } = this
                    //依据关键词过滤
                    let arr = persons.filter(p => p.name.indexOf(keyWord) !== -1)
                    //若须要排序
                    if (sortType) {
                        //排序
                        arr.sort((a, b) => {
                            if (sortType === 1) return a.age - b.age
                            else return b.age - a.age
                        })
                    }
                    return arr
                }
            }

        })
    </script>
</body>

10.6 模仿数据监测

<script type="text/javascript">
        // 1.data中创立的数据 
        let data = {
            name: 'fyl',
            age: 18
        }
        // 2.创立一个监督的实例对象,用于监督data中属性的变动
        const obs = new Observer(data)
        console.log(obs);

        // 3.筹备一个vm实例化对象,收集实例化下的data放入_data中,而后再挂在到vm上
        let vm = {}
        // data领有get set 下次应用vm._data扭转,理论扭转data的数据,去解析
        vm._data = data = obs

        //4.类
        function Observer(obj) {
            //汇总对象中所有的属性造成一个数组
            const keys = Object.keys(obj)
            // 遍历加上getter和setter
            keys.forEach(k => {
                Object.defineProperty(this, k, {
                    get() {
                        return obj[k]
                    },
                    set(newVal) {
                        console.log(`obj的${k}被批改了,我要去解析模板,生成虚构DOM`);
                        obj[k] = newVal
                    }
                })
            })
        }
</script>

10.7 Vue.set的应用

向响应式对象中增加一个 property,并确保这个新 property 同样是响应式的,且触发视图更新。它必须用于向响应式对象上增加新 property,因为 Vue 无奈探测一般的新增 property (比方 this.myObject.newProperty = 'hi')

留神对象不能是 Vue 实例,或者 Vue 实例的根数据对象。
this.student.sex = '女' //间接应用不是响应式
//两种形式
Vue.set(this.student,'sex','男')
this.$set(this.student,'sex','男')

10.8 总结Vue数据监测

Vue监督数据的原理:
                1. vue会监督data中所有档次的数据。

                2. 如何监测对象中的数据?
                                通过setter实现监督,且要在new Vue时就传入要监测的数据。
                                    (1).对象中后追加的属性,Vue默认不做响应式解决
                                    (2).如需给后增加的属性做响应式,请应用如下API:
                                                    Vue.set(target,propertyName/index,value) 或 
                                                    vm.$set(target,propertyName/index,value)

                3. 如何监测数组中的数据?
                                    通过包裹数组更新元素的办法实现,实质就是做了两件事:
                                        (1).调用原生对应的办法对数组进行更新。
                                        (2).从新解析模板,进而更新页面。

                4.在Vue批改数组中的某个元素肯定要用如下办法:
                            1.应用这些API:push()、pop()、shift()、unshift()、splice()、sort()、reverse()
                            2.Vue.set() 或 vm.$set()   (对象,数组的索引,增加索引的内容)
                        
                
                特地留神:Vue.set() 和 vm.$set() 不能给vm 或 vm的根数据对象 增加属性!!!

11、收集表单信息

收集表单数据:
                    若:<input type="text"/>,则v-model收集的是value值,用户输出的就是value值。
                    若:<input type="radio"/>,则v-model收集的是value值,且要给标签配置value值。 不加name属性也可
                    若:<input type="checkbox"/>
                            1.没有配置input的value属性,那么收集的就是checked(勾选 or 未勾选,是布尔值)
                            2.配置input的value属性:
                                    (1)v-model的初始值是非数组,那么收集的就是checked(勾选 or 未勾选,是布尔值)
                                    (2)v-model的初始值是数组,那么收集的的就是value组成的数组
                    备注:v-model的三个修饰符:
                                    lazy:失去焦点再收集数据
                                    number:输出字符串转为无效的数字
                                    trim:输出首尾空格过滤
<body>
    <!-- 筹备好一个容器-->
    <div id="root">
        <form @submit.prevent="submit">
            账号:<input type="text" v-model="userInfo.account">
            <br /><br />
            明码:<input type="password" v-model="userInfo.password">
            <br /><br />
            性别:男<input type="radio" name="sex" v-model="userInfo.sex" value="male">
            女<input type="radio" name="sex" v-model="userInfo.sex" value="female">
            <br /><br />
            喜好:抽烟 <input type="checkbox" v-model="userInfo.hobby" value="smoke">
            喝酒 <input type="checkbox" v-model="userInfo.hobby" value="drink">
            开车 <input type="checkbox" v-model="userInfo.hobby" value="drive">
            <br /><br />
            所属校区:<select v-model="userInfo.city">
                <option value="">请抉择校区</option>
                <option value="beijing">北京</option>
                <option value="shanghai">上海</option>
                <option value="shenzhen">深圳</option>
                <option value="wuhan">武汉</option>
            </select>
            <br /><br />
            其余信息:<textarea v-model="userInfo.other" cols="30" rows="10"></textarea>
            <br /><br />
            <input v-model="userInfo.agree" type="checkbox">浏览并承受<a href="http://www.atguigu.com">《用户协定》</a>
            <br /><br />
            <button>提交</button>
        </form>
    </div>

    <script type="text/javascript">
        new Vue({
            el: '#root',
            data: {
                userInfo: {
                    account: '',
                    password: '',
                    sex: '',
                    hobby: [],
                    city: '',
                    other: '',
                    agree: false,
                }
            },
            methods: {
                submit() {
                    console.log(this.userInfo)
                }
            }
        })
    </script>
</body>

12、过滤器

过滤器:
    定义:对要显示的数据进行特定格式化后再显示(实用于一些简略逻辑的解决)。
    语法:
        1.注册过滤器:Vue.filter(name,callback) 或 new Vue{filters:{}}
        2.应用过滤器:{{ xxx | 过滤器名}}  或  v-bind:属性 = "xxx | 过滤器名"
    备注:
        1.过滤器也能够接管额定参数、多个过滤器也能够串联(如time | timeFormater('YYYY_MM_DD') | mySlice)
        2.并没有扭转本来的数据, 是产生新的对应的数据
        3.部分有,优先应用部分过滤器
<div id="root">
            <h2>显示格式化后的工夫</h2>
            <!-- 计算属性实现 -->
            <h3>当初是:{{fmtTime}}</h3>
            <!-- methods实现 -->
            <h3>当初是:{{getFmtTime()}}</h3>
            <!-- 过滤器实现 -->
            <h3>当初是:{{time | timeFormater}}</h3>
            <!-- 过滤器实现(传参) -->
            <h3>当初是:{{time | timeFormater('YYYY_MM_DD') | mySlice}}</h3>
            <h3 :x="msg | mySlice">尚硅谷</h3>
        </div>
        <div id="root2">
            <h2>{{msg | mySlice}}</h2>
        </div>
    </body>
    <script type="text/javascript">
        Vue.config.productionTip = false
        //全局过滤器
        Vue.filter('mySlice',function(value){
            return value.slice(0,4)
        })
        
        new Vue({
            el:'#root',
            data:{
                time:1621561377603, //工夫戳
                msg:'你好,尚硅谷'
            },
            computed: {
                fmtTime(){
                    return dayjs(this.time).format('YYYY年MM月DD日 HH:mm:ss')
                }
            },
            methods: {
                getFmtTime(){
                    return dayjs(this.time).format('YYYY年MM月DD日 HH:mm:ss')
                }
            },
            //部分过滤器
            filters:{
                timeFormater(value,str='YYYY年MM月DD日 HH:mm:ss'){
                    // console.log('@',value)
                    return dayjs(value).format(str)
                }
            }
        })
        new Vue({
            el:'#root2',
            data:{
                msg:'hello,atguigu!'
            }
        })
    </script>

13、内置指令及自定义指令

13.1 内置指令

    罕用内置指令
        v-text     :  更新元素的 innerText   相似于插值 
            1.作用:向其所在的节点中渲染文本内容。
            2.与插值语法的区别:v-text会替换掉节点中的内容,{{xx}}则不会。
         v-html :  更新元素的 innerHTML  内容按一般 HTML 插入 - 不会作为 Vue 模板进行编译
             1.作用:向指定节点中渲染蕴含html构造的内容。
             2.与插值语法的区别:
                (1).v-html会替换掉节点中所有的内容,{{xx}}则不会。
                 (2).v-html能够辨认html构造。
             3.重大留神:v-html有安全性问题!!!!
                (1).在网站上动静渲染任意HTML是十分危险的,容易导致XSS攻打。
                (2).肯定要在可信的内容上应用v-html,永不要用在用户提交的内容上!
         v-cloak :这个指令放弃在元素上直到关联实例完结编译(没有值)
             1.实质是一个非凡属性,Vue实例创立结束并接管容器后,会删掉v-cloak属性。
            2.应用css配合v-cloak能够解决网速慢时页面展现出{{xxx}}的问题。
        v-once指令:
             1.v-once所在节点在首次动静渲染后,就视为动态内容了。
             2.当前数据的扭转不会引起v-once所在构造的更新,能够用于优化性能。
         v-pre指令:
            1.跳过其所在节点的编译过程。
            2.可利用它跳过:没有应用指令语法、没有应用插值语法的节点,会放慢编译。
         v-if     :  条件渲染(动态控制节点是否存在)
         v-else :  条件渲染(动态控制节点是否存在)
         v-else-if:
         v-show :  条件渲染 (动态控制display)
         v-for  :  遍历数组/对象
         v-on   :  绑定事件监听, 可简写为@   修饰符
         v-bind:xxx : 强制绑定解析表达式, 可简写为 :xxx  修饰符
         v-model: 双向数据绑定  修饰符 .lazy .number .trim
         v-slot(#) : 插槽名
<style>
    [v-cloak]{
        display:none;
    }
</style>
        <!-- 引入Vue -->
    </head>
    <body>
        <!-- 
                v-cloak指令(没有值):
                        1.实质是一个非凡属性,Vue实例创立结束并接管容器后,会删掉v-cloak属性。
                        2.应用css配合v-cloak能够解决网速慢时页面展现出{{xxx}}的问题。
        -->
        <!-- 筹备好一个容器-->
        <div id="root">
            <h2 v-cloak>{{name}}</h2>
        </div>
        <script type="text/javascript" src="http://localhost:8080/resource/5s/vue.js"></script>
    </body>
    
    <script type="text/javascript">
        console.log(1)
        Vue.config.productionTip = false //阻止 vue 在启动时生成生产提醒。
        
        new Vue({
            el:'#root',
            data:{
                name:'尚硅谷'
            }
        })
    </script>

13.2 自定义指令

    需要1:定义一个v-big指令,和v-text性能相似,但会把绑定的数值放大10倍。
    需要2:定义一个v-fbind指令,和v-bind性能相似,但能够让其所绑定的input元素默认获取焦点。
    自定义指令总结:
    一、定义语法:
        (1).部分指令:                                                                                                    new Vue({directives:{指令名:配置对象} })  或  new Vue({    directives{指令名:回调函数}})                          (2).全局指令:
                Vue.directive(指令名,配置对象) 或   Vue.directive(指令名,回调函数)
        留神:配置对象应用函数的写法,默认是bind和update外面的内容
    二、配置对象中罕用的3个回调:
        (1).bind:指令与元素胜利绑定时调用。
        (2).inserted:指令所在元素被插入页面时调用。
        (3).update:指令所在模板构造被从新解析时调用。
        不必 (4)componentUpdated:指令所在组件的 VNode 及其子 VNode 全副更新后调用。
        不必 (5)unbind:只调用一次,指令与元素解绑时调用。
    三、备注:
        1.指令定义时不加v-,但应用时要加v-;多个单词用v-big-number
        2.指令名如果是多个单词,要应用kebab-case命名形式,不要用camelCase命名。指令名多个单词用双引号
<div id="root">
        <h2>{{name}}</h2>
        <h2>以后的n值是:<span v-text="n"></span> </h2>
        <!-- <h2>放大10倍后的n值是:<span v-big-number="n"></span> </h2> -->
        <h2>放大10倍后的n值是:<span v-big="n"></span> </h2>
        <button @click="n++">点我n+1</button>
        <hr />
        <input type="text" v-fbind:value="n">
    </div>
</body>

<script type="text/javascript">
    Vue.config.productionTip = false

    //定义全局指令
    /* Vue.directive('fbind',{
        //指令与元素胜利绑定时(一上来)
        bind(element,binding){
            element.value = binding.value
        },
        //指令所在元素被插入页面时
        inserted(element,binding){
            element.focus()
        },
        //指令所在的模板被从新解析时
        update(element,binding){
            element.value = binding.value
        }
    }) */

    new Vue({
        el: '#root',
        data: {
            name: '尚硅谷',
            n: 1
        },
        directives: {
            //big函数何时会被调用?1.指令与元素胜利绑定时(一上来)。2.指令所在的模板被从新解析时。
            /* 'big-number'(element,binding){
                // console.log('big')
                element.innerText = binding.value * 10
            }, */
            big(element, binding) {
                console.log('big', this) //留神此处的this是window
                // console.log('big')
                element.innerText = binding.value * 10
            },
            fbind: {
                //指令与元素胜利绑定时(一上来)
                bind(element, binding) {
                    element.value = binding.value
                },
                //指令所在元素被插入页面时
                inserted(element, binding) {
                    element.focus()
                },
                //指令所在的模板被从新解析时
                update(element, binding) {
                    element.value = binding.value
                }
            },
            // fbind:{
            //     // 只调用一次,指令第一次绑定到元素时调用。在这里能够进行一次性的初始化设置。
            //     bind(el,binding,vnode,oldVnode){
            //         // 指令所绑定的元素,能够用来间接操作 DOM
            //         console.log(el);
            //         // 一个对象
            //         console.log(binding);
            //         // Vue 编译生成的虚构节点。
            //         console.log(vnode);
            //         // 上一个虚构节点
            //         console.log(oldVnode);
            //         el.value = binding.value
            //     },
            //     // 被绑定元素插入父节点时调用 (仅保障父节点存在,但不肯定已被插入文档中)。
            //     inserted(el){
            //         el.focus()
            //     },
            //     // 所在组件的 VNode 更新时调用,然而可能产生在其子 VNode 更新之前。
            //     update(el,binding){
            //         el.value = binding.value
            //     },
            // 指令所在组件的 VNode 及其子 VNode 全副更新后调用。
            // componentUpdated() {

            // },
            // 只调用一次,指令与元素解绑时调用。
            // unbind() {

            // }
            // }
        }
    })

14、生命周期

罕用的生命周期钩子:
                        1.mounted: 发送ajax申请、启动定时器、绑定自定义事件、订阅音讯等【初始化操作】。
                        2.beforeDestroy: 革除定时器、解绑自定义事件、勾销订阅音讯等【收尾工作】。

                对于销毁Vue实例
                        1.销毁后借助Vue开发者工具看不到任何信息。
                        2.销毁后自定义事件会生效,但原生DOM事件仍然无效。
                        3.个别不会在beforeDestroy操作数据,因为即使操作数据,也不会再触发更新流程了。

15、非单文件组件

以往是多个html文件有css和js文件,头部能够复制应用,不是很不便,可不可以通过导入的模式,间接应用。那么应用组件

组件:实现利用中部分性能代码和资源的汇合 .vue 很多组件

15.1 组件的根本应用

Vue中应用组件的三大步骤:
    一、定义组件(创立组件)
    二、注册组件
    三、应用组件(写组件标签)

    一、如何定义一个组件?
        应用Vue.extend(options)创立,其中options和new Vue(options)时传入的那个options简直一样,但也有点区别;
        区别如下:
            1.el不要写,为什么? ——— 最终所有的组件都要通过一个vm的治理,由vm中的el决定服务哪个容器。
            2.data必须写成函数,为什么? ———— 防止组件被复用时,数据存在援用关系。
        备注:应用template能够配置组件构造。

    二、如何注册组件?
        1.部分注册:靠new Vue的时候传入components选项 Vue.extend({}) 或者间接写选项对象{},在components中会调用extend
        2.全局注册:靠Vue.component('组件名',组件)

    三、编写组件标签:
    <school></school>
<!-- 筹备好一个容器-->
        <div id="root">
            <hello></hello>
            <hr>
            <h1>{{msg}}</h1>
            <hr>
            <!-- 第三步:编写组件标签 -->
            <school></school>
            <hr>
            <!-- 第三步:编写组件标签 -->
            <student></student>
        </div>

        <div id="root2">
            <hello></hello>
        </div>
    </body>

    <script type="text/javascript">
        Vue.config.productionTip = false

        //第一步:创立school组件
        const school = Vue.extend({
            template:`
                <div class="demo">
                    <h2>学校名称:{{schoolName}}</h2>
                    <h2>学校地址:{{address}}</h2>
                    <button @click="showName">点我提醒学校名</button>    
                </div>
            `,
            // el:'#root', //组件定义时,肯定不要写el配置项,因为最终所有的组件都要被一个vm治理,由vm决定服务于哪个容器。
            data(){
                return {
                    schoolName:'尚硅谷',
                    address:'北京昌平'
                }
            },
            methods: {
                showName(){
                    alert(this.schoolName)
                }
            },
        })

        //第一步:创立student组件
        const student = Vue.extend({
            template:`
                <div>
                    <h2>学生姓名:{{studentName}}</h2>
                    <h2>学生年龄:{{age}}</h2>
                </div>
            `,
            data(){
                return {
                    studentName:'张三',
                    age:18
                }
            }
        })
        
        //第一步:创立hello组件
        const hello = Vue.extend({
            template:`
                <div>    
                    <h2>你好啊!{{name}}</h2>
                </div>
            `,
            data(){
                return {
                    name:'Tom'
                }
            }
        })
        
        //第二步:全局注册组件
        Vue.component('hello',hello)

        //创立vm
        new Vue({
            el:'#root',
            data:{
                msg:'你好啊!'
            },
            //第二步:注册组件(部分注册)
            components:{
                school,
                student
            }
        })

        new Vue({
            el:'#root2',
        })
    </script>

15.2 留神点

    几个留神点:
        1.对于组件名:
            一个单词组成:
                第一种写法(首字母小写):school
                第二种写法(首字母大写):School
        多个单词组成:
            第一种写法(kebab-case命名):my-school
            第二种写法(CamelCase命名):MySchool (须要Vue脚手架反对)
        备注:
            (1).组件名尽可能回避HTML中已有的元素名称,例如:h2、H2都不行。
            (2).能够应用name配置项指定组件在开发者工具中出现的名字。

        2.对于组件标签:
            第一种写法:<school></school>
            第二种写法:<school/>
            备注:不必应用脚手架时,<school/>会导致后续组件不能渲染。

        3.一个简写形式:
            const school = Vue.extend(options) 可简写为:const school = options

15.3 组件的嵌套

<body>
        <!-- 筹备好一个容器-->
        <div id="root">
            
        </div>
    </body>

    <script type="text/javascript">
        Vue.config.productionTip = false //阻止 vue 在启动时生成生产提醒。

        //定义student组件
        const student = Vue.extend({
            name:'student',
            template:`
                <div>
                    <h2>学生姓名:{{name}}</h2>    
                    <h2>学生年龄:{{age}}</h2>    
                </div>
            `,
            data(){
                return {
                    name:'尚硅谷',
                    age:18
                }
            }
        })
        
        //定义school组件
        const school = Vue.extend({
            name:'school',
            template:`
                <div>
                    <h2>学校名称:{{name}}</h2>    
                    <h2>学校地址:{{address}}</h2>    
                    <student></student>
                </div>
            `,
            data(){
                return {
                    name:'尚硅谷',
                    address:'北京'
                }
            },
            //注册组件(部分)
            components:{
                student
            }
        })

        //定义hello组件
        const hello = Vue.extend({
            template:`<h1>{{msg}}</h1>`,
            data(){
                return {
                    msg:'欢送来到尚硅谷学习!'
                }
            }
        })
        
        //定义app组件
        const app = Vue.extend({
            template:`
                <div>    
                    <hello></hello>
                    <school></school>
                </div>
            `,
            components:{
                school,
                hello
            }
        })

        //创立vm
        new Vue({
            template:'<app></app>',
            el:'#root',
            //注册组件(部分)
            components:{app}
        })
    </script>

15.3 VueComponent构造函数

对于VueComponent:
    1.school组件实质是一个名为VueComponent的构造函数,且不是程序员定义的,是Vue.extend调用生成的。

    2.咱们只须要写<school/>或<school></school>,Vue解析时会帮咱们创立school组件的实例对象,
    即Vue帮咱们执行的:new VueComponent(options)。

    3.特地留神:每次调用Vue.extend,返回的都是一个全新的VueComponent!!!!

    4.对于this指向:
        (1).组件配置中:
            data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【VueComponent实例对象】。
        (2).new Vue(options)配置中:
            data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【Vue实例对象】。

    5.VueComponent的实例对象,当前简称vc(也可称之为:组件实例对象)。
        Vue的实例对象,当前简称vm。

15.4 一个重要的内置关系 vc和vm的原型

    1.一个重要的内置关系:VueComponent.prototype.__proto__ === Vue.prototype
    2.为什么要有这个关系:让组件实例对象(vc)能够拜访到 Vue原型上的属性、办法。

16、单文件组件

    非单文件组件
    通过Vue.extend去注册组件,在new Vue中的components配置,间接在html中应用<school>
    不易复用,当初将功能模块拆分
    单文件组件
        vue文件 1.webpack解析  2.脚手架
        |-main.js  注册app组件 挂载app 应用template 注册app 配置template(<app/>) 不必在html中写<App/>
        |-App.vue   app中引入components中组件 注册 school和student
        |-index.html 引入main.js 和 Vue
        |-components |-student 
                    有template script export default const student = Vue.extend({})  可简写为 export default{}
                    |-school
    

17、剖析脚手架

    脚手架
    不应用render函数 在main.js中写

原先写法

html:
    <body>
        <!-- 筹备一个容器 -->
        <div id="root"></div>
        <script type="text/javascript" src="../js/vue.js"></script>
        <script type="text/javascript" src="./main.js"></script>
    </body>
main.js:
    import App from './App.vue'
    new Vue({
        el:'#root',
        template:`<App></App>`,
        components:{App},
    })
App.vue:
<template>
    <div>
        <School></School>
        <Student></Student>
    </div>
</template>
<script>
    //引入组件
    import School from './School.vue'
    import Student from './Student.vue'

    export default {
        name:'App',
        components:{
            School,
            Student
        }
    }
</script>

脚手架写法 短少模板解析器

只在main.js中写
//只引入了实时运行版的vue
//import Vue from 'vue'
//完整版的蕴含模板解析器 就能够运行
import Vue from 'vue/dist/vue'
import App from './App.vue'

Vue.config.productionTip = false

new Vue({
  // render: h => h(App),
  components:{App},
  template:`<App/>`
}).$mount('#app')

为什么:Vue = Vue外围(2/3) + 模板解析器(1/3) 所以用render进行渲染 打包后生成最终代码不须要模板解析器的局部

Vue 选项中的 render 函数若存在,则 Vue 构造函数不会从 template 选项或通过 el 选项指定的挂载元素中提取出的 HTML 模板编译渲染函数。

//引入Vue
import Vue from 'vue'
//引入App组件,它是所有组件的父组件
import App from './App.vue'
//敞开vue的生产提醒
Vue.config.productionTip = false

/* 
    对于不同版本的Vue:
    
        1.vue.js与vue.runtime.xxx.js的区别:
                (1).vue.js是完整版的Vue,蕴含:外围性能+模板解析器。
                (2).vue.runtime.xxx.js是运行版的Vue,只蕴含:外围性能;没有模板解析器。

        2.因为vue.runtime.xxx.js没有模板解析器,所以不能应用template配置项,须要应用
            render函数接管到的createElement函数去指定具体内容。
*/

//创立Vue实例对象---vm
new Vue({
    el:'#app',
    //render函数实现了这个性能:将App组件放入容器中   返回的是虚构dom
  render: h => h(App),
    // render:q=> q('h1','你好啊')

    // template:`<h1>你好啊</h1>`,
    // template:`<App/>`,
    // components:{App},
})

18、罕用办法

18.1 ref属性

ref在一般元素上就是实在的Dom节点
组件上就是组件的示例对象(vc)

18.2 props属性

prop承受的值切实data赋值之前

        //简略申明接管
        // props:['name','age','sex'] 

        //接管的同时对数据进行类型限度
        /* props:{
            name:String,
            age:Number,
            sex:String
        } */

        //接管的同时对数据:进行类型限度+默认值的指定+必要性的限度
        props:{
            name:{
                type:String, //name的类型是字符串
                required:true, //name是必要的
            },
            age:{
                type:Number,
                default:99 //默认值
            },
            sex:{
                type:String,
                required:true
            }
        }

18.3 混入Mixin

混入的形式 :办法本身有用本身的 生命周期是都会执行,混入的钩子会提前调用
还能够自定义混入
  1. 性能:能够把多个组件共用的配置提取成一个混入对象
  2. 应用形式:

    第一步定义混合:

    {
        data(){....},
        methods:{....}
        ....
    }

    第二步应用混入:

    ​ 全局混入:Vue.mixin(xxx)
    ​ 部分混入:mixins:['xxx']

18.4 插件

  1. 性能:用于加强Vue
  2. 实质:蕴含install办法的一个对象,install的第一个参数是Vue,第二个当前的参数是插件使用者传递的数据。

通过 install 办法给 Vue 或 Vue 实例增加办法, 定义全局指令 混入 过滤器

  1. 定义插件:
对象.install = function (Vue, options) {
    // 1. 增加全局过滤器
    Vue.filter(....)

    // 2. 增加全局指令
    Vue.directive(....)

    // 3. 配置全局混入(合)
    Vue.mixin(....)

    // 4. 增加实例办法
    Vue.prototype.$myMethod = function () {...}
    Vue.prototype.$myProperty = xxxx
}
  1. 应用插件:Vue.use()
import Vue from 'vue'
import loadingComponent from '@/components/Loading/index.vue'
//应用extend创立 组件的vc构造函数
const LoadingConstructor = Vue.extend(loadingComponent)
//实例化vc 挂载在div中
const instance = new LoadingConstructor({
  el: document.createElement('div')
})
//在实例中挂载属性
instance.show = false // 默认暗藏
// 组件中应用props接管
const loading = {
  show(txt = '') { // 显示办法
    instance.show = true
    instance.text = txt || '拼命加载中'
    document.body.appendChild(instance.$el)
  },
  hide() { // 暗藏办法
    instance.show = false
  }
}

export default {
 //install办法 有一个Vue形参 
  install() {
    if (!Vue.$loading) {
      Vue.$loading = loading
    }
  //通过混入 在created中 将实例化$loading 挂载在this上
    Vue.mixin({
      created() {
        this.$loading = Vue.$loading
      }
    })
  }
}

18.5 nextTick

  1. 语法:this.$nextTick(回调函数)
  2. 作用:在下一次 DOM 更新完结后执行其指定的回调。
  3. 什么时候用:当扭转数据后,要基于更新后的新DOM进行某些操作时,要在nextTick所指定的回调函数中执行。
//解析机会的问题  当this.isEdit数据变动,并没有立刻更新dom 而是执行完focus  所以必须在dom更新后进行执行
if(todo.hasOwnProperty('isEdit')){
                    todo.isEdit = true
                }else{
                    // console.log('@')
                    this.$set(todo,'isEdit',true)
                }
                this.$nextTick(function(){
                    this.$refs.inputTitle.focus()
                })

19、事件总线

main.js
    new Vue({
      render: h => h(App),
      beforeCreate(){
        Vue.prototype.$bus = this
      }
    }).$mount('#app')
绑定 触发 销毁
this.$bus.$on('name',callback=>{})
this.$bus.$emit('name',params)
 this.$bus.$off()全副敞开(name)

公布订阅pubsub.js

//首先是先订阅音讯hello, 定义触发的回调 第一个参数的回调的函数名,第二个是承受的数据
this.pubId = pubsub.subscribe('hello',(msgName,data)=>{
                console.log(this)
                // console.log('有人公布了hello音讯,hello音讯的回调执行了',msgName,data)
})
//发送数据方,须要公布音讯,触发回调
pubsub.publish('hello',666)
//勾销订阅 是勾销订阅号
pubsub.unsubscribe(this.pubId)

20、动画和适度

  1. 作用:在插入、更新或移除 DOM元素时,在适合的时候给元素增加款式类名。
  2. 图示:<img src=”https://img04.sogoucdn.com/app/a/100520146/5990c1dff7dc7a8fb3b34b4462bd0105″ style=”width:60%” />
  3. 写法:

    1. 筹备好款式:

      • 元素进入的款式:

        1. v-enter:进入的终点
        2. v-enter-active:进入过程中
        3. v-enter-to:进入的起点
      • 元素来到的款式:

        1. v-leave:来到的终点
        2. v-leave-active:来到过程中
        3. v-leave-to:来到的起点
    2. 应用<transition>包裹要适度的元素,并配置name属性:

      <transition name="hello">
          <h1 v-show="isShow">你好啊!</h1>
      </transition>
    3. 备注:若有多个元素须要适度,则须要应用:<transition-group>,且每个元素都要指定key值。
<transition-group name="hello" appear>
            <h1 v-show="!isShow" key="1">你好啊!</h1>
            <h1 v-show="isShow" key="2">尚硅谷!</h1>
</transition-group>

应用animate动画库

<transition-group 
            appear
            name="animate__animated animate__bounce" 
            enter-active-class="animate__swing"
            leave-active-class="animate__backOutUp"
        >
            <h1 v-show="!isShow" key="1">你好啊!</h1>
            <h1 v-show="isShow" key="2">尚硅谷!</h1>
</transition-group>

21、vue脚手架配置代理

办法一

​ 在vue.config.js中增加如下配置:

//如果本地存在则不会转发
devServer:{
  proxy:"http://localhost:5000"
}

阐明:

  1. 长处:配置简略,申请资源时间接发给前端(8080)即可。
  2. 毛病:不能配置多个代理,不能灵便的管制申请是否走代理。
  3. 工作形式:若依照上述配置代理,当申请了前端不存在的资源时,那么该申请会转发给服务器 (优先匹配前端资源)

办法二

​ 编写vue.config.js配置具体代理规定:

module.exports = {
    devServer: {
      proxy: {
      '/api1': {// 匹配所有以 '/api1'结尾的申请门路
        target: 'http://localhost:5000',// 代理指标的根底门路
        changeOrigin: true,
        pathRewrite: {'^/api1': ''}//将申请地址中的api1替换为空
      },
      '/api2': {// 匹配所有以 '/api2'结尾的申请门路
        target: 'http://localhost:5001',// 代理指标的根底门路
        changeOrigin: true,
        pathRewrite: {'^/api2': ''}
      }
    }
  }
}
/*
   changeOrigin设置为true时,服务器收到的申请头中的host为:localhost:5000
   changeOrigin设置为false时,服务器收到的申请头中的host为:localhost:8080
   changeOrigin默认值为true
*/

阐明:

  1. 长处:能够配置多个代理,且能够灵便的管制申请是否走代理。
  2. 毛病:配置稍微繁琐,申请资源时必须加前缀。

代码申请写法:

axios.get('http://localhost:8080/demo/cars')  
//vue.config.js
'/demo': {
        target: 'http://localhost:5001',
        pathRewrite:{'^/demo':''},
        // ws: true, //用于反对websocket
        // changeOrigin: true //用于管制申请头中的host值  true:host值不是理论的
}
//申请本地服务器,会转换撑localhost:5001/cars

22、插槽

  1. 作用:让父组件能够向子组件指定地位插入html构造,也是一种组件间通信的形式,实用于 父组件 ===> 子组件
  2. 分类:默认插槽、具名插槽、作用域插槽
  3. 应用形式:

    1. 默认插槽:

      父组件中:
              <Category>
                 <div>html构造1</div>
              </Category>
      子组件中:
              <template>
                  <div>
                     <!-- 定义插槽 -->
                     <slot>插槽默认内容...</slot>
                  </div>
              </template>
    2. 具名插槽:

      父组件中:
              <Category>
                  <template slot="center">
                    <div>html构造1</div>
                  </template>
      
                  <template v-slot:footer>
                     <div>html构造2</div>
                  </template>
              </Category>
      子组件中:
              <template>
                  <div>
                     <!-- 定义插槽 -->
                     <slot name="center">插槽默认内容...</slot>
                     <slot name="footer">插槽默认内容...</slot>
                  </div>
              </template>
    3. 作用域插槽:

      1. 了解:<span style=”color:red”>数据在组件的本身,但依据数据生成的构造须要组件的使用者来决定。</span>(games数据在Category组件中,但应用数据所遍历进去的构造由App组件决定)
      2. 具体编码:

        在slot上绑定属性,能够在父组件中应用子组件的数据 ,承受形式:

        scope=“”

        slot-scope=””

        能够构造赋值

        v-slot:default=””

        default=””

        父组件中:
                <Category>
                    <template scope="scopeData">
                        <!-- 生成的是ul列表 -->
                        <ul>
                            <li v-for="g in scopeData.games" :key="g">{{g}}</li>
                        </ul>
                    </template>
                </Category>
        
                <Category>
                    <template slot-scope="scopeData">
                        <!-- 生成的是h4题目 -->
                        <h4 v-for="g in scopeData.games" :key="g">{{g}}</h4>
                    </template>
                </Category>
        子组件中:
                <template>
                    <div>
                        <slot :games="games"></slot>
                    </div>
                </template>
                
                <script>
                    export default {
                        name:'Category',
                        props:['title'],
                        //数据在子组件本身
                        data() {
                            return {
                                games:['红色警戒','穿梭前线','劲舞团','超级玛丽']
                            }
                        },
                    }
                </script>

23、Vuex

1.概念

​ 在Vue中实现集中式状态(数据)治理的一个Vue插件,对vue利用中多个组件的共享状态进行集中式的治理(读/写),也是一种组件间通信的形式,且实用于任意组件间通信。

2.何时应用?

​ 多个组件须要共享数据时

3.搭建vuex环境

  1. 创立文件:src/store/index.js

    //引入Vue外围库
    import Vue from 'vue'
    //引入Vuex
    import Vuex from 'vuex'
    //利用Vuex插件
    Vue.use(Vuex)
    
    //筹备actions对象——响应组件中用户的动作
    const actions = {}
    //筹备mutations对象——批改state中的数据
    const mutations = {}
    //筹备state对象——保留具体的数据
    const state = {}
    
    //创立并裸露store
    export default new Vuex.Store({
        actions,
        mutations,
        state
    })
  2. main.js中创立vm时传入store配置项

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

4.根本应用

  1. 初始化数据、配置actions、配置mutations,操作文件store.js

    //引入Vue外围库
    import Vue from 'vue'
    //引入Vuex
    import Vuex from 'vuex'
    //援用Vuex
    Vue.use(Vuex)
    
    const actions = {
        //响应组件中加的动作
        jia(context,value){
            // console.log('actions中的jia被调用了',miniStore,value)
            context.commit('JIA',value)
        },
    }
    
    const mutations = {
        //执行加
        JIA(state,value){
            // console.log('mutations中的JIA被调用了',state,value)
            state.sum += value
        }
    }
    
    //初始化数据
    const state = {
       sum:0
    }
    
    //创立并裸露store
    export default new Vuex.Store({
        actions,
        mutations,
        state,
    })
  2. 组件中读取vuex中的数据:$store.state.sum
  3. 组件中批改vuex中的数据:$store.dispatch('action中的办法名',数据)$store.commit('mutations中的办法名',数据)

    备注:若没有网络申请或其余业务逻辑,组件中也能够越过actions,即不写dispatch,间接编写commit

5.getters的应用

  1. 概念:当state中的数据须要通过加工后再应用时,能够应用getters加工。
  2. store.js中追加getters配置

    ......
    
    const getters = {
        bigSum(state){
            return state.sum * 10
        }
    }
    
    //创立并裸露store
    export default new Vuex.Store({
        ......
        getters
    })
  3. 组件中读取数据:$store.getters.bigSum

6.四个map办法的应用

  1. mapState办法:用于帮忙咱们映射state中的数据为计算属性

    computed: {
        //借助mapState生成计算属性:sum、school、subject(对象写法)
         ...mapState({sum:'sum',school:'school',subject:'subject'}),
             
        //借助mapState生成计算属性:sum、school、subject(数组写法)
        ...mapState(['sum','school','subject']),
    },
  2. mapGetters办法:用于帮忙咱们映射getters中的数据为计算属性

    computed: {
        //借助mapGetters生成计算属性:bigSum(对象写法)
        ...mapGetters({bigSum:'bigSum'}),
    
        //借助mapGetters生成计算属性:bigSum(数组写法)
        ...mapGetters(['bigSum'])
    },
  3. mapActions办法:用于帮忙咱们生成与actions对话的办法,即:蕴含$store.dispatch(xxx)的函数

    methods:{
        //靠mapActions生成:incrementOdd、incrementWait(对象模式)
        ...mapActions({incrementOdd:'jiaOdd',incrementWait:'jiaWait'})
    
        //靠mapActions生成:incrementOdd、incrementWait(数组模式)
        ...mapActions(['jiaOdd','jiaWait'])
    }
  4. mapMutations办法:用于帮忙咱们生成与mutations对话的办法,即:蕴含$store.commit(xxx)的函数,传参写在事件后@click=xxx(data)

    methods:{
        //靠mapActions生成:increment、decrement(对象模式)
        ...mapMutations({increment:'JIA',decrement:'JIAN'}),
        
        //靠mapMutations生成:JIA、JIAN(对象模式)
        ...mapMutations(['JIA','JIAN']),
    }

备注:mapActions与mapMutations应用时,若须要传递参数须要:在模板中绑定事件时传递好参数,否则参数是事件对象。

7.模块化+命名空间

  1. 目标:让代码更好保护,让多种数据分类更加明确。
  2. 批改store.js

    const countAbout = {
      namespaced:true,//开启命名空间
      state:{x:1},
      mutations: { ... },
      actions: { ... },
      getters: {
        bigSum(state){
           return state.sum * 10
        }
      }
    }
    
    const personAbout = {
      namespaced:true,//开启命名空间
      state:{ ... },
      mutations: { ... },
      actions: { ... }
    }
    
    const store = new Vuex.Store({
      modules: {
        countAbout,
        personAbout
      }
    })
  3. 开启命名空间后,组件中读取state数据:

    //形式一:本人间接读取
    this.$store.state.personAbout.list
    //形式二:借助mapState读取:
    ...mapState('countAbout',['sum','school','subject']),
    //对象写法
    ...mapState('countAbout',{sum:'sum'),
  4. 开启命名空间后,组件中读取getters数据:

    //形式一:本人间接读取
    this.$store.getters['personAbout/firstPersonName']
    //形式二:借助mapGetters读取:
    ...mapGetters('countAbout',['bigSum'])
    //对象写法
  5. 开启命名空间后,组件中调用dispatch

    //形式一:本人间接dispatch
    this.$store.dispatch('personAbout/addPersonWang',person)
    //形式二:借助mapActions:
    ...mapActions('countAbout',{incrementOdd:'jiaOdd',incrementWait:'jiaWait'})
    ...mapActions('user',['addCash'])
  6. 开启命名空间后,组件中调用commit

    //形式一:本人间接commit
    this.$store.commit('personAbout/ADD_PERSON',person)
    //形式二:借助mapMutations:
    ...mapMutations('countAbout',{increment:'JIA',decrement:'JIAN'}),
    ...mapMutations('user',['addCash'])

    ## 24、路由

  7. 了解: 一个路由(route)就是一组映射关系(key – value),多个路由须要路由器(router)进行治理。
  8. 前端路由:key是门路,value是组件。

1.根本应用

  1. 装置vue-router,命令:npm i vue-router
  2. 利用插件:Vue.use(VueRouter)
  3. 编写router配置项:

    //引入VueRouter
    import VueRouter from 'vue-router'
    //引入Luyou 组件
    import About from '../components/About'
    import Home from '../components/Home'
    
    //创立router实例对象,去治理一组一组的路由规定
    const router = new VueRouter({
        routes:[
            {
                path:'/about',
                component:About
            },
            {
                path:'/home',
                component:Home
            }
        ]
    })
    
    //裸露router
    export default router
  4. 实现切换(active-class可配置高亮款式)

    <router-link active-class="active" to="/about">About</router-link>
  5. 指定展现地位

    <router-view></router-view>

2.几个留神点

  1. 路由组件通常寄存在pages文件夹,个别组件通常寄存在components文件夹。
  2. 通过切换,“暗藏”了的路由组件,默认是被销毁掉的,须要的时候再去挂载。
  3. 每个组件都有本人的$route属性,外面存储着本人的路由信息。
  4. 整个利用只有一个router,能够通过组件的$router属性获取到。

3.多级路由(多级路由)

  1. 配置路由规定,应用children配置项:

    routes:[
        {
            path:'/about',
            component:About,
        },
        {
            path:'/home',
            component:Home,
            children:[ //通过children配置子级路由
                {
                    path:'news', //此处肯定不要写:/news
                    component:News
                },
                {
                    path:'message',//此处肯定不要写:/message
                    component:Message
                }
            ]
        }
    ]
  2. 跳转(要写残缺门路):

    <router-link to="/home/news">News</router-link>

4.路由的query参数

  1. 传递参数

    <!-- 跳转并携带query参数,to的字符串写法 -->
    <router-link :to="/home/message/detail?id=666&title=你好">跳转</router-link>
                    
    <!-- 跳转并携带query参数,to的对象写法 -->
    <router-link 
        :to="{
            path:'/home/message/detail',
            query:{
               id:666,
                title:'你好'
            }
        }"
    >跳转</router-link>
  2. 接管参数:

    $route.query.id
    $route.query.title

5.命名路由

  1. 作用:能够简化路由的跳转。
  2. 如何应用

    1. 给路由命名:

      {
          path:'/demo',
          component:Demo,
          children:[
              {
                  path:'test',
                  component:Test,
                  children:[
                      {
                            name:'hello' //给路由命名
                          path:'welcome',
                          component:Hello,
                      }
                  ]
              }
          ]
      }
    2. 简化跳转:

      <!--简化前,须要写残缺的门路 -->
      <router-link to="/demo/test/welcome">跳转</router-link>
      
      <!--简化后,间接通过名字跳转 -->
      <router-link :to="{name:'hello'}">跳转</router-link>
      
      <!--简化写法配合传递参数 -->
      <router-link 
          :to="{
              name:'hello',
              query:{
                 id:666,
                  title:'你好'
              }
          }"
      >跳转</router-link>

6.路由的params参数

  1. 配置路由,申明接管params参数

    {
        path:'/home',
        component:Home,
        children:[
            {
                path:'news',
                component:News
            },
            {
                component:Message,
                children:[
                    {
                        name:'xiangqing',
                        path:'detail/:id/:title', //应用占位符申明接管params参数
                        component:Detail
                    }
                ]
            }
        ]
    }
  2. 传递参数

    <!-- 跳转并携带params参数,to的字符串写法 -->
    <router-link :to="/home/message/detail/666/你好">跳转</router-link>
                    
    <!-- 跳转并携带params参数,to的对象写法 -->
    <router-link 
        :to="{
            name:'xiangqing',
            params:{
               id:666,
                title:'你好'
            }
        }"
    >跳转</router-link>

    特地留神:路由携带params参数时,若应用to的对象写法,则不能应用path配置项,必须应用name配置!

  3. 接管参数:

    $route.params.id
    $route.params.title

7.路由的props配置*

​ 作用:让路由组件更不便的收到参数

{
    name:'xiangqing',
    path:'detail/:id',
    component:Detail,

    //第一种写法:props值为对象,该对象中所有的key-value的组合最终都会通过props传给Detail组件
    // props:{a:900} 不必props承受会放在$attrs中

    //第二种写法:props值为布尔值,布尔值为true,则把路由收到的所有params参数通过props传给Detail组件
    // props:true
    
    //第三种写法:props值为函数,该函数返回的对象中每一组key-value都会通过props传给Detail组件
    props(route){
        return {
            id:route.query.id,
            title:route.query.title
        }
    }
}

8.<router-link>的replace属性

  1. 作用:管制路由跳转时操作浏览器历史记录的模式
  2. 浏览器的历史记录有两种写入形式:别离为pushreplacepush是追加历史记录,replace是替换以后记录。路由跳转时候默认为push
  3. 如何开启replace模式:<router-link replace .......>News</router-link>

9.编程式路由导航

  1. 作用:不借助<router-link> 实现路由跳转,让路由跳转更加灵便
  2. 具体编码:

    //$router的两个API
    this.$router.push({
        name:'xiangqing',
            params:{
                id:xxx,
                title:xxx
            }
    })
    
    this.$router.replace({
        name:'xiangqing',
            params:{
                id:xxx,
                title:xxx
            }
    })
    this.$router.forward() //后退
    this.$router.back() //后退
    this.$router.go() //可后退也可后退

10.缓存路由组件

  1. 作用:让不展现的路由组件放弃挂载,不被销毁。
  2. 具体编码:

    <keep-alive include="News"> 
        <router-view></router-view>
    </keep-alive>

11.两个新的生命周期钩子

  1. 作用:路由组件所独有的两个钩子,用于捕捉路由组件的激活状态。
  2. 具体名字:

    1. activated路由组件被激活时触发。
    2. deactivated路由组件失活时触发。

12.路由守卫

  1. 作用:对路由进行权限管制
  2. 分类:全局守卫、独享守卫、组件内守卫
  3. 全局守卫:

    //全局前置守卫:初始化时执行、每次路由切换前执行
    router.beforeEach((to,from,next)=>{
        console.log('beforeEach',to,from)
        if(to.meta.isAuth){ //判断以后路由是否须要进行权限管制
            if(localStorage.getItem('school') === 'atguigu'){ //权限管制的具体规定
                next() //放行
            }else{
                alert('暂无权限查看')
                // next({name:'guanyu'})
            }
        }else{
            next() //放行
        }
    })
    
    //全局后置守卫:初始化时执行、每次路由切换后执行
    router.afterEach((to,from)=>{
        console.log('afterEach',to,from)
        if(to.meta.title){ 
            document.title = to.meta.title //批改网页的title
        }else{
            document.title = 'vue_test'
        }
    })
  4. 独享守卫:

    beforeEnter(to,from,next){
        console.log('beforeEnter',to,from)
        if(to.meta.isAuth){ //判断以后路由是否须要进行权限管制
            if(localStorage.getItem('school') === 'atguigu'){
                next()
            }else{
                alert('暂无权限查看')
                // next({name:'guanyu'})
            }
        }else{
            next()
        }
    }
  5. 组件内守卫:

    //进入守卫:通过路由规定,进入该组件时被调用
    beforeRouteEnter (to, from, next) {
    },
    //来到守卫:通过路由规定,来到该组件时被调用
    beforeRouteLeave (to, from, next) {
    }

13.路由器的两种工作模式

  1. 对于一个url来说,什么是hash值?—— #及其前面的内容就是hash值。
  2. hash值不会蕴含在 HTTP 申请中,即:hash值不会带给服务器。
  3. hash模式:

    1. 地址中永远带着#号,不美观 。
    2. 若当前将地址通过第三方手机app分享,若app校验严格,则地址会被标记为不非法。
    3. 兼容性较好。
  4. history模式:

    1. 地址洁净,好看 。
    2. 兼容性和hash模式相比略差。
    3. 利用部署上线时须要后端人员反对,解决刷新页面服务端404的问题。
index.html :html的入口文件
    引入css文件
    引入index.js   此时的src指向实例化Vue的js文件
    <script type='module' src='js/index.js'></script>
css:
    style.css
js:
index.js
定义实例化的Vue  应用render模板去替换el挂载的DOM节点 
导入root文件,指向components中的root
render:(h){return h(root)}
    
components:
    root.js:定义render的返回值
    先导入页面须要的组件 和数据(如果须要则要导入事件总线)
    {
        template:`
        <div id="app">//如果css中定义了app的款式,id=app须要加上
            <todo-list></todo-list>
            <done-list></done-list>
        </div>
        `,
        components:{
            "todo-list":todolist,
            "done-list":donelist
        }
        
    }
    todolist.js
    donelist.js
    先导入事件总线中须要的数据
    定义组件的性能:获取数据应用computed计算属性  定义的办法 须要去触发总线中的办法 eventBus.$emit("事件总线中的办法",传入的参数)
store
    store.js
    先定义须要的数据,在eventBus上注册子组件须要的办法 this.$on("事件总线中的办法",this.eventBus中的办法)

Jenkins装置

nginx配置

yum install gcc-c++
yum install -y pcre pcre-devel
yum install -y zlib zlib-devel
yum install -y openssl openssl-devel
wget http://nginx.org/download/ngi…
tar zxvf nginx-1.16.1.tar.gz
先进入解压文件夹 ./configure && make && make install
whereis nginx 查看nginx装置门路
在usr/local/nginx/html下
启动
[root@localhost ~]# /usr/local/nginx/sbin/nginx
进行/重启
[root@localhost ~]# /usr/local/nginx/sbin/nginx -s stop(quit、reload)
命令帮忙
[root@localhost ~]# /usr/local/nginx/sbin/nginx -h
验证配置文件
[root@localhost ~]# /usr/local/nginx/sbin/nginx -t
配置文件
[root@localhost ~]# vim /usr/local/nginx/conf/nginx.conf

装置yarn

应用 yum 装置 Yarn
Yarn 官网提供的有 Yarn RPM 软件包,在增加 yum 源配置之后可应用 yum 装置:

增加 yum 源配置

curl -sL https://dl.yarnpkg.com/rpm/ya… | sudo tee /etc/yum.repos.d/yarn.repo

应用 yum 装置

sudo yum -y install yarn

查看装置的 Yarn 版本:

yarn -v

Jenkins装置

jekins+gitee+nginx
sudo wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat…
sudo rpm –import https://pkg.jenkins.io/redhat…
sudo yum upgrade
sudo yum install epel-release java-11-openjdk-devel
sudo yum install jenkins
sudo systemctl daemon-reload
sudo systemctl start jenkins 启动
查看状态sudo systemctl status jenkins
批改编辑权限 vim /etc/sysconfig/jenkins
service jenkins restart重启

这时拜访jenkins有不能够,要凋谢阿里云8080端口
1.登录胜利
为了确保管理员平安地装置 Jenkins,明码已写入到日志中(不晓得在哪里?)该文件在服务器上:
/var/lib/jenkins/secrets/initialAdminPassword
请从本地复制明码并粘贴到上面。
d65c81a6952341dfac53d9efaf61e0cc
2.依照默认配置装置插件
3.创立一个管理员账户,实现配置后,就能够登录 Jenkins 了
4.装置插件
  上面来装置nodejs插件

gitee令牌2e724699896926f21b301598d10d91d7

gitee试验jenkins教程

装置rz :yum install -y lrzsz

gcc 版本过低

4.装置gcc

yum install gcc -y #默认装置旧版本4.85

yum -y install centos-release-scl

yum -y install devtoolset-9-gcc devtoolset-9-gcc-c++ devtoolset-9-binutils #装置新版本

切换为新版本

scl enable devtoolset-9 bash #长期切换,退出服务器复原

echo “source /opt/rh/devtoolset-9/enable” >>/etc/profile #永恒切换

jenkins

须要配置webhook gitee须要配置 参考jenkins+gitee实现前端我的项目自动化部署 – 简书 (jianshu.com)

装置nodejs

  • 第一步,到官网查看最新源码,并下载
cd /home/downloads
wget https://nodejs.org/dist/v10.16.0/node-v10.16.0.tar.gz

下载编译好的node Linux

ln -s /usr/local/src/node-v16.5.0-linux-x64/bin/node /usr/local/bin/node

ln -s /usr/local/src/node-v16.5.0-linux-x64/bin/npm /usr/local/bin/npm

课堂常识内容回顾

1、应用template会将el挂载的节点内容替换. 留神template模板的应用

 <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<body>
    <div id="app"></div>
</body>
<script>
    // 模型层
    var obj = {
        message:"hello,world  1"
    }
    // 视图层 替换id=app区域
    var template = `
        <div class='Find'>{{message}}</div>
    `;

    // 视图模型层
    var app = new Vue({
        el:"#app",
        data:obj,
        template:template
    });

2、解冻属性Object.freeze(data),解冻后不能实时响应数据

3、生命周期

  <div id="app">
        <p title="nihao" ref="hello">{{msg}}</p>
    </div>
    <script>
        var app =new Vue({
            // 外部没有el,能够手动进行$mount("#app")挂载
            // el:"#app",
            data:{
                msg:"你好"
            },
            beforeCreate(){
                // 在实例初始化之后,进行数据侦听和事件/侦听器的配置之前同步调用
                console.log("生命周期:beforeCreate");
                console.log('加载data中的msg数据---'+this.msg);
                console.log('获取节点$el---'+this.$el);
                this.initMethod()
            },
            created(){
                // 数据 injections 和reactivity 注入 响应
                // 在实例创立实现后被立刻同步调用。在这一步中,实例已实现对选项的解决,意味着以下内容已被配置结束:数据侦听、计算属性、办法、事件/侦听器的回调函数
                console.log("生命周期:created");
                console.log('加载data中的msg数据---'+this.msg);
                console.log('获取节点$el---'+this.$el);
                this.initMethod()
            },
            beforeMount(){
                // 生成虚构dom  在挂载开始之前被调用:相干的 render 函数首次被调用。
                console.log("生命周期:beforeMount");
                console.log(this.$el);
                console.log(this.$refs);
            },
            mounted(){
                // 实在的dom   实例被挂载后调用,这时 el 被新创建的 vm.$el 替换了
                console.log("生命周期:mounted");
                console.log(this.$el);
                console.log(this.$refs);
            },
            beforeUpdate(){
                // data 数据扭转 beforeUpdate函数中的数据没有扭转  app.msg = 123     this.msg=123
                console.log("生命周期:beforeUpdate");
                console.log(this._vnode.children[0].children[0].text);
            },
            updated(){
                // 通过patch算法 比照理论dom和渲染虚构dom 更新数据 
                console.log("生命周期:beforeUpdate");
                console.log(this._vnode.children[0].children[0].text);
            },
            beforeDestroy(){
                // 应用app.$destroy  卸载对象与vue的绑定
                console.log("生命周期:beforeDestroy");

            },
            destroyed(){
                console.log("生命周期:destroyed");

            },
            methods: {
                initMethod(){
                    console.log('初始化办法调用胜利');
                }
            },

        }).$mount("#app");

4、组件

组件中的data为什么是一个函数的返回值?

<div id="app">
        <button-counter></button-counter>
        <button-counter></button-counter>
        <button-counter></button-counter>
    </div>

    <script>
        Vue.component("button-counter",{
            //如果不应用函数返回,复用的组件的data数据是雷同的援用,通过函数的返回对象,每次创立的都是一个新的数据援用
            // data:{
            //     count:0
            // },
            data(){
                return {
                    count:0
                }
            },
            created(){
                console.log("我是组件");
                console.log(this);
            },
            template:`
            <button v-on:click="count++">你点击了{{count}}次</button>
            `
        })

        var app = new Vue({
            el:"#app",
            created(){
                console.log("我是根");
                console.log(this);
            },
        })

组件的注册形式

//组件的名称:不应用单文件组件时(.vue):举荐遵循 W3C 标准中的自定义组件名 (字母全小写且必须蕴含一个连字符)比方my-component-name
如果组件名称是大驼峰或者小驼峰
Vue.component('MyComponent'/'myComponent', {
  // ... 选项 ...
})
能够在父组件中这样调用是等价的
<my-component></my-component>  <MyComponent></MyComponent>/<myComponent></myComponent> 

注册形式:
//全局注册  间接在任意中央应用
Vue.component('my-component', {
  // ... 选项 ...
})

//部分注册  
<div id="app">
       <my-component></my-component>
    </div>
    <script>
        var options = {
            data(){
                return{
                    msg:"我是子组件中的data值"
                }
            },
            template:"<div>{{msg}}</div>"
        }

        new Vue({
            el:"#app",
            components:{
                "my-component":options,//前面接入选项对象
            }
        });
    </script>

组件间的通信形式有3类:

第一类:父子组件通信

第二类:隔代组件通信

第三类:兄弟组件通信

(1) props/$emit 实用父子组件通信

父–>子传值 props

 <div id="app">
        <book v-for="item in bookList" :name="item.name" :author="item.author"></book>
    </div>
    <script>
        Vue.component("book", {
            props: ["name", "author"],
            template: `
            <div>
                <p>书名:{{name}}</p>
                <p>作者:{{author}}</p>
            </div>           
           `
        })
        var app = new Vue({
            el:"#app",
            data:{
                bookList:[
                {
                    name:"西游记",
                    author:"吴承恩"
                },
                {
                    name:"水浒传",
                    author:"施耐庵"
                },
                {
                    name:"红楼梦",
                    author:"曹雪芹"
                },
                {
                    name:"三国演义",
                    author:"罗贯中"
                }
            ]
            }
        })

    </script>
 <div id="app">
        <!-- v-bind  当做表达式解析 -->

        
        <my-book :name="book.name" :price="book.price"></my-book>
        <my-book v-bind="book"></my-book>
    </div>
    
    <script>
        Vue.component("my-book",{
            props:["name","price"],
            template:`
            <div>
                <p>{{name}}</p>
                <p>{{price}}</p>
            </div>
            
            `
        })

        new Vue({
            el:"#app",
            data:{
                book:{
                    name:"西游记",
                    price:15
                }
            }
        });
    

子父传值 通过$emit(组件上的自定义办法,传入父组件的值)

<div id="app">
        <p>{{count}}</p>
        <my-counter v-on:add="add1" :msg="msg"></my-counter>
    </div>
    <script>
        Vue.component("my-counter", {
            props:['msg'],
            data(){
                return{
                    son:"子组件"
                }
            },
            template: `
            <div>            
                <p>{{son}}</p>
                <p>{{msg}}</p>
                 <button v-on:click="btnClick">减少</button>
            </div>
           `,
           beforeCreate() {
                console.log("子组件的beforeCreated");
            },
            created(){
                console.log("子组件的created");
            },
            beforeMount() {
                console.log("子组件的beforeMount");
            },
            mounted() {
                console.log("子组件的mounted");
            },
            beforeUpdate() {
                console.log('子组件的beforeUpdate');
            },
            updated() {
                console.log("子组件的updated");
            },
            beforeDestroy() {
                console.log("子组件的beforeDestroy");
            },
            destroyed() {
                console.log("子组件的destroyed");
            },

           methods: {
               btnClick(){
                console.log("子组件的btn事件");
                this.$emit("add",{
                    addCount:10,
                    name:"二蛋"
                });
               }
           },
        })

        var app = new Vue({
            el: "#app",
            data: {
                count: 0,
                msg:"父子传值"
            },
            beforeCreate() {
                console.log("父组件的beforeCreated");
            },
            created(){
                console.log("父组件的created");
            },
            beforeMount() {
                console.log("父组件的beforeMount");
            },
            mounted() {
                console.log("父组件的mounted");
            },
            beforeUpdate() {
                console.log('父组件的beforeUpdate');
            },
            updated() {
                console.log("父组件的updated");
            },
            beforeDestroy() {
                console.log("父组件的beforeDestroy");
            },
            destroyed() {
                console.log("父组件的destroyed");
            },

            methods: {
                add1(e){
                    console.log(e.name);
                    console.log("根组件count++");
                    this.count+=e.addCount;
                }
            },

        })

(2)ref与$parent/$children 应用父子组件通信

(3)$attrs/$listeners 应用隔代组件通信

(4)provide / inject 应用于隔代组件通信

  <div id="app">
        <p>我是根元素</p>
        <my-one></my-one>
    </div>    
    <script>
        Vue.component("my-one",{
            inject:["msg","getStr"],
            // 拜访
            template:`
            <div style="border:1px solid red">
                <p>{{msg}}</p>
                <p>{{getStr()}}</p>
            </div>
            `,
        });
        var app = new Vue({
            el:"#app",
            data:{
                msg:'依赖提供的数据',
            },
            methods: {
                getStr(){
                    console.log("依赖提供的办法");
                    return "依赖办法返回的值"
                }
            },

            provide(){
                return {
                    msg:this.msg,
                    getStr:this.getStr,
                }    
            }  
        })
    </script>

(5)EventBus($emit/$on)实用于父子、隔代、兄弟组件通信

    <div id="app">
        <p>{{msg}}</p>
        <my-one></my-one>
    </div>
    <script>
        // 公共仓库治理msg的状态
        var eventBus = new Vue({
            created() {
                // 为事件总线增加change-msg的事件
                this.$on("change-msg",this.print)
            },
            data:{
                msg:'父组件的msg',
            },    
            methods: {
                print(str){
                    this.msg=str;
                    console.log(this.msg);
                },
            },     
        })
        // 2.子组件的数据不须要通过props进行传递,通过eventBus进行触发总线的change-msg事件,传递的参数在print中承受,通过print批改msg中的值
        Vue.component("my-one",{
            template:`
            <div style="border:1px solid red">
                <p>{{msg}}</p>    
                <button @click="btnClick">批改</button>
            </div>
            `,
            computed:{
                msg(){
                    return eventBus.msg;
                }
            },
            
            methods: {
                btnClick(){
                    // 3.$emit 触发change-msg,调用print办法
                    eventBus.$emit("change-msg","我是子组件批改的")
                }
            },
        })
        // 1.获取msg 间接通过eventBus进行获取
        var app =new Vue({
            el:"#app",
            computed:{
                msg(){
                    return eventBus.msg;
                }
            },
            
        });
    </script>

(6)Vuex 实用于父子、隔代、兄弟组件通信

组件的插槽slot

<div id="app">
        <my-slot>
            <div>你好</div>
            <div>你好</div>
        </my-slot>
    </div>
    <script>
        Vue.component("my-slot",{
            template:`
            <div>
                <p>组件插槽</p>
                <slot></slot>
                <p>组件插槽</p> 
            </div>         
            `
        });
        var app =new Vue({
            el:"#app",
            
        })
    </script>

编译作用域

父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。

 <div id="app">
        <my-one>
            <!-- 规定谁的模板 数据就是谁的 -->
            <!-- 编译时在app中的msg应用根组件的作用域的数据 -->

            <!-- 利用 根组件的数据通过slot间接渲染在子组件中 不须要通过props属性进行传递 -->
            <div>{{msg}}</div>
        </my-one>
    </div>

    <script>
        Vue.component("my-one",{
            data(){
                return {
                    msg:"我是子组件的"
                }
            },
            template:`
            <div>
                <p>我是子组件</p>
                <slot></slot>
                <p>我是子组件</p>
            </div>
            `,
        });
        
        var app =new Vue({
            el:"#app",
            data:{
                msg:"我是根组件的"
            }
        });
    </script>

后背内容 默认的内容

 <div id="app">
        <my-slot>
            <!-- 如果此处有内容,子组件中的slot默认内容将不会显示 -->
        </my-slot>
    </div>
    <script>
        Vue.component("my-slot",{
            template:`
            <div>
                <p>组件插槽</p>
                <slot>默认内容</slot>
                <p>组件插槽</p> 
            </div>         
            `
        });
        var app =new Vue({
            el:"#app",
            
        })
    </script>

具名插槽

    <div id="app">
        <my-one>
            <template v-slot:head>
                <div>头部</div>
            </template>
            <template #middle>
                <div>两头</div>
            </template>
<!--            <div>尾部</div>  等价于上面的写法-->
             <template v-slot:default>
                <div>尾部</div>
            </template>

        </my-one>
    </div>

    <script>
        Vue.component("my-one", {

            template: `
            <div>
                <slot name="head"></slot>
                <p>我是子组件</p>
                <slot name="middle"></slot>                    
                <p>我是子组件</p>
                <slot></slot>
            </div>
            `,
        });

        var app = new Vue({
            el: "#app",
        });
    </script>

作用域插槽

    <div id="app">
        <!-- 让插槽内容可能拜访子组件中才有的数据是很有用 -->
        <current-user>
            <!-- 将蕴含所有插槽 prop 的对象命名为 slotProps -->
            <template v-slot:default="slotProps">
                {{slotProps.user.firstName}}
            </template>
        </current-user>
    </div>

    <script>
        Vue.component("current-user", {
            data(){
                return{
                    user:{firstName:"姓",lastName:"名"}
                }
            },
// 绑定在 <slot> 元素上的 attribute 被称为插槽 prop
    // 当初在父级作用域中,咱们能够应用带值的 v-slot 来定义咱们提供的插槽 prop 的名字:
            template: `
            <div>
                <slot v-bind:user="user">{{user.lastName}}</slot>
            </div>
            `,
        });

        var app = new Vue({
            el: "#app",
        });
    </script>
//补充:当被提供的内容只有默认插槽时  组件的标签才能够被当作插槽的模板来应用
<current-user v-slot:default="slotProps">
  {{ slotProps.user.firstName }}
</current-user>
//能够简写为
<current-user v-slot="slotProps">
  {{ slotProps.user.firstName }}
</current-user>
//构造赋值
 <!-- 构造赋值 别名只能在这里应用 -->
            <template v-slot:foot="{user:person}">
                {{person}}
            </template>
//这里还是只能写user
             <slot name="foot" :user="user">
                    <div>{{user}}</div>
                </slot>

要扭转插槽的值

//第一种传入的是对象  子组件中应用user.lastName
 <!-- 将蕴含所有插槽 prop 的对象命名为 slotProps 相当与data的数据 -->
                <template v-slot:default="slotProps">
                    {{slotProps.user}}
                </template>
            <slot v-bind:user="user.firstName">
                    <div>{{user}}</div>
                </slot>
                <slot v-bind:user="user.lastName">
                    <div>{{user}}</div>
                </slot>
//第二种形式  在组件中间接传入
             <template v-slot:default="slotProps">
                {{slotProps.user.lastName}}
            </template>
             <slot v-bind:user="user">
                    <div>{{user}}</div>
                </slot>

动静组件 keep-alive

应用keep-alive时,组件将缓存

    <div id="app">
        <!-- 切换后放弃原页面的数据 -->
        <button @click="msg='my-one'">组件一</button>
        <button @click="msg='my-two'">组件二</button>
        <!-- 所有被keep-alive包裹都有新的两个生命周期 -->
        <!-- <keep-alive> -->
            <component :is="msg"></component>
        <!-- </keep-alive> -->
    </div>

    <script>
        Vue.component("my-one", {
            created() {
                console.log("组件一创立了")
            },
            destroyed() {
                console.log("组件一销毁了")
            },
            activated() {
                console.log("activated生命周期被调用");
            },
            deactivated() {
                console.log("deactivated生命周期被调用");
            },
            template: `
            <div>
               <p>我是组件一</p>
               <input type='text'>
            </div>
            `,
        });
        Vue.component("my-two", {
            created() {
                console.log("组件二创立了");
                
            },
            destroyed() {
                console.log("组件二销毁了");
            },
            data(){
                return {
                    msg:'哈哈'
                }
            },
            template: `
            <div>
               <p>我是组件二</p>
               <p>{{msg}}</p>
               <button @click="msg='你好'">扭转</button>
            </div>
            `,
        });

        var app = new Vue({
            el: "#app",
            data:{
                msg:"my-one"
            }
        });
    </script>
    
    内联模板inline-template
<div id="app">
    <p>{{msg}}</p>
    <!-- 不举荐应用inline-template 应用后将当中的内容作为子组件的模板,作用域是子组件 -->
    <my-one inline-template>
        <div style="border:1px solid red">
            <p>{{msg}}</p>
        </div>
    </my-one>
</div>    
<script>

    Vue.component("my-one",{
        data(){
            return {
                msg:"子组件的msg"
            }
        }
       
    });
    var app = new Vue({
        el:"#app",
        data:{
            msg:'父组件的msg',
        },         
    })
</script>


x-template 

<div id=”app”>

    <p>{{msg}}</p>     
    <my-one> </my-one>
</div>   

<!-- 应用script去写子组件的模板,通过id 赋值给子组件的template -->
<script type="text/x-template" id="one">
    <div style="border:1px solid red">
        <p>{{msg}}</p>
    </div>
</script>
<script>
    
    Vue.component("my-one",{
        template:"#one",
        data(){
            return {
                msg:"子组件的msg"
            }
        }
       
    });
    var app = new Vue({
        el:"#app",
        data:{
            msg:'父组件的msg',
        },         
    })
</script>

混入mixin

混入 (mixin) 提供了一种非常灵活的形式,来散发 Vue 组件中的可复用性能。一个混入对象能够蕴含任意组件选项。当组件应用混入对象时,所有混入对象的选项将被“混合”进入该组件自身的选项。
<div id="app">
    <p>{{msg}}</p>
    <button @click="print">打印</button>
    <p>----------------</p>
    <my-one></my-one>
</div>
<script>
    /* 
        混入就是抽取组件雷同的局部
        通过mixins导入组件 语法mixins:[mixin]
    */
    var mixin = {
        created() {
            console.log("混入对象的生命周期");
        },
        // 当数据对象与组件的数据对象抵触时(除了生命周期会合并),以组件为准 办法是挂载在组件上
        //例如 methods、components 和 directives,将被合并为同一个对象。两个对象键名抵触时,取组件对象的键值对。
        data(){
            return {
                msg:"混入对象的msg你好"
            }
        },
        methods: {
            print(){
                console.log(this.msg);
            }
        },
    }

    Vue.component("my-one",{
        mixins:[mixin],
        // 同名的钩子函数将合并为一个数组,因而都将被调用 
        // 混入的钩子函数会先于组件的钩子函数执行
        created() {
            console.log("组件本人的生命周期钩子函数");
        },
        data(){
            return {
                msg:"组件的数据你好"
            }
        },
       template:`
       <div>
            <p>我是子组件---{{msg}}</p>
            <button @click="print">打印</button>
        </div>
       `
    })
    var app = new Vue({
        el:"#app",
        mixins:[mixin],
    })

</script>

过滤器 filter

过滤器能够用在两个中央:**双花括号插值和 `v-bind` 表达式** (后者从 2.1.0+ 开始反对)。过滤器应该被增加在 JavaScript 表达式的尾部,由“管道”符号批示。

当全局过滤器和部分过滤器重名时,会采纳部分过滤器。

全局过滤器:在创立 Vue 实例之前全局定义过滤器

// 全局过滤器

     Vue.filter("replaceMinus",function(value){
         return value.replace(/-/g," ");
     })

部分过滤器

var app = new Vue({

        el:"#app",
        data:{
            msg:'hello-world-haha-heihei'
        },
        filters:{
            "replaceMinus":function(value){
                return value.replace(/-/g," ");
            },
            "upperCase":function(value){
                return value.toUpperCase();
            }
        }
    })

 案例:
<div id="app">
    <p>{{msg | replaceMinus}}</p>
    <p>{{msg | upperCase}}</p>
   
</div>
<script>
    //    全局过滤器
    Vue.filter("replaceMinus",function(value){
        return value.replace(/-/g," ");
    })
    var app = new Vue({
        el:"#app",
        data:{
            msg:'hello-world-haha-heihei'
        },
        filters:{
            // "replaceMinus":function(value){
            //     return value.replace(/-/g," ");
            // },
            "upperCase":function(value){
                return value.toUpperCase();
            }
        }
    })

</script>


自定义指令directive

<div id=”app”>

    <input type="text" v-focus>自定义指令</input>
    <input type="text" v-focu>
</div>
<script>
        
    // 全局指令注册 bg inserted的函数
    Vue.directive('focus',{
        inserted:function(el){
            // el是以后的dom节点
            console.log(el);
            // window对象
            console.log(this);
            el.focus();
        }
    })
  //部分指令注册应用directives
    var app = new Vue({
        el: "#app",
       directives:{
           focu:{
               inserted:function(el){
                //    同上
                   console.log(this);
                   console.log(el);
                   el.focus();
               }
           }
       }
    })

</script>

自定义指令的钩子函数

一个指令定义对象能够提供如下几个钩子函数 (均为可选):

bind:只调用一次,指令第一次绑定到元素时调用。在这里能够进行一次性的初始化设置。

inserted:被绑定元素插入父节点时调用 (仅保障父节点存在,但不肯定已被插入文档中)。

update:所在组件的 VNode 更新时调用,然而可能产生在其子 VNode 更新之前。指令的值可能产生了扭转,也可能没有。然而你能够通过比拟更新前后的值来疏忽不必要的模板更新 。

componentUpdated:指令所在组件的 VNode 及其子 VNode 全副更新后调用。

unbind:只调用一次,指令与元素解绑时调用。


钩子函数参数

指令钩子函数会被传入以下参数:

el:指令所绑定的元素,能够用来间接操作 DOM。
binding:一个对象,蕴含以下 property:

    name:指令名,不包含 v- 前缀。
    value:指令的绑定值,例如:v-my-directive="1 + 1" 中,绑定值为 2。
    oldValue:指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否扭转都可用。
    expression:字符串模式的指令表达式。例如 v-my-directive="1 + 1" 中,表达式为 "1 + 1"。
    arg:传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 "foo"。
    modifiers:一个蕴含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }。

vnode:Vue 编译生成的虚构节点。移步 VNode API 来理解更多详情。
oldVnode:上一个虚构节点,仅在 update 和 componentUpdated 钩子中可用。

留神:除了 el 之外,其它参数都应该是只读的,切勿进行批改。如果须要在钩子之间共享数据,倡议通过元素的 dataset 来进行。

<div id=”app”>

    <div id="hook-arguments-example" v-demo:foo.a.b="msg"></div>
</div>

<script>
    // 全局注册 bg inserted的函数
    Vue.directive('demo', {
        bind: function (el, binding, vnode) {
            // el是以后的dom节点
            console.log(el);
            // 一个对象蕴含属性
            console.log(binding);
            // Vue 编译生成的虚构节点。
            console.log(vnode);
            var s = JSON.stringify
            el.innerHTML =
                //示意demo
                'name: ' + s(binding.name) + '<br>' +
                //示意msg
                'value: ' + s(binding.value) + '<br>' +
                //msg
                'expression: ' + s(binding.expression) + '<br>' +
                //foo
                'argument: ' + s(binding.arg) + '<br>' +
                //{a:true,b:true}
                'modifiers: ' + s(binding.modifiers) + '<br>' +
                'vnode keys: ' + Object.keys(vnode).join(', ')
        }
    })
    var app = new Vue({
        el: "#app",
        data: {
            msg: "hello"
        }
    })

</script>


### [动静指令参数](https://cn.vuejs.org/v2/guide/custom-directive.html#动静指令参数)

创立一个自定义指令,用来通过固定布局将元素固定在页面上。咱们能够像这样创立一个通过指令值来更新竖直地位像素值的自定义指令:

这会把该元素固定在间隔页面顶部 200 像素的地位。但如果场景是咱们须要把元素固定在左侧而不是顶部又该怎么办呢?这时应用动静参数就能够十分不便地依据每个组件实例来进行更新。

<div id=”dynamicexample”>
<h3>Scroll down inside this section ↓</h3>
<p v-pin:[direction]=”200″>I am pinned onto the page at 200px to the left.</p>
</div>
//通过
Vue.directive(‘pin’, {
bind: function (el, binding, vnode) {

el.style.position = 'fixed'
var s = (binding.arg == 'left' ? 'left' : 'top')
el.style[s] = binding.value + 'px'

}
})

new Vue({
el: ‘#dynamicexample’,
data: function () {

return {
  direction: 'left'
}

}
})

渲染函数render

`createElement` 到底会返回什么呢?其实不是一个*理论的* DOM 元素。它更精确的名字可能是 `createNodeDescription`,因为它所蕴含的信息会通知 Vue 页面上须要渲染什么样的节点,包含及其子节点的形容信息。咱们把这样的节点形容为“虚构节点 (virtual node)”,也常简写它为“**VNode**”。“虚构 DOM”是咱们对由 Vue 组件树建设起来的整个 VNode 树的称说

<div id=”app”>

   
</div>
<div>
    <anchored-heading :level="2">Hello-world!</anchored-heading>
</div>


<script>

    Vue.component('anchored-heading', {
        render: function (createElement) {
            console.log(this.level);
            console.log(this.$slots);
            return createElement(
                'h' + this.level,   // 标签名称
                this.$slots.default // 子节点数组
            )
        },
        props: {
            level: {
                type: Number,
                required: true
            }
        }
    })
    var app = new Vue({
        el: "#app",

        // 通过渲染函数
        render:function(createElement){
            let vnode = createElement(
                "h1",//第一个参数
                {   //第二个参数
                    class:{
                        foo:true,
                    },
                    style:{
                        color:"red",
                    },
                    attrs:{
                        title:"题目属性"
                    }
                },
                "你好")//第三个参数
            console.log(vnode);
            return vnode
        }
    })

</script>

## vue-router

index.html

链接到vue的router中
<router-link to="/about">About</router-link>
<router-link to="/home">Home</router-link>
展现跳转显示的模板地位
<router-view></router-view>

js/index.js

导入router
定义router:router

router/index.js

导入组件About 组件中导入的地址是绝对本身文件的
new VueRouter({
    routes:[
        {
            path:'/about',
            component:About
        }
    ]
})

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理