Vue笔记2.1

心情:上次发表了vue的笔记,感觉还是有很多东西不懂,所以这次又把vue2过了一遍,巩固一下基础

1.初始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(){}
  // 创建Vue实例   配置对象axios({}  )
        Vue({
            el: "#root", // el用于指定当前Vue实例为哪个容器服务,值通常为css选择器字符串
            data: {// data中用于存储数据,数据工供el所指定的容器去使用,值我们暂时先写成一个对象。
                name: "atguigu",
                address:"上海"
            }
        })

2.Vue模板语法

  Vue模板语法有2大类:
        1、插值语法:
            功能:用于解析标签体内容。
            写法:{{xxx}},xxx是js表达式,且可以直接读取到data中的所有属性
        2、指令语法:
            功能:用于解析标签(包括:标签属性、标签体内容、绑定事件)
            举例:v-bind:href="xxx" 或 :href="xxx" xxx同样是写js表达式,
                  且可以直接读取到data中的所有属性
            备注:Vue中有很多指令,且形式都是:v-???,此处我们只是拿v-bind举个例子

3.数据绑定

Vue中有2中数据绑定的格式:

  1. 单向绑定(v-bind):数据只能从data流向页面
  2. 双向绑定(v-model):数据不仅能从data流向页面,还可以从页面流向data。
  3. 备注:
    1. 双向绑定一般都应用在表单类元素上(如:input、select等)
    2. v-model:value 可以简写为v-model,因为v-model默认收集的就是value值。

4.el与dat的两种写法

data与el的2种写法

  1、el有2种写法
      (1).new Vue时候配置el属性
      (2).先创建Vue实例,随后再通过vm.$mount('#root')指定el的值。
  2、data有2中写法
      (1).对象式
      (2).函数式
      如何选择:目前哪种写法都可以,以后学习到组件时,data必须使用函数式,否则会报错。
  3、一个重要的原则:
      有Vue管理的函数,一定不要写箭头函数,一旦写了箭头函数,this就不在是Vue实例了。

5.MVVM模型

 MVVM模型:
            1.M:模型(Model):data中的数据
            2.V:视图(View):模板代码
            3.VM:视图模型(ViewModel):Vue实例
 观察发现:
            1.data中所有的属性,最后都出现在了vm身上
            2.vm身上所有的属性,及Vue原型上所有属性,在Vue模板中都可以直接使用。

6.数据代理

  1. Object.definProperty方法

     Vue.config.productionTip = false
            let number = 18
            let person = {
                name: '张三',
                sex: "男",
                // age: 18
            }
            console.log(person);
            // 不可枚举(遍历)
            // 不可修改
            // // 不可删除
            Object.defineProperty(person, 'age', {
                // value: 18,
                // enumerable: true,//控制属性是否可以没,默认值是false
                // writable: true,//控制属性是否可以被修改,默认值是false
                // configurable: true//控制属性是否可以被删除,默认值是false
                
                // 当有人读取person的age属性是,get函数(getter)救护被调用,且返回值就是age的值
                get() {
                    console.log('有人读取age属性!');
                    return number
                },
    
                // 当有人修改person的age属性,set函数(setter)就会被调用,且会受到修改的具体值
                set(value) {
                    console.log('有人修改了age属性,且值是:', value);
                    number = value;
                }
            })
            // console.log(Object.·keys(person));
            // for (let key in person) {
            //     console.log('@', person[key]);
            // }
    
  2. 数据代理的概念:通过一个对象代理另一个对象中属性的操作 (读/写)

  3. Vue中的数据代理:

    1. Vue中的数据代理:
    	  通过vm对象来代理data对象属性中的操作(读/写)
    2、Vue中数据代理的好处:
            更加方便的操作data中的数据
    3、基本原理:
            通过Object.defineProperty()把data对象中所有属性添加到vm上
            为每一个添加到vm上的属性,都制定一个getters/setter。
            在getter/setter内部去操作(读/写)data中所对应的属性
    

7.事件处理

  1. 事件的基本使用:
    1. 使用v-on:xxx 或 @xxx 绑定事件,其中xxx是事件名
    2. 事件的回调需要配置在methods对象中,最终会在vm上
    3. methods中配置的函数,不要用箭头函数!否则this就不是vm了;
    4. methods中配置的函数,都是被Vue所管理的函数,this的指向是vm 或 组件实例对象
    5. @click=“demo” 和 @click=“demo($event)” 效果一直,但是后者可以传参
  2. Vue中的事件修饰符:
    1. prevent: 阻止默认事件(常用);
    2. stop:阻止事件冒泡(常用);
    3. once:事件只触发一次(常用);
    4. capture:使用事件的捕获模式
    5. self:只有event.target是当前操作的元素才触发事件
    6. passive:事件的默认行为立即执行,无需等待事件回调执行完毕。

8.计算属性

计算属性

  1. 定义:要用的属性不存在,要通过已有的属性计算的来
  2. 原理:底层借助了Object.defineproperty方法提供的getters和setter。
  3. get函数什么时候执行?
    1. 除去读取时会执行一次。
    2. 当依赖的数据发生改变时会被再次调用
  4. 优势、与methods实现相比,内部有缓存机制(复用),效率更高,调试方便
  5. 备注:
    1. 计算属性最终会相互出现在vm上,直接读取使用即可。

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

       computed: {
                      // 完整写法
                      // fullName: {
                      //     get() {
                      //         console.log('get方法被调用了');
                      //         // console.log(this); //此处的this是vm
                      //         return this.firstName + '-' + this.lastName
                      //     },
                      //     set(value) {
                      //         console.log('set', value);
                      //         const arr = value.split('-');
                      //         this.firstName = arr[0];
                      //         this.lastName = arr[1];
                      //     }
                      // }
                      // 简写
                      fullName() {
                          setTimeout(function () {
                              return this.firstName + '-' + this.lastName;
                          }, 1000)
      
                      }
                  }
      

9.监视属性

