星星博客 »  > 

2021面试题—vue篇

day1 - 双向数据绑定

一、MVVM

  • m model(模型) 指的是后端传输的数据
  • v view(视图) 指的是所看到的页面
  • vm viewmodel(视图模型) 它是MVVM的核心,是连接view和model的桥梁,它有两个方向:一是将【模型】转化成【视图】,即将后端传递的数据转化成所看到的页面。实现的方式是:数据绑定。二是将【视图】转化成【模型】,即将所看到的页面转化成后端的数据。实现的方式是:DOM 事件监听。这两个方向都实现的,我们称之为数据的双向绑定。总结:在MVVM的框架下视图和模型是不能直接通信的。它们通过ViewModel来通信,ViewModel通常要实现一个observer观察者,当数据发生变化,ViewModel能够监听到数据的这种变化,然后通知到对应的视图做自动更新,而当用户操作视图,ViewModel也能监听到视图的变化,然后通知数据做改动,这实际上就实现了数据的双向绑定。并且MVVM中的View 和 ViewModel可以互相通信。MVVM流程图如下:

在这里插入图片描述

let vm = new Vue({
    // el 表示根节点,说明了你的Vue框架的活动范围或者作用域,作用于id为app的这个div以及所有子元素中
    el: '#app',
    // data Vue可以操作的数据集合
    data: {
        a: 1,
        b : 2,
        arr : [1, 2, 3],
        obj : {
            name : 'laoxie',
            age : 18,
        }
    }
})   

二、常见问题:

1、如何查看一个对象是否具有双向数据绑定,就看它有没有get和set方法

2、如何获取vue中可操作的数据集合中的某一项

console.log(vm.a === vm.$data.a); // true
console.log(vm.a);  // 1

3、如果Vue可操作集合中的数据不是一开始就写上去的,而是后来定义的,那么它是不具备双向数据绑定的特性

4、Vue 无法检测到对象属性的添加或删除。由于 Vue 会在初始化实例时对属性执行 getter/setter 转化,所以属性必须在 data 对象上存在才能让 Vue 将它转换为响应式的

5、如何在Vue实例化之后定义的属性具有响应式特性?

* vm.$set(vm.$data.obj, '属性', '初始值');
* Vue.set(vm.someObject, 'b', 2)

6、如果Vue的实例中的可操作的数据集合中存在数组,当数组的length发生改变,视图是不会发生改变的,这个是特例。但是我们就想让视图更新,这就需要使用数组的变异方法,也就是说修改原数组的方法,目前学习这7个就行

7、特例:Vue不能检测数组length的变化 和 索引位置对应的数据变化,只有以下7个方法具有双向数据绑定的特性

8.数组的变异方法

push pop shift unshift splice sort reverse

三、回顾Object.defineProperty()方法:

// 定义对象中的attr属性
Object.defineProperty(data, 'attr', {
    value : 'wwg',
    enumerable: false,    // 定义属性能否被遍历,默认是false,不可遍历
    configurable: false   // 定义属性能否被删除 默认false,不可被删除
    writable: false,         // 定义属性能否被设置,默认false,不可重写
    当获取data的属性时会触发函数
})

四、双向数据绑定:

let data = {};
// 设置一个中间对象
let temp = {};
// 定义对象中的a属性
Object.defineProperty(data, 'a', {
    // 当获取data的属性时触发函数
    get(){  
        return temp.a;
    },
    // 当设置data的属性时触发函数
    set(value){
        temp.a = value; 
        // 双向数据绑定
        // model --- 修改 --- view
        inp.value = value;
    }

})
// 双向数据绑定
// view --- 修改 --- model
// 在文本框中输入数据就会触发函数
inp.addEventListener('input', function () {
    data.a = this.value;
})

day2 - 生命周期函数

let vm = new Vue({
    el: '#app',

    // beforeCreate(){
    //     // this都指向vue实例
    //     console.log(this);
    //     debugger;
    // },

    // created(){   // 使用ajax请求数据(重要)
    //     // this都指向vue实例
    //     console.log(this)
    //     debugger;
    // },

    // beforeMount(){
    //     debugger;
    // },

    mounted(){   // 可以操作节点(重要)
        // 在这里获取el时为什么只能用this,而不能用vm.$el?

        // 在这里是拿不到vm的,因为所有的生命周期函数都是在=右边执行的,所以使用一个没有定义的变量会报错vm is not defined
        // console.log(vm)

        // 表示下一个进程,里面的回调是异步的
        this.$nextTick(() => { // 在下一个进程执行回调函数
            console.log(vm);
            console.log(this);
        })
        // console.log(this.$el);
        // console.log(arguments);
        // debugger;
    },

    // beforeUpdate(){
    //     console.log('beforeUpdate')
    // },

    // updated(){
    //     console.log(updated)
    // },

    // beforeDestroy(){
    //     console.log('beforeDestory');
    // },
    // destroyed(){
    //     console.log('destoyed');
    // },

    data: {
        a: 1,
    }
})

一、8个生命周期函数:

  • 创建阶段
  • 挂载阶段
  • 更新阶段
  • 销毁阶段
  1. beforeCreate

    • 创建vm实例之前会触发的这个函数,此时Vue实例的状态 data中没有数据
  2. created

    • 走完beforeCreate函数,data中是没有数据的,只有执行了created函数后,data中才有数据
    • 此时Vue实例中的数据已初始化完成,data中已经有数据,但是数据没有挂载到视图中,因为这个状态下是没有el挂载点,所以无法更新视图
  3. beforeMount

    • 此时Vue实例已经有el挂载点(这是与created时的区别)
    • 此时根节点已存在,但数据没有挂载到根节点上
  4. mounted

    • 此时数据已经挂载到根节点上了

    在mounted函数中,如何获取el?为什么用vm.$el的方式获取会报错?

    答:console.log(this.$el);
            因为所有的生命周期函数都是在=右边执行的,所以使用一个没有定义的变量会报错: vm is not defined
        如果我就想在这里打印vm:
        就要使用this.$nextTick()函数,表示下一个进程,里面的回调是异步的
        this.$nextTick(() => { 
            console.log(vm);
            console.log(this);
            // 这里的this和vm基本上是等价的,但还是有一点差别:vm表示所有生命周期函数都执行完毕后的实例,而this表示当前状态下的实例,也就是说当前生命周期函数下的实例
        })
    })
    
  5. beforeUpdate

    • data中的数据发生变化之前触发
  6. updated

    • data中的数据发生变化之后触发
  7. beforeDestory

    • 销毁vue实例之前触发
  8. destroyed

    • 销毁vue实例之后触发

