Vue基础第二天之“异步与同步 、绑定class样式、条件渲染、key的工作原理、监测数据的原理、修改数组中的某个元素、什么是数据劫持、过滤器、内置指令、自定义指令、生命周期”

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script type="text/javascript" src="../js/vue.js"></script>
    <script type="text/javascript" src="../js/dayjs.min.js"></script>
</head>
<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>
<body>
    <!-- 
    // 一、监听和计算属性的对比
    computed和watch之间的区别:
	1.computed能完成的功能,watch都可以完成,都能实现的情况下,优先使用computed
	2.watch能完成的功能,computed不一定能完成,例如:watch可以进行异步操作,比如加个定时器,而且计算属性是不能的
    3.watch可以进行异步操作,computed不能进行异步任务操作
	两个重要的小原则:
	1.所被Vue管理的函数,最好写成普通函数,这样this的指向才是vm 或 组件实例对象。
	2.所有不被Vue所管理的函数(定时器的回调函数、ajax的回调函数等、Promise的回调函数),最好写成箭头函数,这样this的指向才是vm 或 组件实例对象。
    3.注意://这边定时器的回调是浏览器引擎帮你调的,所以必须要用箭头函数,不然this指向,会指向windes


    二、异步与同步的理解
    比如:你叫我去吃饭,我听到了就立刻和你去吃饭,如果我没有听到,你就会一直叫我,直到我听见和你一起去吃饭,这个过程叫同步;
    异步过程指你叫我去吃饭,然后你就去吃饭了,而不管我是否和你一起去吃饭。而我得到消息后可能立即就走,也可能过段时间再走。
    
    三、绑定class样式
    1.绑定class样式--字符串写法,适用于:样式的类名不确定,需要动态指定
    2.绑定class样式--数组写法,适用于:要绑定的样式个数不确定、名字也不确定
    3.绑定class样式--对象写法,适用于:要绑定的样式个数确定、名字也确定,但要动态决定用不用
    4.绑定style样式--对象写法 
    5.绑定style样式--数组写法

    四、条件渲染:
	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一定可以获取到(只是显示与隐藏)。
    注意:
    v-if与template的配合使用,不能跟v-show使用,template最大的好处是不会破坏html样式结构

    五、v-for遍历渲染数据
    v-for指令:
	1.用于展示列表数据
	2.语法:v-for="(item, index) in xxx" :key="yyy",in可以用of代替
	3.可遍历:数组、对象、字符串(用的很少)、指定次数(用的很少)
    注意:遍历数组的时候,index是数组的下标。但是对象的key是值属性名


    六、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是没有问题的。

    七、列表过滤和列表排序
    1.computed能完成的功能,watch都可以完成,都能实现的情况下,优先使用computed
    2.indexOf('')空字符串的时候,返回的是0,所以这就存在一个问题 

    八、更新时的一个问题
    1.生效
    // this.persons[0].name = '马老师' //奏效
	// this.persons[0].age = 50 //奏效
	// this.persons[0].sex = '男' //奏效

	2.无效// this.persons[0] = {id:'001',name:'马老师',age:50,sex:'男'} //不奏效
	解决:
    this.persons.splice(0,1,{id:'001',name:'马老师',age:50,sex:'男'})

    九、Vue监测数据的原理-对象
    1.通过get和set,进行监测数据的

    十、Vue.set的使用
    1.Vue.set(this.car,'youhao','1.7')//生效,存在get响应式
    2.this.car.youhao = 1.7//不会生效,因为没用get响应式
    注意:
    set的对象不能vue实例,或者Vue 实例的根数据对象(也就是_data)
    this.$set和Vue.set是同一个意思,this必须指向vue实例

    十一、Vue监测数据的原理-数组
    1.数组不是通过set和get去监视数据的,而是用包装去监听的
    2.通过7个常用的对数组操作的方法去监听的
        push在数组的最后一个位置新增元素
        pop删除一个元素
        shift删除第一个元素
        unshift在数组前面添加一个元素
        splice数组指定位置,删除,插入,替换元素
        sort数组排序
        reverse反转数组

    十二、总结vue监听数据, Vue监视数据的原理:
    0.this.$set和Vue.set是同一个意思
	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的根数据对象 添加属性!!!

    十三、什么是数据劫持
    1.如果有人修改了data中的数据,那马上就会被set劫持到了,劫持到了后干了2件事情,1.修改数据2.重新解析模板

    十四、收集表单数据:
    select option
	若:<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:输入首尾空格过滤

    十五、过滤器:
	定义:对要显示的数据进行特定格式化后再显示(适用于一些简单逻辑的处理)。
	语法:
	1.注册过滤器:全局Vue.filter(name,callback) 或 局部new Vue{filters:{}}
	2.使用过滤器:{{ xxx | 过滤器名}}  或  v-bind:属性 = "xxx | 过滤器名"
	备注:
	1.过滤器也可以接收额外参数、多个过滤器也可以串联
    2.并没有改变原本的数据, 是产生新的对应的数据

    十六、内置指令
    我们学过的指令:
	v-bind	: 单向绑定解析表达式, 可简写为 :xxx
	v-model	: 双向数据绑定
	v-for  	: 遍历数组/对象/字符串
	v-on   	: 绑定事件监听, 可简写为@
	v-if 	 	: 条件渲染(动态控制节点是否存存在)
	v-else 	: 条件渲染(动态控制节点是否存存在)
	v-show 	: 条件渲染 (动态控制节点是否展示)

    1.v-text_指令
    1-1.作用:向其所在的节点中渲染文本内容。
	1-2.与插值语法的区别:v-text会替换掉节点中的内容,{{xx}}则不会。

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

    3.v-cloak_指令
    3-1.本质是一个特殊属性,Vue实例创建完毕并接管容器后,会删掉v-cloak属性。
	3-2.使用css配合v-cloak可以解决网速慢时页面展示出{{xxx}}的问题。

    4.v-once_指令
    4-1.v-once所在节点在初次动态渲染后,就视为静态内容了。
	4-2.以后数据的改变不会引起v-once所在结构的更新,可以用于优化性能。

    5.v-pre_指令
    5-1.跳过其所在节点的编译过程。
	5-2.可利用它跳过:没有使用指令语法、没有使用插值语法的节点,会加快编译。


    十七、自定义指令
    需求1:定义一个v-big指令,和v-text功能类似,但会把绑定的数值放大10倍。
	需求2:定义一个v-fbind指令,和v-bind功能类似,但可以让其所绑定的input元素默认获取焦点。
	自定义指令总结:
	1、定义语法:
	(1).局部指令:
        new Vue({new Vue({
        directives:{指令名:配置对象} 或 directives{指令名:回调函数}
	}) 																		})
	(2).全局指令:
	Vue.directive(指令名,配置对象) 或   Vue.directive(指令名,回调函数)

	2、配置对象中常用的3个回调:
	(1).bind:指令与元素成功绑定时调用。
	(2).inserted:指令所在元素被插入页面时调用。
	(3).update:指令所在模板结构被重新解析时调用。

	3、备注:
	(1).指令定义时不加v-,但使用时要加v-;
	(2).指令名如果是多个单词,要使用kebab-case命名方式,不要用camelCase命名。
    (3).函数方式和对象方式的定义是有区别的需要注意



    十八、生命周期
	1.又名:生命周期回调函数、生命周期函数、生命周期钩子。
	2.是什么:Vue在关键时刻帮我们调用的一些特殊名称的函数。
	3.生命周期函数的名字不可更改,但函数的具体内容是程序员根据需求编写的。
	4.生命周期函数中的this指向是vm 或 组件实例对象。
    
    mounted
	//Vue完成模板的解析并把初始(第一次)的真实DOM元素放入页面后(挂载完毕)调用mounted

   -->

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

		<!-- 绑定class样式--字符串写法,适用于:样式的类名不确定,需要动态指定 -->
        <div class="basic" :class="styleall"  @click="changeMood">{{name}}</div>

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

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

        <!-- 绑定style样式--对象写法 -->
		<div class="basic" :style="styleObj">{{name}}</div> <br/><br/>

        <!-- 绑定style样式--数组写法 -->
		<div class="basic" :style="styleArr">{{name}}</div>
		<div class="basic" :style="[styleObj,styleObj2]">{{name}}</div>


        <!-- 使用v-show做条件渲染 -->
            <p>当前的num为{{num}}</p>
            <button @click="num++">点我+1</button>
			<h2 v-show="false">欢迎来到1{{name}}</h2>
			<h2 v-show="1 === 1">欢迎来到2{{name}}</h2>

            <!-- 使用v-if做条件渲染 -->
			<h2 v-if="false">欢迎来到1{{name}}</h2>
			<h2 v-if="1 === 1">欢迎来到2{{name}}</h2>

			<!-- v-else和v-else-if -->
			<div v-if="num === 1">Angular</div>
			<div v-else-if="num === 2">React</div>
			<div v-else-if="num === 3">Vue</div>
			<div v-else>哈哈</div>

            <!-- v-if与template的配合使用,不能跟v-show使用,template最大的好处是不会破坏html样式结构-->
			<template v-if="num === 1">
				<h2>你好</h2>
				<h2>尚硅谷</h2>
				<h2>北京</h2>
			</template>

            <!-- 遍历数组 -->
            <ul>
                <li v-for="item in persons" :key="item.id">
                    {{item.name}}-{{item.age}}
                </li>
            </ul>
            <!-- 遍历对象 -->
			<button @click="addFilPersone">新增</button>
			<button @click="addFilPersone2">新增2</button>
            <ul>
                <li v-for="(value,key) of car" :key="key">
                    {{value}}-{{key}}
                </li>
            </ul>
            <!-- 遍历字符串 -->
            <ul>
                <li v-for="(char,index) in str" :key="index">
                    {{char}}-{{index}}
                </li>
            </ul>
            <!-- 遍历指定次数 -->
            <ul>
                <li v-for="(number,index) in 5" :key="index">
                    {{number}}-{{index}}
                </li>
            </ul>

            <button @click.once="add">添加一个老刘</button>
            <ul>
				<li v-for="(p,index) of persons" :key="index">
					{{p.name}}-{{p.age}}
					<input type="text">
				</li>
			</ul>

            <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 perstwo" :key="index">
					{{p.name}}-{{p.age}}-{{p.sex}}
				</li> -->
                <li v-for="p of filPersone" :key="p.id">
					{{p.name}}-{{p.age}}-{{p.sex}}<input type="text"/>
				</li>
			</ul>

            <h3>现在是:{{fmtTime}}</h3>
            <h3>现在是:{{time | timeFormater}}</h3>
			<h3>现在是:{{time | timeFormater('YYYY_MM_DD') | mySlice}}</h3>

            <p v-big="numa"></p>
            <p v-big-number="numa"></p>
            
            <button @click="numa++">点击+1</button>
            <input type="text" v-fbind="numa">
            <p :style="{opacity}">生命周期函数</p>

    </div>
    <script type="text/javascript">
        Vue.config.productionTip = false//阻止 vue在启动时生成生产提示
        //全局过滤器
		Vue.filter('mySlice',function(value){
			return value.slice(0,4)
		})

        //定义全局指令
		/* Vue.directive('fbind',{
			//指令与元素成功绑定时(一上来)
			bind(element,binding){
				element.value = binding.value
			},
			//指令所在元素被插入页面时
			inserted(element,binding){
				element.focus()
			},
			//指令所在的模板被重新解析时
			update(element,binding){
				element.value = binding.value
			}
		}) */

        const vm = new Vue({
            el:'#root',
            data(){
                return{
                    num:0,
                    numa:0,
                    firstName:'张',
                    lastName:'三',
                    fullName:'张-三',
                    name:'尚硅谷',
                    styleall:'normal',
                    classArr:['atguigu1','atguigu2','atguigu3'],
                    classObj:{
                        atguigu1:true,
                        atguigu2:false,
			    	},
                    styleObj:{
                        fontSize: '40px',
				    	color:'red',
                    },
                    styleObj2:{
					    backgroundColor:'orange'
				    },
                    styleArr:[
					{
						fontSize: '40px',
						color:'blue',
					},
					{
						backgroundColor:'gray'
					}],
                    persons:[
						{id:'001',name:'张三',age:18},
						{id:'002',name:'李四',age:19},
						{id:'003',name:'王五',age:20}
					],
					car:{
						name:'奥迪A8',
						price:'70万',
						color:'黑色'
					},
					str:'hello',
                    persone:[
						{id:'001',name:'马冬梅',age:29,sex:'女'},
						{id:'002',name:'周冬雨',age:20,sex:'女'},
						{id:'003',name:'周杰伦',age:21,sex:'男'},
						{id:'004',name:'温兆伦',age:22,sex:'男'}
					],
                    keyWord:'',
                    perstwo:[],
                    sortType:0,//0原顺序 //1降序 //2是升序
                    time:1621561377603, //时间戳
                    opacity:1,
                    
                }
            },
            watch:{
                firstName(val){
                    setTimeout(()=>{//这边定时器的回调是浏览器引擎帮你调的,所以必须要用箭头函数,不然this指向,会指向windes
                     this.fullName = val + '-' + this.lastName
                    },1000)
                },
                lastName(val){
                     this.fullName = this.firstName+ '-'+val
                },
                // keyWord:{//监听实现
                //     immediate:true,
                //     handler(val){
                //         this.perstwo = this.persone.filter((p)=>{
                //         return p.name.indexOf(val) != -1
                //         })
                //     }
                // }
            },
            computed:{//计算属性
                quanming(){
                    return this.firstName + this.lastName
                },
                filPersone(){//计算属性实现
                    const arr = this.persone.filter((p)=>{
                         console.log(p.name)
                        return  p.name.indexOf(this.keyWord) != -1//indexOf('')空字符串的时候,返回的是0,所以这就存在一个问题 

                    })
                    if(this.sortType){
                        arr.sort((p1,p2)=>{
                        return  this.sortType === 1? p1.age-p2.age:p2.age-p1.age
                     })
                    }
                    console.log(arr)
                    return arr
                },
                fmtTime(){
					return dayjs(this.time).format('YYYY年MM月DD日 HH:mm:ss') 
                },
            },
            //局部过滤器
            filters:{
                timeFormater(value,str='YYYY年MM月DD日 HH:mm:ss'){
					// console.log('@',value)
					return dayjs(value).format(str)
				},
                
            },
            methods:{
                changeMood(){
                    this.styleall = 'happy'
                    let arr = ['happy','sad','normal'];
                    let index = Math.floor(Math.random()*3)
                    this.styleall = arr[index]
                    
                },
                add(){
                    let txt = {id:'000',name:'老王',age:12}
                    this.persons.unshift(txt);
                },
                addFilPersone(){
                    Vue.set(this.car,'youhao','1.7')//生效,存在get响应式
                    // this.car.youhao = 1.7//不会生效,因为没用get响应式
                },
                addFilPersone2(){
                    this.persons.unshift({id:'004',name:'老婆',age:20},)
                }
            },
            directives:{
                //big函数何时会被调用?1.指令与元素成功绑定时(一上来)。2.指令所在的模板被重新解析时。
                big(element,bingding){//函数式
                    // console.log('big',this) //注意此处的this是window
                    // console.log(element,bingding)//真实DOM,和绑定内容
                    element.innerText = bingding.value*10
                },
                // fbind(element,bingding){
                //     element.value = bingding.value*10
                //     element.focus()//失效
                
                // },
                'big-number'(element,binding){
					// console.log('big')
					element.innerText = binding.value * 10
				}, 
                fbind:{//对象式
                    //指令与元素成功绑定时(一上来)
                    bind(element,binding){
						element.value = binding.value*10
					},
					//指令所在元素被插入页面时
					inserted(element,binding){
						element.focus()
					},
					//指令所在的模板被重新解析时
					update(element,binding){
						element.value = binding.value*10
					}
                }
            },
			//mounted Vue完成模板的解析并把初始(第一次)的真实DOM元素放入页面后(挂载完毕)调用mounted
            mounted(){
				console.log('mounted',this)
				setInterval(() => {
					this.opacity -= 0.01
					if(this.opacity <= 0) this.opacity = 1
				},16)
			},
        })
    </script>
</body>
</html>

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值