监视属性watch:

  1. 当被监视的属性变化时,回调函数自动调用,进行相关操作

  2. 监视的属性必须存在,才能进行监视!

  3. 监视的两种写法:

      (1).new Vue()时传入watch配置
      (2).通过vm.$watch监视
    
      (1).new Vue()时传入watch配置
       watch: {
             info: {
                  immediate: true, //初始化是让handler调用一下
                // handler什么时候调用?当isHost发生改变时。
                  handler(newVal, oldVal) {
                     console.log('isHost被修改了', newVal, oldVal);
                 }
              }
          }
      (2).通过vm.$watch监视
           vm.$watch('abc',{
                immediate:true,
                handler(newVal,oldVal){
                    console.log('info被修改了',newVal,oldVal);
                }
            })
    
  4. 深度监视:
    (1). Vue中的watch默认不监测对象内部值的改变(一层)
    (2). 配置deep:true可以监测对象内部值改变(多层)

    备注:
    (1).Vue自身可以监测对象内部值的改变,但Vue提供的watch默认不可以
    (2).使用watch时根据数据的具体结构,决定是否采用深度监视

         watch: {
                    info: {
                        immediate: true, //初始化是让handler调用一下
                        // handler什么时候调用?当isHost发生改变时。
                        handler(newVal, oldVal) {
                            console.log('isHost被修改了', newVal, oldVal);
                        }
                    },
                    // 监视多级结构中某个属性的变化
                    // "numbers.a": {
                    //     handler() {
                    //         console.log('a被改变了');
                    //     }
                    // }
                    // 监视多级结构中所有属性的变化
                    numbers: {
                        deep: true,
                        handler() {
                            console.log('numbers被监视了');
                        }
                    }
                }
    
  5. 监视属性简写:

           watch: {
                     // 完整写法
                   // isHost: {
                        // immediate: true, //初始化是让handler调用一下
                       // deep: true,// 监视多级结构中所有属性的变化
                     //  handler(newVal, oldVal) {
                    		//  console.log('isHost被修改了', newVal, oldVal);
                     //  }
                    // },
    
                     // 简写
                     isHost(newVal, oldVal) {
                        console.log('isHost被修改了', newVal, oldVal);
                  }
              }
                
         vm.$watch('isHost', function (newVal, oldVal) {
               console.log('isHost被修改了', newVal, oldVal);
           })
    
    
  6. 深度监视:
    computed和watch之间的区别:

    1. computed能完成的功能,watch都可以完成。
    2. watch能完成的功能呢,cmputed不一定能完成,例如:watch进行异步操作。

    两个重要的原则:

    1. 所有被Vue管理的函数,最好写成普通函数,这样this的指向才是vm或组件实例对象。
    2. 所有不被Vue所管理的函数(定时器的的回调函数、ajax的回调函数等、Promise的回答函数), 最好写成回调函数,这样this的指向才是vm或组件实例对象。

10.绑定样式

绑定样式:

  1. class样式

    写法:class=“xxx”,xxx可以是字符串、对象、数组
    字符串写法适用于:类名不确定的个,要动态获取
    对象写法适用于:哟啊坝顶多个样式,个数不确定,名字也不确定
    数组写法适用于:要绑定多个样式,个数确定,名字确定,但不确定用不用

  2. style样式

    :style="{fontSize:xxx}“其中xxx是动态值
    :style=”[a,b]"其中a、b是样式对象

 <!-- 准备好一个容器 -->
    <div id='root'>
        <!-- 绑定class样式 -字符串写法,适用于:样式的类名不确定,需要动态指定 -->
        <div class="basic normal" :class="mood" @click="changeMod">{{name}}</div><br><br>

        <!-- 绑定class样式 -数组写法,适用于:要绑定样式的个数不确定、名字不确定 -->
        <div class="basic normal" :class="classArr">{{name}}</div><br><br>

        <!-- 绑定class样式 -对象写法,适用于:要绑定样式的个数确定、名字确定 但要动态决定用不用 -->
        <div class="basic normal" :class="classObj">{{name}}</div><br><br>

        <div class="basic normal" :style="styleObj1">{{name}}</div><br><br>

        <div class="basic normal" :style="styleArr">{{name}}</div><br><br>
    </div>
    <script>
        Vue.config.productionTip = false //阻止vue在启动时生产生产提示
	var vm = new Vue({
            el: '#root',
            data: {
                name: "尚硅谷",
                mood: 'normal',
                classArr: ['atguigu1', 'atguigu2', 'atguigu3'],
                classObj: {
                    atguigu1: false,
                    atguigu2: true
                },

                styleObj1: {
                    backgroundColor: 'orange!important'
                },
                styleObj2: {
                    color: 'red',
                    fontSize: '40px'
                },
                styleArr: [
                    {
                        color: 'red',
                        fontSize: '40px'
                    },
                    {
                        backgroundColor: 'orange'
                    }
                ]
            },
            methods: {
                changeMod() {
                    const arr = ['happy', 'sad', 'normal']
                    let index = Math.floor(Math.random() * 3)
                    this.mood = arr[index]
                    // document.getElementById('demo').className = 'basic happy'
                }
            }
        });
  </script>

11.条件渲染

条件渲染

  1. v-if

    写法:
         (1).v-if="表达式"
         (2).v-esle-if="表达式"
         (3).v-else="表达式"
         适用于: 切换频率较低的场景
         特点:不展示的DOM元素直接被移除
         注意:v-if可以和:v-else-if、v-else一起使用,但要求结构不能别打断
    
  2. v-show

    	 写法:v-show="表达式"
         适用于:切换频率较高的场景
         特点:不展示的DOM元素未被移除,仅仅是使用样式隐藏掉
    
  3. 备注:使用v-if的时,元素可能无法获取到,而是使用v-show一定可以获取到