以上8个声明周期函数中的额this都指向Vue实例vm

二、Vue实例获取属性的几种方式

  • vm.$data 获取数据
  • vm.$el 获取根节点
  • vm.$set(data, ‘属性’, ‘值’) 设置响应式属性
  • vm.$mount(el) 挂载根节点的另外一种方式
  • vm.$destroy(); 实例销毁时触发

三、常用指令:

  • {{数据}} 在{{}}中可以插入Vue提供的数据,不会把标签格式的字符串解析成标签
  • v-html 类似于innerHTML,把数据解析成对应的标签格式
  • v-text 类似于innerText,不会把标签格式的字符串解析成标签
  • v-if=“数据” 这里的数据表示js的变量或者表达式
    • 如果数据为真 则渲染该节点
    • 如果数据为假 则不渲染该节点
  • v-else-if=“数据”
  • v-else
    • v-if、v-else-if和v-else 如果一起出现,必须是相邻兄弟,否则会警告
  • v-show=“数据” 这里的数据表示js的变量或者表达式
    • 如果数据为真 则显示该节点
    • 如果数据为假 则不显示该节点
  • v-on:click=回调函数 为元素绑定一个点击事件
  • v-on:click.once=回调函数 为元素绑定一个一次性的点击事件
  • v-once 只渲染元素和组件一次。随后的重新渲染,元素/组件及其所有的子节点将被视为静态内容并跳过。这可以用于优化更新性能。

四、自定义指令

  • 全局:Vue.directive()
  • 局部:directives()

day3 - v-model 修饰符-methods-computed

一、v-model详解

<div id="app">
    <!-- <input type="text" v-model.number.lazy.trim="a"> -->

    <!-- <input type="radio" v-model="b" value="男"><input type="radio" v-model="b" value="女">-->

    <!-- <input type="checkbox" v-model="arr" value="刘备">刘备
    <input type="checkbox" v-model="arr" value="关羽">关羽
    <input type="checkbox" v-model="arr" value="张飞">张飞 -->

    <!-- <select v-model='d' multiple>
        <option value="刘备">刘备</option>
        <option value="关羽">关羽</option>
        <option value="张飞">张飞</option>
    </select> -->

    <textarea v-model="f"></textarea>
</div>
let vm = new Vue({
    el: "#app",
    data: {
        // a: 1,
        // b: "男",     // 男 默认选中 model影响view
        // arr: ['张飞']
        // c:'刘备'
        // d: []
        f: ""
    }
})  

二、v-model作用:

用来收集表单数据

  • 单选按钮:收集的是value值 收集的数据存放在字符串中
  • 多选按钮:收集的是value值 收集的数据存放在数组中
  • 下拉菜单:
    1. 选中一个:

      • 收集的是value值 收集的数据存放在字符串中;
    2. 选中多个(ctrl + 选项):

      • 如果想同时选中多个,首先要给select加上multiple属性,然后把数据存放到数组当中
  • 文本域和普通的表单元素都可用字符串收集

三、表单修饰符:

  • .number
  1. 限制用户输入的数据必须是数字
  2. 把用户输入的数据转转成数字类型
  • .lazy

    • 当文本框失去焦点时 数据响应视图变化
  • .trim

    • 对视图中的数据进行处理,再响应到Vue中

四、按键修饰符:

  • .enter / .13 在enter键抬起时触发
  • .ctrl
  • .alt
  • .tab
  • .delete (捕获“删除”和“退格”键)
  • .esc
  • .space
  • .up
  • .down
  • .left
  • .right
<div id="app">
    <input type="text" @keyup.alt.13="fn">按键修饰符
</div>
let vm = new Vue({
    el: '#app',
    methods: {
        fn(ev){
            console.log(ev.keyCode)
        }
    }
})

五、事件修饰符

1、@click=fn 和 @click=fn() 的区别:

后者必须要手动传入$event    才能在回调函数中使用事件对象

2、常用事件修饰符:

.once   为元素绑定一次性事件
.stop   阻止事件冒泡
.capture  为元素绑定一个事件捕获阶段触发的回调函数 
.self  为元素绑定一个只在自身上出发的事件,也就是说事件捕获和事件冒泡都不会让.self绑定的函数执行
.prevent 阻止元素的默认行为   
<div id="app">
    <!-- 当你给元素绑定事件时, = 右侧的事件函数加不加括号都一样能触发?有什么区别?
        不写括号时,系统会传一个事件对象event
        写括号时,系统的事件对象不会再主动传递,需要自己手动传递
    -->
    <!-- <p @click ="fn($event)">{{text}}</p> -->

    <div @click="parent">
        parent
        <div @click.self="son">
            son
            <div @click="grandson">
                grandson
            </div>
        </div>
    </div>

    <!-- 点击跳转是a标签的默认行为,阻止元素的默认行为以后就不会跳转 -->
    <a href="http://www.baidu.com" @click.prevent>百度</a>

</div>
let vm = new Vue({
    el: '#app',
    data: {
        text: '我是一个段落'
    },
    methods: {
        fn(e){
            console.log(e)
        },
        parent(){
            console.log('parent');
        },
        son(){
            console.log('son');
        },
        grandson(){
            console.log('grandson');
        },
    }
})

六、computed

<div id="app">
    姓:<input type="text" v-model="firstName">
    字:<input type="text" v-model="lastName">
    
    <!-- 这个是写在computed属性当中,而fullName表示一个属性,内部默认有个get方法 -->
    <!-- <p>{{firstName + lastName}}</p> -->
    
    <!-- 这个是写在methods属性当中,这表示一个真正的函数,要想显示必须加括号执行它 -->
    <!-- <p>{{fullName()}}</p>     -->
    <p>{{fullName()}}</p>
</div>
let vm = new Vue({
    el: '#app',
    data: {
        firstName: "",
        lastName: ''
    },
    methods:{
        fullName(){
            return this.firstName + this.lastName;
        }
    },
    computed:{  // 计算属性
        // 这里的fullName是一个属性,原理如下
        // fullName(){
        //     return this.firstName + this.lastName;
        // }
        // 上面的函数和下面的等价
        // fullName: {
        //     get(){
        //         return this.firstName + this.lastName;
        //     }
        // }
        // computed和data中的属性的区别:
            // data中的属性是可读可写的
            // computed中的属性只可读不可写
    }
})

七、computed和methods的区别:

  • 方法写在methods中,当视图重新渲染时,方法会再次执行
  • 属性写在computed中,当视图重新渲染时,get不会再次执行(会存缓存中读取数据,有利于性能优化)
