vue的引用

通过script标签的方式进行引用。

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

组件

vue 的核心功能之一就是组件

components

组件基本分类

  • 根组件
  • 可复用的功能组件

根组件的创建

通过 vue 提供的构造函数可以实例化出来一个跟组件实例对象

let app = new Vue(options);

应用最顶层的组件,一般情况下,一个独立的应用有且只有一个根组件(节点)

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

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

<body>
    <!-- VUE的入口 -->
    <div id="app"></div>
    <script>
        // 创建一个根组件
        let app = new Vue({
            // 定义一个模板
            template: '<div>xiaokang.me</div>'
        })
        // 将模板添加到#app这个元素中
        app.$mount('#app')
    </script>
</body>

</html>

image-20200925182627376

上面发生了什么?

其实通过实例化Vue对象,传入配置字段template相当于定义了一个模板,通过Vue对象提供的$mount方法,将其添加到指定的标签元素中。类似于createElementappendChild的概念。

可复用的功能组件

通过 Vue 提供的静态方法 component 窗口可复用的功能组件

let component1 = Vue.component(options)

组件配置选项:https://cn.vuejs.org/v2/api/

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>

</head>

<body>
    <!-- VUE的入口 -->
    <div id="app"></div>
    <script src="./js/vue.js"></script>
    <script>
        // 定义一个可以复用的组件
        Vue.component('tab', {
            template: `<div>这是一个tab选项卡</div>`
        })
        // 创建一个根组件
        let app = new Vue({
            // 定义一个模板
            template: `
            <div>
                <p>xiaokang.me</p> 
                <tab />
                <br />
            </div>
            `
        })

        app.$mount('#app')
    </script>
</body>

</html>

image-20200925191124804

el选项

如果提供了 el,且又没有提供template,那么会自动把el的innerHTML作为template。

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>

</head>

<body>
    <!-- VUE的入口 -->
    <div id="app">
        <h1>xiaokang.me</h1>
        <tab>
    </div>
    <script src="./js/vue.js"></script>
    <script>
        // 定义一个可以复用的组件
        Vue.component('tab', {
            template: `<div>这是一个tab选项卡</div>`
        })
        // 创建一个根组件
        let app = new Vue({
            el: '#app'
        })
    </script>
</body>

</html>

image-20200925191629284

data与更新

使用 vue 的原因,在于数据,页面会根据不同的数据显示不同的内容

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>

</head>

<body>
    <!-- VUE的入口 -->
    <!-- vue中的花括号内可填入的内容
     * 表达式:可以通过运算(执行)得到结果(数据)的公式
     *  - 变量
     *  - 函数调用
     *  - 数学运算
     *
     * 语句:if,else,while,for....
     *
     * 数据来源于组件内部,比如 data 中的数据
     * 解析过程中,会自动绑定组件实例中的数据

     -->
    <div id="app">
        <h1>xiaokang.me</h1>
        <h2>name:{{name}}</h2>
        <tab>
    </div>
    <script src="./js/vue.js"></script>
    <script>
        // 定义一个可以复用的组件
        Vue.component('tab', {
            template: `<div>这是一个tab选项卡</div>`
        })
        // 创建一个根组件
        let app = new Vue({
            el: '#app',
            // 用来挂载组件所需要渲染的数据
            data: {
                name: 'Xioakang',
                age: 18
            }
        })
    </script>
</body>

</html>

将数据传入到Vue对象选项中的data字段,在模板里只需要通过{{}}`即可调用到该属性,例如`{{name}}表示调用data.name,其数据来源于data中的数据,所以不需要写data.name

Vue会把data传入的属性挂载到Vue对象中,因此属性命名时不可以与原有属性冲突。

image-20200925192227986

关于数据的更新,只需要改动属性即可。如图:

image-20200925192509124

拦截数据

简单来说,就是数据修改时拦截数据,这样就实现了只关注数据的修改,而不关心渲染。

vue3 之前,数据的监听是通过 Object.defineProperty 方法来实现的,但是该方法只能监听拦截单个数据,对于对象新增属性无法监听拦截。所以,对于数据对象中新增的属性,我们需要调用 vue 提供的方法来进行处理

对vue的模拟如下:

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>

    <script>
        let obj1 = {
            x: 1,
            y: 2
        }
        function render() {
            console.log('渲染了!');
        }
        let obj2 = Object.assign({}, obj1)
        // 当每次修改x属性时,调用render函数进行渲染。
        Object.defineProperty(obj1, 'x', {
            set(newVal) {
                // 如果使用obj1会导致循环递归的问题,因此使用另一个变量
                obj2.x = newVal
                render()
            },
            get() {
                return obj2.x
            }
        })
        obj1.x = 2
        console.log(obj1.x);
    </script>
</body>

</html>

acd5884e-83cb-40ec-a7e7-6038681601c5

通过 Object.defineProperty 监听拦截中存在一些问题

  • 属性新增属性
  • 数组方法:push、pop、shift、unshift、splice、sort、reverse
  • 数组新增值:[]
  • 数组 length 属性

以上的操作中并不会触发监听拦截

vue 对数组中的 pushpop 等方法进行重新包装,所以在 vue 中调用这些方法,可以对数组的修改进行监听拦截

https://cn.vuejs.org/v2/guide/list.html#%E5%8F%98%E5%BC%82%E6%96%B9%E6%B3%95-mutation-method

为了解决上述问题,vue2提供了set方法,其原理如下:

function set(key, value) {
    Object.defineProperty(obj1, key, {
        set(newVal) {
            value = newVal;
            render();
        },
        get() {
            return value;
        }
    })
}

此时通过调用set方法即可对新属性进行拦截。

2f273461-26c0-46a3-8093-27d9cd0733cc

在vue中有两种方式调用set方法:

Vue.set(app.user, 'age', 19)
// 或下面的方法(app为Vue的实例对象)
app.$set(app.user, 'age', 19)

e0bfbd08-c4de-4e91-a1d7-fa522f4b6cd7