12.列表渲染

  1. 基本列表:

    v-for指令:
          1、用于展示列表数据
          2、语法:v-for="(item,index) in xxx" :key="xxx"
          3、可遍历:数组、对象、字符串(用得很少)、指定次数(用的很少)
      
       <!-- 遍历数组 -->
        <h2>人员列表(遍历数组)</h2>
        <ul>
            <li v-for="(p,index) in persons" :key="p.id">
                {{p.name}}---{{p.age}}---{{index}}
            </li>
        </ul>
    
    	 <!-- 遍历对象 -->
        <h2>汽车信息(遍历对象)</h2>
        <ul>
            <li v-for="(value,key) in car" :key="key">
                {{key}}---{{value}}
            </li>
        </ul>
     	<!-- 遍历字符串 -->
        <h2>测试遍历字符串(用得少)</h2>
        <ul>
            <li v-for="(char,index) in str" :key="index">
                {{char}}---{{index}}
            </li>
        </ul>
    	<!-- 遍历指定次数 -->
        <h2>测试遍历指定次数(用的少)</h2>
        <ul>
            <li v-for="(number,index) in 6" :key="index">
                {{index}}---{{number}}
            </li>
        </ul>
    
  2. key的原理:
    面试题:react 、vue中的可以有什么作用?(key的内部原理)

    1、虚拟DOM中可以的作用:
          key是虚拟DOM对象的标识,当状态中的数据发生变化时,Vue会根据【新数据】生成【新的虚拟DoM】
          随后Vue进行【新虚拟DOM】与【就虚拟DOM】的差异比较,比较规则如下:
                
     2、对比规则:
          (1).就虚拟DOM中找到与新虚拟DOM相同的key:
                  - 若虚拟DOM中内容没变,直接使用之前的真实的DOM
                  - 若虚拟DOM中内容变了,则生成的真实DOM,随后替换掉页面中之前的真实DOM
         (2). 就虚拟DOM中未找到与新虚拟DOM相同的key:
                  - 创建新的真实DOM,随后渲染到页面
                    
     3.用index作为可以可能引发的问题:
         1.若对数据机型:逆序添加、逆序删除等破坏顺序操作:
              会产生没有必要的真实DOM更新 ==> 界面效果没问题,但效率低
         
         2.如果结构中还包含输入类的DOM会产生错误DOM更新 => 界面有问题
                    
     4、开发中如何选择key?:
         1.最好使用每条数据的唯一标识作为key,比如id、身份证号、手机号、学号等唯一值。
         2.如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示。
          使用index作为key是没有问题的。
    
  3. 列表过滤

     <div id='root'>
            <input type="text" placeholder="请输入姓名" v-model="keyword">
            <ul>
                <li v-for="(p,index) in filtPersons" :key="p.id">
                    {{p.name}}-{{p.age}}-{{p.sex}}
                </li>
            </ul>
    
        </div>
        
    <script>
    Vue.config.productionTip = false //阻止vue在启动时生产生产提示    
    new Vue({
                el: "#root",
                data: {
                    keyword: '',	
                    persons: [
                        {
                            id: "001", name: "马冬梅", age: 19, sex: '女'
                        },
                        {
                            id: "002", name: "周冬雨", age: 20, sex: '女'
                        },
                        {
                            id: "003", name: "周杰伦", age: 21, sex: '男'
                        },
                        {
                            id: "004", name: "温兆伦", age: 22, sex: '男'
                        },
                    ],
                },
                computed: {
                    filtPersons() {
                        return this.persons.filter((p) => {
                            return p.name.indexOf(this.keyword) !== -1
                        })
                    }
                }
            })
        </script>
    
  4. 列表排序

    <!-- 准备好一个容器 -->
        <div id='root'>
            <input type="text" placeholder="请输入姓名" v-model="keyword">
            <button @click="sortType = 2">年龄升序</button>
            <button @click="sortType = 1">年龄降序</button>
            <button @click="sortType = 0">原顺序</button>
            <ul>
                <li v-for="(p,index) in filtPersons" :key="p.id">
                    {{p.name}}-{{p.age}}-{{p.sex}}
                </li>
            </ul>
    
        </div>
        <script>
            Vue.config.productionTip = false //阻止vue在启动时生产生产提示
    
            new Vue({
                el: "#root",
                data: {
                    keyword: '',
                    sortType: 0, //0 代表原顺序,1代表降序,2代表升序
                    persons: [
                        {
                            id: "001", name: "马冬梅", age: 30, sex: '女'
                        },
                        {
                            id: "002", name: "周冬雨", age: 31, sex: '女'
                        },
                        {
                            id: "003", name: "周杰伦", age: 18, sex: '男'
                        },
                        {
                            id: "004", name: "温兆伦", age: 19, sex: '男'
                        },
                    ],
                },
                computed: {
                    filtPersons() {
                        const arr = this.persons.filter((p) => {
                            return p.name.indexOf(this.keyword) !== -1
                        })
    
                        if (this.sortType) {
                            arr.sort((p1, p2) => {
                                return this.sortType === 1 ? p2.age - p1.age : p1.age - p2.age;
                            })
                        }
                        console.log(arr);
                        return arr;
                    }
                }
            })
    
        </script>
    
  5. 更新时的一个问题

    <!-- 准备好一个容器 -->
        <div id='root'>
            <button @click="upateMei">点击时更新马冬梅的个人信息</button>
            <ul>
                <li v-for="(p,index) in persons" :key="p.id">
                    {{p.name}}-{{p.age}}-{{p.sex}}
                </li>
            </ul>
    
        </div>
        <script>
            Vue.config.productionTip = false //阻止vue在启动时生产生产提示
    
            new Vue({
                el: "#root",
                data: {
                    persons: [
                        {
                            id: "001", name: "马冬梅", age: 19, sex: '女'
                        },
                        {
                            id: "002", name: "周冬雨", age: 20, sex: '女'
                        },
                        {
                            id: "003", name: "周杰伦", age: 21, sex: '男'
                        },
                        {
                            id: "004", name: "温兆伦", age: 22, sex: '男'
                        },
                    ],
                },
                methods: {
                    upateMei() {
    
                        // 可以更新
                        // this.persons[0].name = "马老师"
                        // this.persons[0].age = 50
                        // this.persons[0].sex = "男"
    
                        // 先点按钮在点击vue的调试工具,vue数据更新,页面数据不更新
                        // 先点vue调试工具再点击按钮,vue数据不更新,页面数据不更新
                        this.persons[0] = { id: "001", name: "马老师", age: 50, sex: '男' }   // 不奏效
                        this.persons.splice(0, 1, { id: "001", name: "马老师", age: 50, sex: '男' })
                    }
                }
            })
    
    
        </script>
    
  6. Vue检测数据改变的原理_对象

      <!-- 准备好一个容器 -->
    <div id='root'>
        <h2>学校名称:{{name}}</h2>
        <h2>学校地址:{{address}}</h2>
    </div>
    <script>
    
        // 1、加工data(所谓的加工就是把data中的每一组的key:value 都形成了get和set写法) ,加工就能变成响应式了数据变页面也跟着变
        //     一整套流程:
        //     name一改变了,set就调用,set已调用就重新解析模板,
        //     模板一重新解析,生成新的虚拟DOM,然后新旧DOM对比,然后更新页面
        // 2、vm._data = data
        Vue.config.productionTip = false //阻止vue在启动时生产生产提示
    
        // vm.name vm.addres 这叫啥?  数据的data
        var vm = new Vue({
            el: '#root',
            data: {
                name: "尚硅谷",
                address: "北京",
                student: {
                    name: 'tom',
                    age: {
                        rAge: 40,
                        sAge: 29
                    }
                }
            }
        });
    </script>
    
  7. 模拟一个数据监测

      <script>
        let data = {
            name: '尚硅谷',
            address: "北京",
            a: {
                b: 1
            }
        }
    	 // let tmp = '尚硅谷'
    
        // setInterval(() => {
        //     if (data.name !== tmp) {
        //         tmp = data.name
        //         console.log('name被改变了~~~');
        //     }
        // },100)
        // Object.defineProperty(data, 'name', {
        //     get() {
        //         return data.name
        //     },
        //     set(val) {
        //         data.name = val
        //     }
        // })
    
     const obs = new Observer(data);
        // 这个是data对象,然后交给Observer,然后data身上有什么
        // 意味着obs这个实例对象身上也有相同的属性
        console.log(obs);
    
        // 准备一个vm实例对象
        let vm = {}
    
        vm._data = data = obs;
    
        function Observer(obj) {
            // 汇总对象中所有的属性形成一个数组
            const keys = Object.keys(obj);
            // 遍历
            console.log(keys);
            // 这个this是Observer的实例对象
    
            console.log('this', this);
            keys.forEach((k) => {
                // console.log(k);
                // Object.defineProperty 
                Object.defineProperty(this, k, {
                    get() {
                        return obj[k]
                    },
                    set(val) {
                        console.log(`${k}被改了1111,我要去解析模板,生成虚拟DOM,我要开始忙了`);
                        obj[k] = val;
                    }
                })
            })
        }
    </script>
    
  8. Vue.set的使用

    <div id='root'>
        <h1>学校信息</h1>
        <h2>学校名称:{{name}}</h2>
        <h2>学校地址:{{address}}</h2>
        <h2>校长是:{{school.leader}}</h2>
        <hr>
    
        <h1>学生信息</h1>
        <button @click="addSex">添加一个性别属性,默认值是男</button>
        <h2>姓名: {{student.name}}</h2>
        <h2 v-if="student.sex">性别: {{student.sex}}</h2>
        <h2>年龄: 真实{{student.age.rAge}}、对外{{student.age.sAge}}</h2>
        <h2>朋友们</h2>
        <ul>
            <li v-for="f in student.friends" :key="index">
                {{f.name}} -- {{f.age}}
    
            </li>
        </ul>
    </div>
    
    <script>
        Vue.config.productionTip = false //阻止vue在启动时生产生产提示
    
        var vm = new Vue({
            el: '#root',
            data: {
                name: "尚硅谷",
                address: "北京",
                school: {},
                student: {
                    name: 'tom',
                    // sex: "男",
                    age: {
                        rAge: 40,
                        sAge: 29
                    },
                    firends: [
                        { name: "jerry", age: 35 },
                        { name: "tony", age: 36 },
                    ]
                }
            },
            methods: {
                addSex() {
                    // Vue.set(this.student, 'sex', '男')
                    this.$set(this.student, 'sex', '男')
                }
            }
        })
    </script>
    
  9. Vue检测数据改变的原理_数组

    <div id='root'>
        <h2>学校名称:{{ school.name}}</h2>
        <h2>学校地址:{{ school.address}}</h2>
        <h2>校长是:{{ school.leader}}</h2>
        <hr>
        <h1>学生信息</h1>
        <button @click="addStu">添加一个性别属性,默认值是男</button>
        <ul>
            <li>姓名:{{student.name}}</li>
            <li>年龄:真实{{student.age.rage}},对外{{student.age.sAge}}</li>
        </ul>
        <h2>爱好</h2>
        <ul>
            <li v-for="item in student.hobby">{{item}}</li>
        </ul>
        <h2>爱好</h2>
        <ul>
            <li v-for="f in student.friends">{{f.name}}--{{f.age}}</li>
        </ul>
    </div>
    <script>
       Vue.config.productionTip = false //阻止vue在启动时生产生产提示
        var vm = new Vue({
            el: '#root',
            data: {
                school: {
                    name: "尚硅谷",
                    address: "北京",
                },
                student: {
                    name: 'tom',
                    name: 'tom',
                    hobby: [
                        '抽烟',
                        '喝酒',
                        '烫头',
                    ],
                    age: {
                        rAge: 40,
                        sAge: 29
                    },
                    friends: [
                        { name: 'jerry', age: 35 },
                        { name: 'tony', age: 36 }
                    ]
                }
            },
            methods: {
                addStu() {
    
          // vm._data.student.hobby.push === Array.prototype.push
        //   vm._data.student.hobby.push  vue写的一个push
        //   你先找到的是vue给你写的push
        //   vue写的push做了两件事
        //   1、正常的一件事,正常的调用了正常数组上(Array.prototype)的push方法   
        //   2、重新解析模块,生成虚拟DOM    
                    this.student.hobby[0] = '学习';
           		 }
            }
        });
    
    </script>
    
  10. 总结Vue数据检测

    数据劫持:把vue实例中的data修改成_data,这种行为(把所有的数据都变成getset形式),这种变化,这种行为,就叫做劫持
    Vue监视数据的原理:
            1.vue中监视data中所有层次的数据
    
            2.如何监测对象中的数据?
                通过setter实现监视,且要在new Vue()时就传入要检测的数据。
                (1).对象中后追加的属性.Vue默认不做响应式处理
                (2).如需给后添加的属性做响应式,请使用如下API:
                     Vue.set(target,propertyeName/index,value) 或
                     vm. $set(target,propertyeName/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的根数据对象 添加属性!!!
    
    
    

13.收集表单数据

	收集表单数据:
        若:<input type="text">. 则v-model收集的是value值,用户输入的就是value值
        若:<input type="radio">. 则v-model收集的是value值,且要给标签配置value值
        若:<input type="checkbox">. 
            1.没有配置input的value属性,name收集的就是checked(勾选 or 未勾选,是布尔值)
            2.配置input的value属性:
                (1)v-model的初始值是非数组,name收集的就是checked(勾选 or 未勾选,是布尔值)
                (1)v-model的初始值是数组,name收集的就是value组成的数据
        
        备注:v-model的三个修饰符
                lazy:失去焦点在收集数据
                number:输入字符串转为有效的数字
                trim:输入首位空格过滤

14.过滤器:

  定义:对要显示的数据进行特定格式化后在显示(适用于一些简单逻辑的处理)。
  语法:
    1、注册过滤器:Vue.filter(name,callback)  或  new Vue({filters:{}})
    2、使用过滤器:{{xxx | 过滤器名 }} 或  v-bind:属性="xxx | 过滤器名称"

备注:
    1.过滤器也可以接收额外参数,多个过滤器也可以串联
    2.并没有该笔那原本的数据,是产生新的对应的数据
<!-- 准备好一个容器 -->
    <div id='root'>
        <h2>显示格式化后的时间</h2>
        <h4>现在是:{{time}}</h4>

        <!-- 计算属性实现 -->
        <h4>现在是:{{fmtTime}}</h4>
        <!-- methods实现 -->
        <h3>现在是:{{getFmtTIme()}}</h3>

        <!-- 过滤器的实现 -->
        <h3>现在是:{{time | timeFormater}}</h3>
        <h3>现在是:{{time | timeFormater('YYYY_MM_DD') | mySlice}}</h3>

        <h3 :x="msg | mySlice">尚硅谷</h3>

        <!-- <input type="text" v-model="ms | mySlice"> -->

    </div>

    <div id="root2">
        <h2> {{msg | mySlice}}</h2>
    </div>

    <script>
        Vue.config.productionTip = false //阻止vue在启动时生产生产提示
        Vue.filter('mySlice', function (value) {
            return value.slice(0, 4)
        })
        var vm = new Vue({
            el: '#root',
            data: {
                time: 1634129928126,
                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('YYYY年MM月DD日 HH:mm:ss')
                    return dayjs(value).format(str)

                },
                mySlice(value) {
                    // console.log('@', value);
                    // return dayjs(value).format('YYYY年MM月DD日 HH:mm:ss')
                    return value.slice(0, 4)

                },
            }
        });

        new Vue({
            el: "#root2",
            data: {
                msg: "hello!!!尚硅谷"
            }
        })
    </script>