<div id="app">

    <p @click="fn">computed和methods的区别</p>

    <p>{{sum}}</p>

    <p>{{c}}</p>

</div>
let vm = new Vue({
    el: '#app',
    data: {
        a: 1,
        b: 2,
        c: ''
    },
    methods: {
        fn(){
            this.c = "海文";
            console.log('点击');
        },
        // sum(){
        //     console.log('methods中的额sum')
        //     return this.a + this.b;
        // }
    },
    computed: {
        sum() {
            console.log('methods中的额sum')
            return this.a + this.b;
        }
    }
})

day4

一、给标签绑定属性:v-bind

  • :属性=“属性值”

    • <==> :属性名=“属性值”
  • :class=“对象”

    • 只要对象的键值为true,则标签就回有对应键名的类名
  • :class=“数组”

    • 只要数组中存在某一项,则标签就会有对应数组项的类名

注意:

如果自定义属性的属性值不加"",它默认会加的

绑定一个对象:键值为假,就不会添加属性
objClass: {
red: true,
c_blue: false
}

绑定一个数组:数组的每一项为一个属性值,会有重复的

<div id="app">
    <!-- <p v-bind:title='text' :data-id="id" class="on" :class='["wwg", "long"]'>v-bind</p> -->

    <!-- <p v-bind:title='text' :data-id="id" class="on" :class='["wwg", "wwg"]'>v-bind</p> -->

    <p @click="fn" :class="objClass">v-bind</p>

</div>
let vm = new Vue({
    el: '#app',
    data: {
        text: '这是v-bind绑定的title',
        id: 1,
        objClass: {
            red: true,
            c_blue: true
        },
    },
    methods: {
        fn() {
            this.objClass.red = !this.objClass.red;
        }
    }
})

二、绑定样式:

  • :style=对象

    • 对象的键名是标签的属性名 键值是标签的属性值
  • :style=数组

    • 多个对象的键名是标签的属性名
    • 多个对象的键值是标签的属性值

style 和 :style中的样式显示的顺序是怎么样的???

​ 不论style写在前面还是后面,标签总是显示Vue实例绑定的样式,这里涉及到Vue实例的生命周期,因为在style中的样式是页面渲染时候就存在的,而Vue实例中的样式是经过一系列生命周期函数的,在mounted()函数执行完成后才将data挂载到el上的,所以最终显示的是Vue实例绑定的样式。

<div id="app">
    <!-- <p style="background-color: lightblue;">我是p标签</p> -->
    
    <!-- <p :style="{backgroundColor: 'red'}">我是p标签</p> -->
    <!-- <p :style="styleObj1">/我是p标签</p> -->
    <p style="background-color: red;" :style="[styleObj1, styleObj2]">我是p标签</p>
</div>
let vm = new Vue({
    el: '#app',
    data: {
        styleObj1: {
            backgroundColor: 'lightblue',
            width: '800px',
        },
        styleObj2: {
            width: '200px',
            height: '100px'
        }
    }
})

三、watch侦听器__异步更新队列

<div id="app">
    <p id="op" @click="fn">{{text}}</p>
    {{b}}
    {{c}}
    {{arr}}
</div>
let vm = new Vue({
    el: '#app',
    data: {
        a: 1,
        text: '原来的文字',
    },
    methods: {
        fn(){
            // 修改data中的数据
            this.text = '更新后的文字';
            // // 在这里即使修改了data中的额数据,但是data中的数据不会立马映射到视图中,那么它什么时候映射到视图中?
            // console.log(op.innerText)
            // debugger;

            // 当视图更新完成后,回调函数触发
            // this.$nextTick(() => {
            //     console.log(op.innerText  );
            //     debugger;
            // });
            
            // debugger
            // 什么情况下data中的数据会发生变化?
            // 其实在Vue实例的过程中就会生成一个监视器_watchers,当data中的数据发生变化时,_watchers就会被触发,从而更新数据
            // 注意:data中的所有数据共用一个监视器watcher,而computed中的每个属性都一个监视器watcher,在这里debugger后可以看到watchers中的长度为3,watch中每个选项也独占一个监视器,是确定data中具体属性的属性值发生变化(updated也能确定data中属性的属性值发生变化,但是无法确定是哪个属性发生变化)
        }
    },
    computed: {
        b(){
            return 1;
        },
        c(){
            return 2;
        }
    },
    watch: { // watch选项,是确定data中具体属性的值发生变化
        text() { // a函数在data的中的a属性发生变化时触发,必须跟data中的数据同名
            console.log(1);
        },
    },
})

day7 父子组件传值、生命周期–插槽

一、父子组件的生命周期:

1、定义子组件 --》 2.注册子组件 --》 3.使用子组件(4种使用template方案)
2、子组件的生命周期函数与父组件的生命周期函数的关系:
父组件先创建 ----------------------》 子组件创建 ---------------》 子组件挂载 -----------》 父组件挂载
beforeCreate created beforeMount beforeCreate created boforeMount mounted mounted

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vue组件_父子组件的生命周期</title>
    <script src="../vue.js"></script>
</head>
<body>
    <div id="app">
        <!-- 使用子组件模板:方案一 -->
        <son></son>

        <!-- 使用子组件模板:方案四 -->
        <!-- <son inline-template>
            <div>
                <p>北京</p>
                <p>上海</p>
                <p>广州</p>
                <p>深圳</p>
            </div>
        </son> -->

    </div>
    <!-- template模板中的id不是选择器,所以必须是【表情】 -->
    <!-- 引入子组件 方案二(推荐) -->
    <template id="son">
        <div>
            <p>北京</p>
            <p>上海</p>
            <p>广州</p>
            <p>深圳</p>
        </div>
    </template>
    <!-- 引入子组件 方案三 -->
    <!-- <script  type="text/x-template" id="son">        
        <div>
            <p>北京</p>
            <p>上海</p>
            <p>广州</p>
            <p>深圳</p>
        </div>
    </script> -->

    <script>
        
        /*
            1、组件:通过Vue构造函数实例出来的对象就叫做组件
            1》定义组件  2》在根组件或者父组件中注册组件
        */

        // 定义子组件:son这个组件是由template这个模板渲染出来的
        let son = {
            // 对于这个子组件来说,我们 只能有一个子元素,但是子元素可以嵌套其它元素
            template: '#son',
            // 使用子组件模板:方案一 
            // template: `<div>
            //                 <p>北京</p>
            //                 <p>上海</p>
            //                 <p>广州</p>
            //                 <p>深圳</p>
            //             </div>`
            beforeCreate() {
                console.log(' 子组件 beforeCreate')
            },
            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')
            }
        }

        // 根组件
        let vm = new Vue({
            el: '#app',
            data: {

            },
            // 注册组件
            components: {
                son
            },
            beforeCreate(){
                console.log(' 根组件 beforeCreate')
            },
            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')
            }
        })

        /*
            1.定义子组件 --》 2.注册子组件 --》 3.使用子组件(4种使用template方案)
            2、子组件的生命周期函数与父组件的生命周期函数的关系:
                父组件先创建 ----------------------》 子组件创建 ---------------》 子组件挂载 -----------》 父组件挂载
            beforeCreate created beforeMount     beforeCreate created       boforeMount mounted          mounted
        
        */
    
    
    </script>