15.内置指令

  1. v-text内置_指令

    我们学过的指令:
        v-bind  : 单向绑定解析表达式,可简写为 :xxx
        v-model : 双向数据绑定
        v-for   : 遍历数组/对象/字符串
        v-on    : 绑定事件加监听,可简写为@
        v-if    : 条件渲染(动态控制节点是否存在)
        v-else  : 条件渲染(动态控制节点是否存在)
        v-show  : 条件渲染(动态控制节点是否展示)
    
    v-text指令:
        1.作用:向其所在节点中渲染文本内容
        2.与插值语法的区别:v-text会替换掉节点中的内容,{{xxx}}则不会 `在
    
  2. v-html_指令

    v-html指令:
                1.作用:向指定节点中渲染包含HTML结构的内容
                2.与插值语法的区别:
                    (1).v-html会替换节点中所有的内容,{{xx}}则不会。
                    (2).v-html可以识别HTML结构
                3.严重注意:v-html有安全性问题!!!
                    (1).在网站上动态渲染HTML是非常危险的,容易导致xss攻击
                    (2).一定要在可信的内容上使用v-html,永不要用在用户提交的内容上!
    
  3. v-clock_指令

     v-cloak指令(没有值)1.本质是一个特殊属性,Vue实例创建完成并接管容器后,会删掉v-cloak属性
            2.使用css配合v-cloak可以解决网速慢时页面展示出{{xxx}}的问题
    	
     <style>
        [v-cloak] {
            display: none;
        }
    </style>
    <div id='root'>
        <h2 v-cloak>{{name}}</h2>
    </div>
    <script>
        Vue.config.productionTip = false //阻止vue在启动时生产生产提示
        setTimeout(function () {
            var vm = new Vue({
                el: '#root',
                data: {
                    name: '尚硅谷'
                }
            });
        }, 5000)
    </script>
    
  4. v-once_指令

      v-once指令:
            1.v-once所在节点在初次动态渲染后,被视为静态内容了。
            2.以后数据的改变不会引起v-once所在结构的更新,可以优化性能。
            
      <div id='root'>
        <h2 v-once>初始化的n值是:{{n}}</h2>
        <h2>当前的n值是:{{n}}</h2>
        <button @click="n++">点我n+1</button>
    </div>
    <script>
        Vue.config.productionTip = false //阻止vue在启动时生产生产提示
        var vm = new Vue({
            el: '#root',
            data: {
                n: 1
            }
        });
      </script>
    
  5. v-pre_指令

     <div id='root'>
        <h2 v-pre>Vue其实很简单</h2>
        <h2 v-pre>当前的n值是:{{n}}</h2>
        <button @click="n++">点我n+1</button>
    </div>
    <script>
        Vue.config.productionTip = false //阻止vue在启动时生产生产提示
        var vm = new Vue({
            el: '#root',
            data: {
                n: 1
            }
        });
    </script>
    

16.自定义指令

  1. 自定义指令

     需求1:定义一个v-big指令,和v-text功能类似,但会把绑定的数值放大10倍
     需求2:定义一个v-fbind指令,和v-bind功能类似,但可以让其所绑定改的input元素默认获取焦点
            
            自定义指令总结:
                一、定义语法:
                    (1).局部指令:
                            new Vue({                                                              new Vue({ 
                                directives:{指令名:配置对象}                 或                         directives:{指令名:配置对象}     
                            })                                                                     })
                    (2).全局指令:
                            Vue.directive(指令名,配置对象)                  或                     Vue.directive(指令名,   回调函数)
                二、配置对象中常用的3个回调:
                    (1).bind:指令与元素成功绑定时调用
                    (2).inserted: 指令所在元素被插入页面时调用
                    (3).update: 指令所在模板结构被重新解析时调用
                   
                三、备注
                    1.指令定义时不加v-,但使用时加v-;
                    2.指令如果是多个单词,要使用kebab-case命名方式,不要使用camelCase命名。
    
    <div id='root'>
            <h2>当前的n值是 <span v-text="n"></span></h2>
            <h2>放大10被后的n值是: <span v-big-number="n+1+2"></span></h2>
            <button @click="n++">点我n+1</button><br><br>
            <input type="text" v-fbind:value="n">
        </div>
    
        <div id="root2">
            <input type="text" v-fbind:value="x">
        </div>
     	
     	<script>
            // 定义全局指令
             Vue.directive('fbind', {
                 bind(element, binding) {
                     element.value = binding.value
                },
                 inserted(element, binding) {
                     element.focus();
                 },
                 update(element, binding) {
                     element.value = binding.value
                 },
             })
    
            // Vue.directive('big-number', function (element, binding) {
            //     element.innerText = binding.value * 10
    
            // })
    
    
            Vue.config.productionTip = false //阻止vue在启动时生产生产提示
            var vm = new Vue({
                el: '#root',
                data: {
                    n: 1
                },
                directives: {
                    // big函数合适会被调用?1、指令与元素成功绑定时(一上来)2、指令所在的模板被重新解封时。
                    // 'big-number'(element, binding) {
                    //     // console.log(a);
                    //     // console.dir(a);
                    //     // console.dir(a instanceof HTMLElement);
                    //     // console.log(binding);
                    //     // console.log(binding.value);
                    //     element.innerText = binding.value * 10
                    // },
                    // fbind: {
                    //     // 1、指令与元素成功绑定时(一上来)
                    //     bind(element, binding) {
                    //         element.value = binding.value;
                    //     },
                    //     // 2、指令所在元素被插入页面时
                    //     inserted(element, binding) {
                    //         element.focus();
                    //     },
                    //     // 3、指令所在的模板被重新解封时。
                    //     update(element, binding) {
                    //         element.value = binding.value
                    //     },
                    // }
                }
            });
            new Vue({
                el: "#root2",
                data: {
                    x: 1
                }
            })
        </script>
    	
    
  2. 回顾一个DOM操作

    <style>
         .demo {
             background-color: orange;
         }
    </style
    <button>点击按钮添加一个输入框</button>
    <script>
        var btn = document.getElementsByTagName('button')[0]
        btn.onclick = function () {
            var input = document.createElement('input');
            input.className = "demo"
            input.vlaue = "99"
            // input.parentElement.style.backgroundColor = 'skyblue'
            console.log(input.parentElement);
            input.onclick = () => { alert(1) }
    
    
            document.body.appendChild(input);
            input.focus();
            console.log(input.parentElement);
        }
    </script>
    
    

17.生命周期

  1. 引出生命周期
     生命周期:
            1.又名:生命周期回调函数、声明周期函数、生命周期钩子
            2.是什么:Vue在关键时刻帮我们调用的一些特殊名称的函数。
            3.生命周期的名字不可更改,但函数的具体内容是更许愿根据需求编写的。
            4.生命周期函数的this指向时vm或组件实例对象
    
    	 <div id='root'>
        <h2></h2>
        <h2 v-if="a">欢迎学习Vue</h2> 
        <h2 :style="{opacity}">欢迎学习Vue</h2>
        <!-- {{change()}} -->
    </div>
    <script>
        Vue.config.productionTip = false //阻止vue在启动时生产生产提示
        const vm = new Vue({
            el: '#root',
            data: {
                a: false,
                opacity: 1
            },
            methods: {},
            // Vue完成模板的解析并把初始的真实DOM放入页面后(挂载完毕)调用mounted
            mounted() {
                console.log('mounted', this);
                setInterval(() => {
                    this.opacity -= 0.01
                    if (this.opacity <= 0) this.opacity = 1
                }, 16)
            }
        });
    
    </script>
    
  2. 分析生命周期
      <!-- 准备好一个容器 -->
    <div id='root' :x="n">
        <h2>当前的n值是:{{n}}</h2>
        <button @click='add'>点我n+1</button>
        <button @click='bye'>点我销毁</button>
    </div>
    <script>
        Vue.config.productionTip = false //阻止vue在启动时生产生产提示
        const vm = new Vue({
            el: '#root',
            // template: `
            //     <div>
            //         <template v-if="false">
            //             <h2>当前的n值是:{{n}}</h2>
            //             <h2>当前的n值是:{{n}}</h2>
            //             <h2>当前的n值是:{{n}}</h2>
            //         </template>
            //         <h2>当前的n值是:{{n}}</h2>
            //         <button @click='add'>点我n+1</button>    
            //     </div>
            // `,
            data: {
                n: 1
            },
            watch:{
                n(){
                    console.log('n变了~~~');
                }
            },
            methods: {
                add() {
                    console.log('add');
                    this.n++
                },
                bye() {
                    console.log('bye');
                    this.$destroy();
                }
            },
            beforeCreate() {
                console.log('beforeCreate');
                // console.log(this);
                // debugger;
            },
            created() {
                console.log('created');
                // console.log(this);
                // debugger;
            },
            beforeMount() {
                console.log('beforeMount');
                // console.log(this);
                // debugger;
                // debugger;
            },
            mounted() {
                console.log('mounted');
                // console.log(this);
                // document.querySelector('h2').innerText = 123
                // debugger;
                // console.log('mounted', this.$el instanceof HTMLElement);
            },
            beforeUpdate() {
                console.log('beforeUpdate');
                // console.log(this.n);
                // debugger;
            },
            updated() {
    
                console.log('updated');
                // console.log(this.n);
                // debugger;
                // this.n = 99;
            },
            beforeDestroy() {
                console.log('beforeDestroy');
                // console.log(this.n);
                // this.add();
                this.n = 999;
            },
            destroyed() {
                console.log('destroyed');
            }
        });
    </script>
    
    
  3. 总结生命周期
     常用的生命周期钩子:
            1.mounted:发送ajax请求、启动定时器、绑定自定义事件、订阅消息等【初始化操作】
            2.beforeDestroy:清除定时器、解绑自定义事件、取消订阅消息等【收尾工作】
    
        关于销毁Vue实例
            1.销毁后借助Vue开发者工具看不到任何信息。
            2.销毁后自定义事件失效,但原生DOM事件依然有效。
            3.一般不会在beforeDestroy操作数据,因为几遍操作数据,也不会在触发更新流程了。
    
    	<div id='root'>
        <h2></h2>
        <h2 :style="{opacity}">欢迎学习Vue</h2>
        <button @click="opacity = 1">透明度设置为1</button>
        <button @click="stop">点我停止变化</button>
    </div>
    <script>
        
        Vue.config.productionTip = false //阻止vue在启动时生产生产提示
        const vm = new Vue({
            el: '#root',
            data: {
                opacity: 1,
    
            },
            methods: {
                stop() {
                    this.$destroy();
                }
            },
            // Vue完成模板的解析并把初始的真实DOM放入页面后(挂载完毕)调用mounted
            mounted() {
                this.timer = setInterval(() => {
                    this.opacity -= 0.01
                    console.log('setInterval');
                    if (this.opacity <= 0) this.opacity = 1
                }, 16)
            },
            bforeDestroy() {
                console.log('vm即将驾鹤西游了');
                clearInterval(this.timer)
            }
        });
    
    
    
    </script>
    

18.非单文件组件

  1. 基本使用
     	传统方式编写应用
                存在的问题:
                    1.依赖关系混乱,不好维护
                    2.代码复用率不高
    
            组件的定义:实现应用中局部功能代码(css,html,js)的和资源的集合。
        
            非单文件组件:
                    一个文件中包含n个组件。
    
            单文件组件:    
                    一个文件中只包含1个组件。
    
    
    
            重点:
                Vue中使用组件的三大步骤:
                    一、定义组件(创建组件)
                    二、注册组件
                    三、使用组件(写组件标签)
                
                一、如何定义一个组件?
                    使用VUe.extend(options)创建,其中options和new Vue(options)传入的options几乎一样,但也有点区别。
                    区别如下:
                        1.el不要写,为什么? ———— 最终所有的组件都要经过一个vm的管理,由vm中的el决定服务那个容器。
                        1.data必须写成函数,为什么?————— 避免组件被复用时,数据存在引用关系。
                    
                二、如何注册组件?
                        1.局部注册:靠new Vue的时候传入components选项
                        2.全局注册:靠VUe.component('组件名',组件)
                
                三、编写组件标签:
                    <school></school>
    
    <!-- 准备好一个容器 -->
    <div id='root'>
        <hello></hello>
        <hr>
        <h1>{{msg}}</h1>
        <hr>
        <!-- 第三部:编写组件标签 -->
        <school></school>
    
        <hr>
        <!-- 第三部:编写组件标签 -->
        <student></student>
    </div>
    
    <div id="root2">
        12121
        <hello></hello>
    </div>
    <script>
        Vue.config.productionTip = false //阻止vue在启动时生产生产提示
    
    
    
        // 创建school组件
        const school = Vue.extend({
            // el:"#root", // 一定不要写el配置项,一定不要写el配置型,因为最终所有的组件都要被一个vm管理,有vm决定该服务于那个容器
            template: `
            <div>
                <h2>学校名称:{{schoolName}}</h2>
                <h2>学校地址:{{address}}</h2>
                <button @click="clickHanrdel">点我提示学校名称</button>
            </div>
            `,
            data() {
                return {
                    schoolName: '尚硅谷',
                    address: " 北京昌平",
                }
            },
            methods: {
                clickHanrdel() {
                    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: "<h1>{{msg}}</h1>",
            data() {
                return {
                    msg: "你好啊!Tom"
                }
            }
        })
    
        // 全局注册组件
        Vue.component('hello', hello)
    
    
        // 创建vm
        var vm = new Vue({
            el: '#root',
            data: {
                msg: '你好啊!!'
            },
            // 第二步:注册组件(局部注册)
            components: {
                school,
                student
            }
        });
    
        const vm2 = new Vue({
            el: "#root2",
            data: {
    
            },
            // components: {
            //     hello
            // }
        })
    
    
        // let data = {
        //     a: 1,
        //     b: 2
        // }
    
        // function data() {
        //     return {
        //         a: 1,
        //         b: 2
        //     }
        // }
    
        // const x1 = data();
        // const x2 = data();
    </script>
    
  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;
    	
    	<div id='root'>
        <h1>{{msg}}</h1>
        <school></school>
    </div>
    <script>
        Vue.config.productionTip = false //阻止vue在启动时生产生产提示
    
        // const s = Vue.extend({
        //     name: "atguigu",
        //     template: `
        //         <div>
        //             <h2>学校名称:{{name}}</h2>    
        //             <h2>学校地址:{{address}}</h2>    
        //         </div>
        //     `,
        //     data() {
        //         return {
        //             name: '尚硅谷',
        //             address: '北京'
        //         }
        //     }
        // })
    
        const s = {
            name: "atguigu",
            template: `
                <div>
                    <h2>学校名称:{{name}}</h2>    
                    <h2>学校地址:{{address}}</h2>    
                </div>
            `,
            data() {
                return {
                    name: '尚硅谷',
                    address: '北京'
                }
            }
        }
    
        var vm = new Vue({
            el: '#root',
            data: {
                msg: '欢迎学习Vue!'
            },
            components: {
                school: s
            }
        });
    </script>
    	
    
  3. 组件的嵌套
      <div id='root'>
        <!-- <app></app> -->
    </div>
    <script>
        Vue.config.productionTip = false //阻止vue在启动时生产生产提示
    
        // 定义student组件
        const student = Vue.extend({
            template: `
                <div>
                    <h2>学生姓名:{{name}}</h2>    
                    <h2>学生年龄:{{age}}</h2>    
                </div>
            `,
            data() {
                return {
                    name: '尚硅谷',
                    age: 18
                }
            }
        })
    
        // 定义school组件
        const school = Vue.extend({
            template: `
                <div>
                    <h2>学校名称:{{name}}</h2>    
                    <h2>学校地址:{{address}}</h2>   
                    <student></student> 
                </div>
            `,
            data() {
                return {
                    name: "尚硅谷",
                    address: "北京"
                }
            },
            components: {
                student
            }
        })
    
        // 定义hello组件
        const hello = Vue.extend({
            template: `
                <div>
                    <h2>{{msg}}</h2>    
                </div>
            `,
            data() {
                return {
                    msg: "欢迎来到尚硅谷学习",
                }
            },
            components: {
                student
            }
        })
    
    
        // 定义一个app组件
        const app = Vue.extend({
            template: `
                <div>
                    <hello></hello>
                    <school></school>
                </div>
            `,
            data() {
                return {
                }
            },
            components: {
                school,
                hello,
            }
        })
    
        var vm = new Vue({
            el: '#root',
            template: "<app></app>",
            data: {
            },
            // 注册组件(局部)
            components: {
                app
            }
        });
    </script>
    
  4. VueComponent
      关于VueComponent:
            1.school组件本质是一个名为VueComponent的构造函数,且不是程序员定义的,是Vue.extend生成的
    
            2.我们值需要写<school></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
    
    
    <div id='root'>
        <school></school>
        <hello></hello>
    </div>
    <script>
        /*
            Vue.extend = function (extendOptions) {
                    ......
    
                var Sub = function VueComponent (options) {l 
                // console.log('VueComponent调用了');
                this._init(options);
                };
                  ......
                return Sub
            };
        */
        Vue.config.productionTip = false //阻止vue在启动时生产生产提示
        // 定义school组件
        const school = Vue.extend({
            template: `
                <div>
                    <h2>学校名称:{{name}}</h2>    
                    <h2>学校地址:{{address}}</h2> 
                    <button @click="showName">点我提示学校名称</button>    
                </div>
            `,
            data() {
                return {
                    name: "尚硅谷",
                    address: "北京"
                }
            },
            methods: {
                showName() {
                    alert(this.name)
                    // 这个this就是Vuecomponent实例对象
                    console.log(this)
                }
            }
        })
    
        // 定义hello组件
        const test = Vue.extend({
            template:`<span>atguigu</span>`
        })
    
        // 定义hello组件
        const hello = Vue.extend({
            template: `
                <div>
                    <h2>{{msg}}</h2>    
                    <test></test>
                </div>
            `,
            data() {
                return {
                    msg: "你好啊",
                }
            },
            components:{
                test
            }
        })
        school.a = 99
        // console.log('@', school.a);
        // console.log('#', hello.a);
    
        var vm = new Vue({
            el: '#root',
            data: {
            },
            components: {
                school,
                hello
            }
        });
    
        console.log(vm);
    </script>
    
    
  5. 一个重要的内置关系
       1.一个重要的内置关系:VueCOmponent.prototype.__proto__ === Vue.prototype
       2.为什么要有这个关系:让组件实例对象(vc)可以访问到Vue原型上的属性、方法
        <!-- 准备好一个容器 -->
    <div id='root'>
        <school></school>
        <!-- 使用school模板,就new VueComponent() -->
    </div>
    <script>
        Vue.config.productionTip = false //阻止vue在启动时生产生产提示
        Vue.prototype.x = 99;
        // 定义school组件
    
        // school是VueComponent 构造函数
        const school = Vue.extend({
            template: `
                <div>
                    <h2>学校名称:{{name}}</h2>    
                    <h2>学校地址:{{address}}</h2> 
                    <button @click="showX">点我输出x</button>
                </div>
            `,
            data() {
                return {
                    name: "尚硅谷",
                    address: "北京"
                }
            },
            methods: {
                showX() {
                    console.log(this.x);
                }
            }
        })
    
        var vm = new Vue({
            el: '#root',
            data: {
            },
            components: {
                school
            }
        });
    
        // console.log(school.prototype.__proto__ === Vue.prototype);
    
        //  定义一个构造函数
        // function Demo() {
        //     this.a = 1;
        //     this.b = 2;
        // }
        // 创建一个Demo的实例对象
        // const d = new Demo();
    
        // console.log(Demo.prototype); //显示原型
        // console.log(d.__proto__);//隐式原型
    
        // console.log(Demo.prototype == d.__proto__);
            // 实例的隐式原型属性,永远指向自己缔造者的原型对象
    
        // // 程序员通过显示原型属性操作原型对象,追加一个x属性,值为99
        // Demo.prototype.x = 99;
    
        // // console.log('@', d.__proto__.x);
        // console.log('@', d);
    
        // function Person() {
    
        // }
        // function Dog() {
    
        // }
        // const p = new Person();
        // const d2 = new Dog();
        // console.log(p);
        // console.log(d2);
    </script>
        
    

19.单文件组件

// 1.创建School组件
<template>
  <div class="demo">
    <h2>学校名称:{{ name }}</h2>
    <h2>学校地址:{{ address }}</h2>
  </div>
</template>

<script>
export default {
  name: "School",
  data() {
    return {
      name: "尚硅谷",
      address: "北京.昌平",
    };
  },
};
</script>

<style>
.demo {
  background-color: gray;
}
</style>
// 2.App.vue文件引入了School组件中
<template>
  <div>
    <h1 v-text="msg" ref="title"></h1>
    <button ref="btn" @click="showDom">点我输出上方的DOM元素</button>
    <School id="sch" />
  </div>
</template>

<script>
// 引入组件
import School from "./components/School.vue";
export default {
  name: "App",
  data() {
    return {
      msg: "欢迎学习Vue!",
    };
  },
  methods: {
    showDom() {
      console.log("@@", this.$refs.title);//真实DOM元素
      console.log("@@", this.$refs.btn);// 真实DOM元素
      console.log("@@", this.$refs.sch);//School组件的实例对象(vc)
    },
  },
  components: {
    School,
  },
};
</script>

<style>
</style>


// 3.在main.js中引入App.vue文件
 import App from './App.vue'
 new Vue({
    el: "#root",
    template: `<App></App>`,
    components: { App }
 })
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值