</body>
</html>

二、父组件传值–子组件校验:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>02.父组件传值_子组件校验</title>
    <script src="../vue.js"></script>
</head>
<body>
    <div id="app">
        <son :msg="msg"></son>
    </div>

    <template id="son">
        <!-- 对于每个子组件,我们只能有一个元素,但是可以包裹其他元素 -->
        <div>我是子组件,父组件传递的数据是msg:{{msg}}, b:{{b}}</div>
    </template>
    
    <script>
        /*
        使用组件的步骤:
            1.定义组件
            2.注册组件
            3.写好html模板
            4.使用组件
        
        父组件和子组件通信:
            根组件的数据 ---》 子组件
            通过绑定属性的方式传递数据,并且要在子组件中定义一个props属性承接父组件的数据

        子组件的props这个选项,专门用来存放接受父组件数据对应的变量

        子组件的data选项必须是一个函数,数据存放在函数返回的对象当中

        * 只要是组件,都是双向数据绑定的
        * 组件内部的this都指向对应的组件

            
        */
        // 定义子组件
        let son = {
            // props: ['msg'], // 用来承接根组件的数据

            // 校验父组件传过来的参数
            props: {
                msg: { // 校验变量msg
                    // type: String,   // 检测类型
                    // required: true   // 设置为必传参数
                    default: 3
                }
            },

            template: '#son',
            // 子组件中的data选项不能只是一个对象,必须是一个data函数,在函数返回值中存放子组件要控制的数据
            data(){
                return {
                    b: 3
                }
            }
        }

        let vm = new Vue({
            el: '#app',
            data: {
                // msg: 2
            },
            components: {   // 注册组件
                son
            }
        })
    
    </script>
</body>
</html>

三、单向数据流:

单向数据流

  • 子组件不能直接修改父组件中 传递的数据
  • 解决方法:
    可以在子组件data选项中存储父组件传递的数据,之后修改子组件中的数据即可
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>03.单向数据流</title>
    <script src="../vue.js"></script>
</head>
<body>
    <div id="app">
        <son :msg='msg' :a='a'></son>
    </div>
    <template id="son">
        <div @click="change">我是子组件,父组件传递的数据是{{msg}}, {{b}}</div>
    </template>
    <script>
        let son = {
            data(){
                return {
                    b: this.a
                }
            },
            props: ['msg', 'a'],
            template: '#son',
            methods: {
                change(){
                    console.log('函数执行了');
                    this.b = 2
                }
            }
        }
        let vm = new Vue({
            el: '#app',
            data: {
                msg: 2,
                a: 1
            },
            components: {
                son
            }
        })  
    
    </script>
</body>
</html>

四、插槽:

slot 可以让组件更加灵活
slot插槽 不带name属性,会有隐含的名字’default’ 可以给slot加上name属性

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>插槽</title>
    <script src="../vue.js"></script>
</head>
<body>
    <div id="app">
        <son>
            <h2 slot="header">标题</h2>
            <h3 slot="footer">页脚</h3>
            <template slot="more">
                <h2>一个槽可以插入多个数据</h2>
                <h2>标题</h2>
                <h3>页脚</h3>
                <h2>标题</h2>
                <h3>页脚</h3>
                <h2>标题</h2>
                <h3>页脚</h3>
                <h2>标题</h2>
                <h3>页脚</h3>
            </template>
        </son>
    </div>
    
    <template id="son">
        <div>
            <!-- 具名插槽 -->
            <slot name="header"></slot>
            我是子组件的数据
            <slot name="more"></slot>
            <!-- 匿名插槽 -->
            <slot name="footer"></slot>
        </div>
    </template>

    <script>
        /*
            组件可以复用
        */
        let son = {
            template: '#son'
        }

        let vm = new Vue({
            el: '#app',
            components: {
                son
            }
        })  
    </script>
</body>
</html>

day8 Vue组件补充

一、如何获取单个ref标记的单个节点:

this.refs 获取所有含有ref标记的单个节点
如果使用v-for获取相同的ref标记,则会获取到多个节点
如果ref标记到组件上,则获取的是整个组件

异步更新DOM:

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

<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>

<body>


    <div id="app">
        <son ref="son"></son>
    </div>

    <template id="son">
        <div>{{msg}}</div>
    </template>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>


    <script>

        let son = {
            template: '#son',
            data() {
                return {
                    msg: '我是子组件的数据'
                }
            },
            mounted() {
                this.msg = 'xxx';   //修改msg
            }
        }
        let vm = new Vue({
            el: '#app',
            components: {
                son
            },
            mounted() {
                this.$nextTick(() => {
                    console.log(this.$refs.son.$el.innerText);
                })
            }
        })

    </script>

</body>

</html>

二、父组件 —> 子组件:

父组件 —> 子组件 是通过 绑定属性来传递数据的

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>father-son</title>
    <script src="../vue.js"></script>
</head>
<body>
    <div id="app">
        <son :a="msg"></son>
    </div>

    <template id="son">
        <div>{{a}}</div>
    </template>

    <script>
        let son = {
            template: '#son',
            props: ['a'],
        }
    
        let vm = new Vue({
            el: '#app',
            data: {
                msg: '我是 父组件'
            },
            components: {
                son
            }
        })
    </script>
</body>
</html>

三、子组件 —> 父组件:

子组件 —> 父组件 是 通过 触发事件 来实现数据传递

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>son-father</title>
    <script src="../vue.js"></script>
</head>
<body>
    <div id="app">
        <son @send="fn"></son>
    </div>
    <template id="son">
        <div @click="fn">
            我是子组件 向父组件传递的数据是:{{msg}}{{name}}
        </div>
    </template>
    <script>
        let son = {
            template: '#son',
            data(){
                return {
                    msg: '我是',
                    name: '子组件'
                }
            },
            methods: {
                fn(){
                    this.$emit('send', this.msg, this.name)
                }
            }
        }
        let vm = new Vue({
            el: '#app',
            methods: {
                fn(val1, val2){
                    console.log('子组件传递的数据是:'+ val1 + val2);
                }
            },
            components: {
                son
            }
        })
    
    </script>
</body>
</html>

四、非父子级关系的数据传递:

非父子级关系的数据传递 是 通过 事件车eventBus 来实现数据传递的
简单的说事件车其实就是中间介质,是两个组件数据传递的桥梁

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>son-son</title>
    <script src="../vue.js"></script>
</head>
<body>
    <div id="app">
        <heaven></heaven>
        <xiaoming></xiaoming>
    </div>
    <template id="heaven">
        <div>{{msg}}</div>
    </template>
    <template id="xiaoming">
        <div @click="fn">{{msg}}</div>
    </template>
    

    <script>
        let eventBus = new Vue();
    
        let heaven = {
            template: '#heaven',
            data(){
                return {
                    msg: 'I am heaven'
                }
            },
            created(){
                eventBus.$on('xxx', (msg)=>{    // heaven组件先订阅一个事件
                    console.log('xxx事件已经触发了,我监测到了', this.msg)
                });
            }
        }
        let xiaoming = {
            template: '#xiaoming',
            data(){
                return {
                    msg: 'I am xiaoming'
                }
            },
            methods: {
                fn() {
                    eventBus.$emit('xxx', this.msg);
                }
            }
        }
        let vm = new Vue({
            el: '#app',
            components: {
                heaven,
                xiaoming
            }
        })
    
    </script>
</body>
</html>

day10 路由

一、局部组件——全局组件

局部组件必须要在某个组件中注册后才能使用,但全局组件不需要注册就可以在任意位置使用

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>01.局部组件_全局组件</title>
    <script src="../vue.js"></script>
</head>
<body>
    <div id="app">
        <home></home>
        <user></user>
    </div>
    <script>
        // 全局组件
        Vue.component('home', {
            template: '<div>首页</div>'
        });
        Vue.component('user', {
            template: '<div>用户中心</div>'
        })
        // 局部组件
        // let home = {
        //     template: '<div>首页</div>'
        // }
        // let user = {
        //     template: '<div>用户中心</div>'
        // }        
        let vm = new Vue({
            el: '#app',
            components: {
                // home, 
                // user
            }
        })
    </script>
</body>
</html>

二、动态组件:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>02.动态组件</title>
    <script src="../vue.js"></script>
</head>
<body>
    <div id="app">
        <component is="user"></component>
    </div>
    <script>
    /*
        动态组件:component is属性必须写 
    */        
        // 局部组件
        let home = {
            template: '<div>首页</div>'
        }
        let user = {
            template: '<div>用户中心</div>'
        }
        
        let vm = new Vue({
            el: '#app',
            components: {
                home, 
                user
            }
        })    
    </script>
</body>
</html>

三、组件切换 keep-alive

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>03.组件切换</title>
    <script src="../vue.js"></script>
</head>
<body>
    <div id="app">
        <input type="radio" v-model="radio" value="home">主页
        <input type="radio" v-model="radio" value="user">用户中心
        <!-- keep-alive 保持存活 只要创建过  就保存在缓存中,如果没有keep-alive,那么组件切换会每次重新创建 -->
        <keep-alive>
            <component :is="radio"></component>
        </keep-alive>
    </div>

    <script>
        let home = {
            template: '<div>首页</div>',
            created(){
                alert('home created');
            }
        }
        let user = {
            template: '<div>用户中心</div>',
            created() {
                alert('user created');
            }
        }
    
        let vm = new Vue({
            el: '#app',
            data: {
                radio: 'home'
            },
            components: {
                home,
                user
            }
        })

        /*
            使用动态组件时,每一次切换都会重新创建组件(判断组件是否被重新创建,就看它的created方法是否重新执行了),这样会影响页面的性能,
            解决方案:把动态组建放到缓存中  使用内置组件  keep-alive

            keep-alive  可以保证内部组件不被销毁
        */
    </script>
</body>
</html>

四、路由:

  • router-link 组件的属性(内置组件):

    • tag 改变组件在页面中的种类
  • to 指定跳转的地址

    问题:to前面为什么加 :

    • 解决:to是属性,= 右边的是字符串,要想把它变成js代码,就加:

      • 常见的就是 = 后面是一个对象的时候就加 : 只有一个路由的时候不用加

      • <router-link to="/home">首页</router-link>
        <router-link :to="{path: '/home'}">首页</router-link>
        
        // 以上这两种情况都是对的
        
  • query传参表示:

    • 通过查询字符串的方式发送数据
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>04.路由</title>
</head>
<body>
    <div id="app">
        <!-- 1.a标签切换 -->
        <!-- <a href="#/home">首页</a>
        <a href="#/user">用户中心</a> -->
        
        <!-- 2.router-link 中 to属性中path切换 -->
        <!-- <router-link :to="{path:'/home', query: {a: 1}}" tag="button">首页</router-link>
        <router-link :to="{path:'/user'}" tag="button">用户中心</router-link> -->
        
        <!-- 3.router-link 中 to属性中name切换 并且可以传递参数-->
        <router-link :to="{name: 'homelink', query: {a: 1}}" tag="button">首页</router-link>
        <router-link :to="{name: 'userlink'}" tag="button">用户中心</router-link>

        <router-view></router-view>
    </div>
    
    <script src="../vue.js"></script>
    <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
    <script>
    
    // 定义局部组件
    let home = {
        template: '<div>首页</div>',
        created(){
            // 注意这里的参数是存在与$route里面的
            console.log(this.$route.query);
        }
    }
    let user = {
        template: '<div>用户中心</div>'
    }
    // 1.定义组件和路由的映射表
    let routes = [
        {path: '/home', name: 'homelink', component: home},
        {path: '/user', name: 'userlink', component: user},
        // 当匹配不到上面的路由时,就进行重定向到/home路由,然后渲染home组件
        {path: '*', redirect: '/home'}  // 默认匹配home路由,然后渲染出来
    ];

    // 2.实例化路由对象,将组件和路由的映射表 注入 到路由对象中
    let router = new VueRouter({
        routes
    })
    
    let vm = new Vue({
        el: '#app',
        // 3.将路由对象注入到根实例中(这一步之前在Vue实例中是没有_route和_router属性的)
        router
    })

/*
    router-link 组件的属性
        tag 改变组件在页面中的种类

        to  指定跳转的地址
            问题:为什么加 : 
            解决:to是属性,= 右边的是字符串,要想把它变成js代码,就加:

    query传参表示: 通过查询字符串的方式发送数据   
*/  
    </script>
</body>
</html>

五、动态路由——声明式导航

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>05.动态路由</title>
</head>
<body>
    <div id="app">
        <!-- 通过查询字符串的方式发送数据时,to属性中必须使用path -->
        <!-- <router-link :to="{path: '/home/41asdaasdf', query: {a: 1}}" tag="button">首页</router-link> -->
        <router-link :to="{name: 'homelink', params: {id: 1}}" tag="button">首页</router-link>
        <!-- 通过params发送数据时要注意两点:
                1.to属性中必须使用name
                2.params参数中的键名必须与 组件和路由的映射表中 path中的变量相同
        -->
        <router-view></router-view>
    </div>
    
    <script src="../vue.js"></script>
    <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
    <script>
    
    // 定义局部组件
    let home = {
        template: '<div>首页</div>'
    }
    let user = {
        template: '<div>用户中心</div>'
    }
    // 1.定义组件和路由的映射表
    let routes = [
        /*
            动态路由:
                含有可变参数的路由
        */
        {path: '/home/:id', name: 'homelink', component: home},
    ];

    // 2.实例化路由对象,将组件和路由的映射表 注入 到路由对象中
    let router = new VueRouter({
        routes
    })
    
    let vm = new Vue({
        el: '#app',
        // 3.将路由对象注入到根实例中(这一步之前在Vue实例中是没有_route和_router属性的)
        router,
    })
    
    </script>
</body>
</html>

六、动态路由——编程式导航:

r o u t e 和 route和 routerouter的区别:

  • $route:是放属性的
  • $router:是放方法的

声明式导航 和 编程式导航的区别:

  • 声明式导航:通过标签的to属性跳转
  • 编程式导航:通过js代码跳转
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>06.编程式导航</title>
    <script src="../vue.js"></script>
    <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
</head>
<body>
    <div id="app">
        <button @click="goHome">首页</button>
        <button @click="goUser">用户中心</button>
        <button @click="goBack">返回上一页</button>
        <router-view></router-view>
    </div>
    <script> 
   
    // 定义局部组件
    let home = {
        template: '<div>首页</div>'
    }
    let user = {
        template: '<div>用户中心</div>'
    }
    let back = {
        template: '<div>返回上一页</div>'
    }

    // 定义组件与路由的映射表
    let routes = [
        { path: '/home', name: 'homelink', component: home},
        { path: '/user/:id', name: 'userlink', component: user},
        {path: '*', redirect: '/home'}
    ];

    // 实例化路由对象,将组件和路由的映射表注入到路由对象中
    let router = new VueRouter({
        routes
    })

    let vm = new Vue({
        el: '#app',
        // 将路由对象注入到根实例中(这一步之前在Vue实例中是没有_route和_router属性的)
        router,
        methods: {
            goHome(){
                this.$router.push({
                    path: '/home',
                    query: {a: 1, b: 2}
                })
            },
            goUser(){
                this.$router.push({
                    name: 'userlink',
                    params: {
                        id: 1
                    }
                })
            },
            goBack(){
                this.$router.back();
            }
        }
    })
    </script>
</body>
</html>

七、动态加载数据:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>07.动态加载数据</title>
</head>
<body>
    <div id="app">
        <router-link :to="{name: 'articlelink', params: {page: 1}}" tag="button">第1章</router-link>
        <router-link :to="{name: 'articlelink', params: {page: 2}}" tag="button">第2章</router-link>
        <router-link :to="{name: 'articlelink', params: {page: 3}}" tag="button">第3章</router-link>

        <!-- $route中params或者query中数据发生变化时,将视图重新渲染一次,这样就相当于组件的生命周期函数重新执行一次 -->
        <router-view :key="Math.random()"></router-view>
    </div>

    <script src="../vue.js"></script>
    <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
    <script>
        // 定义局部组件
        let article = {
            template: '<div>这是第{{$route.params.page}}篇文章</div>',
            // watch: {
            //     $route(){
            //         alert(`这是第${this.$route.params.page}章数据`);
            //     }
            // },
            created(){
                // 这个组件在更新时没有重新创建,只是修改了参数,这样不利于我们发送数据
                alert(`这是第${this.$route.params.page}章数据`);
            }
        }
        // 定义组件与路由的映射表
        let routes = [
            {path: '/article/:page', name: 'articlelink', component: article}
        ]

        // 实例化路由对象
        let router = new VueRouter({
            routes
        })
    
        let vm = new Vue({
            el: '#app',
            router
        })
    </script>
</body>
</html>

八 vue实现路由按需加载的3种方式:

  • vue异步组件:
  • es提案的import:
  • webpack的require.ensure():

vue异步组件技术 ==== 异步加载
vue-router配置路由 , 使用vue的异步组件技术 , 可以实现按需加载 .
但是,这种情况下一个组件生成一个js文件

/*vue异步组件技术*/
{
    name: 'home',
    path: '/home',
    component: resolve => require(['@/components/home'], resolve)
},
{
    name: 'sort',
    path: '/sort',
    component: resolve => require(['@/components/sort'], resolve)
},

路由懒加载(使用import)

const Home = () => import('@/components/home')
{
    home: 'home',
    path: '/home',
    component: Home
}

webpack提供的require.ensure()
vue-router配置路由,使用webpack的require.ensure技术,也可以实现按需加载。
这种情况下,多个路由指定相同的chunkName,会合并打包成一个js文件。

/* 组件懒加载方案三: webpack提供的require.ensure() */
{
  path: '/home',
  name: 'home',
  component: r => require.ensure([], () => r(require('@/components/home')), 'demo')
}, {
  path: '/index',
  name: 'Index',
  component: r => require.ensure([], () => r(require('@/components/index')), 'demo')
}, {
  path: '/about',
  name: 'about',
  component: r => require.ensure([], () => r(require('@/components/about')), 'demo-01')
}

day11 路由守卫

一、路由嵌套:

  • vue-router 做的是单页面应用

  • exact 精确匹配 仅限于有子路由的使用 只有点击它本身时,才会添加两个类名(router-link-exact-active router-link-active)

  • router-link-exact-active 和 router-link-active的区别:

    • router-link-exact-active :精确匹配,如果给它设置了样式,点击子路由,父路由不会显示对应的样式
    • router-link-active : 不精确匹配,如果给它设置了样式,点击子路由,父路由也会显示对应的样式

    简单的说:/router 可以匹配/router 和 /router/2
    而如果使用exact的话/router 则只能匹配/router,不能匹配/router/2

  • event属性:默认是点击触发,可以修改

    • 如:event=“mouseenter”
  • meta属性存储源数据

    • 如:点击导航,修改HTML页面中的title
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>01.路由嵌套</title>
    <script src="../vue.js"></script>
    <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
    <style>
        * {
            margin: 0;
            padding: 0
        }

        #app {
            position: relative;
            width: 800px;
            height: 500px;
            border: solid;
            margin: 50px auto;
        }

        #app .navlist {
            overflow: hidden;
        }

        a {
            text-decoration: none;
            line-height: 40px;
            height: 40px;
            text-align: center;
        }

        #app .navlist a {
            float: left;
            width: 20%;

            box-shadow: 0 0 10px 0 blue inset;

        }

        #app .about {
            position: absolute;
            left: 0;
            right: 0;
            top: 60px;
            width: 100%;
            margin: auto;
            height: 440px;
            box-shadow: 0 0 10px 0 blue inset
        }

        #app .about ul {
            float: left;
        }

        #app .about li {
            list-style-type: none;
            width: 162px;
            height: 40px;
            margin: 20px 0;
            box-shadow: 0 0 10px 0 blue inset;
        }

        #app .about .heaven {
            float: right;
            width: 600px;
            height: 400px;
            box-shadow: 0 0 10px 0 blue inset
        }
        /* .router-link-active{
            background-color:rgba(0,0,0,.5)
        } */

        .active{
            background: rgba(0,0,0,.5);
        }
    
    </style>
</head>
<body>
    <div id="app">
        <router-link to="/home" event="mouseenter">首页</router-link>
        <router-link to="/user">用户中心</router-link>
        <router-link to="/about" exact>关于我们</router-link>
        <router-link to="/login">登录</router-link>
        <router-link to="/register">注册</router-link>

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

    <template id="about">
        <div class="about">
            <ul>
                <li><router-link to="/about/concat">联系我们</router-link></li>
                <li><router-link to="/about/partner">合作伙伴</router-link></li>
                <li><router-link to="/about/address1">公司地址</router-link></li>
            </ul>

            <router-view class="heaven"></router-view>
        </div>
    </template>

    <script>
        /*
            vue-router 做的是单页面应用
        
            exact 精确匹配 仅限于有子路由的使用 只有点击它本身时,才会添加两个类名(router-link-exact-active router-link-active)

            router-link-exact-active 和 router-link-active的区别:
                router-link-exact-active :精确匹配,如果给它设置了样式,点击子路由,父路由不会显示对应的样式
                router-link-active : 不精确匹配,如果给它设置了样式,点击子路由,父路由也会显示对应的样式

            简单的说:/router 可以匹配/router 和 /router/2
                而如果使用exact的话
                /router 则只能匹配/router,不能匹配/router/2

            event属性:默认是点击触发,可以修改
            event="mouseenter"

            meta属性存储源数据
        */
        let home = {
            template: '<div>首页</div>',
            created(){
                document.title = this.$route.meta.title;
            }

        }
        let user = {
            template: '<div>用户中心</div>',
            created() {
                document.title = this.$route.meta.title;
            }
        }
        let about = {
            template: '#about',
            created() {
                document.title = this.$route.meta.title;
            }
        }
        let login = {
            template: '<div>登录</div>',
            created() {
                document.title = this.$route.meta.title;
            }
        }
        let register = {
            template: '<div>注册</div>'
        }

        let concat = {
            template: '<div>110</div>'
        }
        let partner = {
            template: '<div>阿里云大学</div>'
        }
        let address1 = {
            template: '<div>广州天河区</div>'
        }

        // 路由和组件的映射表
        let routes = [
            {
                path: '/home', 
                component: home,
                meta: {
                    title: '首页'
                }
            },
            {
                path: '/user', 
                component: user,
                meta: {
                    title: '用户中心'
                }
            },
            {
                path: '/about', 
                component: about,
                children: [ // 配置子路由,子路由没有 /
                    {path: 'concat', component: concat},
                    {path: 'partner', component: partner},
                    // 组件和原生html标签重复就会报错
                    {path: 'address1', component: address1}
                ],
                meta: {
                    title: '关于我们'
                }
            },
            {
                path: '/login', 
                component: login,
                meta: {
                    title: '登录'
                }
            },
            {
                path: '/register', 
                component: register,
                meta: {
                    title: '注册'
                }
            }
        ]

        // 实例化路由对象
        let router = new VueRouter({
            routes,
            // 为不精确匹配的类名router-link-active重命名
            // linkActiveClass: 'active'
            // 为精确匹配的类名router-link-exact-active重命名
            linkActiveClass: 'active'
        })


        let vm = new Vue({
            el: '#app',
            router
        })

        /*
            注意点:
                1.配置子组件映射表时,path中的路由是不写 /
                2.在模板中写子组件时,要带上父路由,这样才能匹配到对应的组件,例如 /about/concat
        */
    
    </script>
</body>
</html>

day12 Vue脚手架

一、Vue中的入口文件main.js的作用:

  • 初始化Vue生成的实例对象,去挂载或绑定模板文件(public/index.html)中的app对象,我们所写的代码都放在模板文件中的app对象里面

一、axios函数:

  • axios是一种发送请求的工具,跟ajax很相似
  • 使用外链的形式从github上查找引入js脚本
  • 把axios函数注入到Vue的原型上,这样每个Vue实例都可以调用axios函数,从而发送请求
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>01.新闻列表</title>
    <script src="../vue.js"></script>
    <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
    <div id="app">
        <router-view></router-view>
    </div>

    <template id="newsList">
        <div class="newsList">
            <ul v-for="newList in newsList">
                <li>
                    <!-- 
                        注意:params发送数据只能用name,并且参数对象中的键名必须和组件路由映射表中的动态路由相同
                     -->
                    <!-- <router-link :to="{name:'articlelink', params: {id: newList.aid}}"> -->
                    <router-link :to="{path: '/article', query: {id: newList.aid}}">
                        {{newList.title}}
                    </router-link>
                </li>
            </ul>
        </div>
    </template>

    <template id="article">
        <div class="article">
            <a href="javascript:history.go(-1)">&lt;&lt;返回新闻列表</a>
            <h2>{{title}}</h2>
            <div v-html="content"></div>
        </div>
    </template>

    <script>
        // 设置默认路径
        axios.defaults.baseURL = 'http://www.phonegap100.com/appapi.php';
        // 设置返回数据的格式
        axios.interceptors.response.use(function (response) {
            return response.data.result;
        })
        // 把axios函数注入到Vue的原型上,这样每个组件(每个Vue组件都是一个实例)都可以调用axios
        Vue.prototype.$axios = axios;

        let newsList = {
            template: '#newsList',
            data(){
                return {
                    newsList: []
                }
            },
            // 请求接口数据

            // 方法一:
            // created(){
            //     // 使用axios拉取数据
            //     // axios中的get方法返回一个Promise对象
            //     this.$axios.get('http://www.phonegap100.com/appapi.php?a=getPortalList&catid=20')
            //         .then(res => {
            //             // console.log(res.data.result)
            //             this.newsList = res.data.result
            //         })
            // }

            // 方法二:
            // async created() {
            //     // 解构赋值
            //     let {data: {result}} = await this.$axios.get('http://www.phonegap100.com/appapi.php?a=getPortalList&catid=20');
            //     this.newsList = result;
            // }

            // 方法三:直接指定返回我们需要的数据,这样就不用解构数据
            async created() {
                this.newsList = await this.$axios.get('?a=getPortalList&catid=20');
            }

        }

        let article = {
            template: '#article',
            data(){
                return {
                    content: '',
                    title: ''
                }
            },
            // watch: {
            //     $route(){
            //         alert(1)
            //     }
            // },
            async created(){
                // let [{title, content}] = await this.$axios.get('?a=getPortalArticle&aid=' + this.$route.params.id);
                let [{title, content}] = await this.$axios.get('?a=getPortalArticle&aid=' + this.$route.query.id);                
                this.title = title;
                this.content = content;
            }
        }
        // 组件和路由的映射表
        let routes = [
            {path: '/', component: newsList},
            // {path: '/article/:id', name: 'articlelink', component: article} 
            {path: '/article', name: 'articlelink', component: article}
        ]
        // 实例化路由对象
        let router = new VueRouter({routes})

        let vm = new Vue({
            el: '#app',
            router
        })
    </script>
</body>
</html>

day13

  • v-for会报错,要加key

  • 如何判断后台是否允许前端跨域请求数据?

    • 看请求头 request Headers 中是否有origin字段,如果有表示不允许跨域,如果没有就表示可以跨域
  • Vue解决跨域的方案:

  1. 治标不治本的一种:降低浏览器的安全等级

    • 谷歌浏览器解决跨域问题 --disable-web-security --user-data-dir
    • 这种方法实际就是降低浏览器的安全
  2. 服务器代理:

    • 在baidu中找proxyTable:webpack之proxyTable设置跨域
      在config的index.js文件中找到proxyTable,粘贴代码,将重写接口中的数据设置空字符串
    proxyTable: {
    '/api': {
      target: 'http://www.abc.com',  //目标接口域名
      changeOrigin: true,  //是否跨域
      pathRewrite: {
        '^/api': '/api'   //重写接口
      }
    },
    
  3. 设置请求头:

    • 在服务器中设置请求头
    app.use('/login', (req, res) => {
        res.header("Access-Control-Allow-Origin", "*");
        //允许的header类型
        res.header("Access-Control-Allow-Headers", "content-type");
        //跨域允许的请求方式 
        res.header("Access-Control-Allow-Methods", "DELETE,PUT,POST,GET,OPTIONS");
        console.log(req.body)
        res.send('1')
    })
    
  4. JSONP

    • 1、我们引入的script标签中的src与我们的本地域名肯定不是同源的,但是我们可以访问数据,这就表明script的src属性能够实现跨域请求资源的。
    • 2、script标签请求资源的本质是一串js代码

前端框架:

  • jQuery 2006 - 2013
  • angular 2009 - 2014 MVC
  • Recat 2013 虚拟DOM
  • Vue 2014

实例化Vue

new Vue({
    el : '#app'
    data : {

    }
})
  • 使用Vue就是实例化
    配置参数:
    el : 将实例与配置参数联系起来的
    data : 数据
    绑定数据到视图:
    {{}}
    实时更新

Vue是借鉴Recat和angular的优点,使用MVVM模式

数据绑定:

  1. 绑定在内容上 {{}}
  2. 绑定在属性上 采用指令的方式绑定

常用指令:

  • v-bind 简写 : 可以执行js代码

修饰符

  • v-model.lazy

    • 失去焦点触发 等价于 v-on:change
  • v-model.trim

    • 失去焦点自动去除首尾空格
  • v-model.number

    • 将input输入的内容的类型改成number类型
  • v-model.checkbox

    • true-value=“laoxie”
    • false-value=“jingjing”
* 用法:
v-bind:属性 = "变量"

<!-- 缩写 -->
<img :src="imageSrc">

<!-- 动态特性名缩写 (2.6.0+) -->
<button :[key]="value"></button>

<!-- 内联字符串拼接 -->
<img :src="'/path/to/images/' + fileName">

<!-- class 绑定 -->
<div :class="{ red: isRed }"></div>
<div :class="[classA, classB]"></div>
<div :class="[classA, { classB: isB, classC: isC }]">

<!-- style 绑定 -->
<div :style="{ fontSize: size + 'px' }"></div>
<div :style="[styleObjectA, styleObjectB]"></div>

<!-- 绑定一个有属性的对象 -->
<div v-bind="{ id: someProp, 'other-attr': otherProp }"></div>

<!-- 通过 prop 修饰符绑定 DOM 属性 -->
<div v-bind:text-content.prop="text"></div>
  • v-model 在表单控件或者组件上创建双向绑定

Vue是一个高性能高效率的框架

Vue是一个高性能、高效率的框架

  • VirtualDOM虚拟DOM
    • 结构类似于真实DOM节点的对象
    // 虚拟节点是一个个节点累积起来的
    {
        type: 'div',
        attrs: {},
        children: [{}],
        key: 
        .....
    }
    
  • diff算法
btn.innerText = 'laoxie';
btn.innerText = 'jingjing';
btn.innerText = 'xiaoxie';
btn.innerText = 'laoxie';
  1. 影响页面性能因素

    • 节点操作平凡

      • 测试一段代码执行消耗多少时间
        • console.log(‘jingjing’);
        • console.log(‘jingjing’);
    • 事件绑定数量

      • 优化事件处理的方式 — 事件委托
    • http请求数量

  2. key的作用:

    • Vue识别DOM节点的一个通用机制(用于diff算法)

    • 加key,可以解决排序的一些问题

相关文章