初学Vue(2)

文章目录

监视属性 watch

  1. 当被监视的属性变化时,回调函数自动调用,进行相关操作
  2. 监视的属性必须存在,才能进行监视
  3. 监视的两种写法:
    a. new Vue时传入watch配置
    b. 通过vm.$watch监视
html 复制代码
<body>
  <div id="root">
    <h2>今天天气很{{info}}</h2>
    <button @click="changeWeather">切换天气</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: {
      changeWeather() {
        this.isHot = !this.isHot
      }
    },

    // 方法一:
    watch:{
      // 正常写法
      isHot: {
        immediate: true,  // 初始化时让handler调用一下
        // handler什么时候调用?当isHot发生改变时、
        handler(newValue, oldValue){
          console.log('newValue:', newValue);
          console.log('oldValue:', oldValue);
        },
      }

      // 简写
      isHot(newValue,oldValue){
        console.log('isHot被修改了')
      }
    }
  })

  // 方法二:
  // 正常写法
  vm.$watch('isHot',{
    immediate: true,  // 初始化时让handler调用一下
    // handler什么时候调用?当isHot发生改变时、
    handler(newValue, oldValue){
      console.log('newValue:', newValue);
      console.log('oldValue:', oldValue);
    },
  })

  // 简写
  vm.$watch('isHot',(newValue,oldValue){
    console.log('isHot被修改了',newValue)
  })
</script>

深度监视

  1. Vue中的Watch默认不监测对象内部值的改变(一层)
  2. 配置deep:true可以监测对象内部值改变(多层)
  3. 备注:
    a. Vue自身可以监测对象内部值的改变,但Vue提供的watch默认不可以
    b. 使用watch时数据的具体结构,决定是否采用深度监视
html 复制代码
<body>
    <div id="root">
        <h2>今天天气很{{info}}</h2>
        <button @click="changeWeather">切换天气</button>
        <hr>
        <h3>a的值是:{{numbers.a}}</h3>
        <button @click="numbers.a++">点我让a+1</button>
        <br>
        <h3>b的值是:{{numbers.b}}</h3>
        <button @click="numbers.b++">点我让b+1</button>
    </div>
</body>
<script type="text/javascript">
    Vue.config.productionTip = false;

    const vm = new Vue({
        el: '#root',
        data: {
            isHot: true,
            numbers:{
                a: 1,
                b: 1
            }
        },
        computed: {
            info() {
                return this.isHot ? '炎热' : '凉爽'
            }
        },
        methods: {
            changeWeather() {
                this.isHot = !this.isHot
            }
        },
        watch:{
            isHot: {
                // immediate: true,  // 初始化时让handler调用一下
                // handler什么时候调用?当isHot发生改变时、
                handler(newValue, oldValue){
                    console.log('newValue:', newValue);
                    console.log('oldValue:', oldValue);
                },
            },
            // 监视多级结构中某个属性的变化
            'numbers.a':{
                // deep: true,
                handler(){
                    console.log('a被改变了');
                },
            },

            // 监视多级结构中所有属性的变化
            numbers: {
                deep: true,
                handler() {
                    console.log('a被改变了');
                },
            }

          // 简写
          vm.$watch('isHot',{
            
          })
        }
    })
</script>

computed 和 watch 之间的区别

  1. computed能完成的功能,watch都可以完成
  2. watch能完成的功能,computed不一定能完成,例如:watch可以进行异步操作
    两个重要的小原则:
  3. 所被Vue管理的函数,最好写成普通函数,这样this的指向才是vm 或 组件实例对象
  4. 所有不被Vue所管理的函数(定时器的回调函数、ajax的回调函数等),最好写成箭头函数,这样this的指向才是vm 或 组件实例对象

绑定样式(class style)

  1. class样式
    写法:class="xxx" xxx可以是字符串、对象、数组
    字符串写法适用于:类名不确定,要动态获取
    对象写法适用于:要绑定多个样式,个数不确定,名字也不确定
    数组写法适用于:要绑定多个样式,个数确定,名字也确定,但不确定用不用
  2. style样式
    :style="{fontSize:xxx}" 其中xxx是动态值
    :style="[a,b]" 其中a、b是样式对象
html 复制代码
<div id="root">
  <!-- 绑定class样式--字符串写法,适用于:样式的类名不确定,需要动态绑定 -->
  <div class="basic" :class="mood" @click="changeMood">{{name}}</div><br><br>
  <!-- 绑定class样式--数组写法,适用于:样式个数不确定、类名也不确定 -->
  <div class="basic" :class="arr" @click="changeMood">{{name}}</div> <br><br>
  <!-- 绑定class样式--对象写法,适用于:要绑定的样式确定,类名也确定,但要动态决定用不用 -->
  <div class="basic" :class="arr" @click="changeMood">{{name}}</div><br><br>
  <!-- 绑定style样式,对象写法 -->
  <div class="basic" :style="styleObj">{{name}}</div><br><br>
  <!-- 绑定style样式,数组写法 -->
  <div class="basic" :style="styleArr">{{name}}</div>
</div>

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

  new Vue({
    el: '#root',
    data: {
      name: '檀健次',
      mood: 'normal',
      arr: ['attjc1', 'attjc2', 'attjc3'],
      classObj: {
        attjc1: false,
        attjc2: true,
        attjc3: true
      },
      styleObj: {
        color: 'white',
        backgroundColor: 'orange'
      },
      styleArr: [
        {
          fontSize: '30px'
        }
      ]
    },
    methods: {
      changeMood() {
        // this.mood = 'happy'
        const arr = ['happy', 'sad', 'normal']
        this.mood = arr[Math.floor(Math.random() * arr.length)]
      }
    }
  })
</script>

条件渲染

  1. v-if
    写法:
    (1) v-if="表达式"
    (2) v-else-if="表达式"
    (3) v-else="表达式"
    适用于:切换频率较低的场景
    特点:不展示的DOM元素直接被移除
    注意:v-if可以和:v-else-is、v-else一起使用,但要求结构不能被打断
  2. v-show
    写法:v-show="表达式"
    适用于:切换频率较高的场景
    特点:不展示的DOM元素未被移除,仅仅是使用样式隐藏掉
  3. 备注:使用v-if的时候,元素可能无法获取到,而使用v-show一定可以获取到
html 复制代码
<div id="root">
  <h2>当前值是:{{n}}</h2>
  <button @click="n++">点我n+1</button>

  <!-- 使用v-show做条件渲染 -->
  <!-- <h2 v-show="true">要见{{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-if 和 v-else -->
  <div v-if="n === 1">tjc</div>
  <div v-else-if="n === 2">txd</div>
  <div v-else-if="n === 3">tlq</div>
  <div v-else>哈哈</div>
</div>

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

  new Vue({
    el: '#root',
    data: {
      name: '檀健次',
      n: 1
    }
  })
</script>

列表渲染

基本列表

v-for指令

  1. 用于展示列表数据
  2. 语法:v-for="(item,index) in xxx" :key="yyy"
  3. 可遍历:数组、对象、字符串(用的很少)、指定次数(用的很少)
html 复制代码
<div id="root">
  <!-- 遍历数组 -->
  <h2>人员列表(遍历数组)</h2>
  <ul>
    <li v-for="(p,index) in persons" :key="index">
      {{p.name}}--{{p.age}}
    </li>
  </ul>
  <!-- 遍历对象 -->
  <h2>汽车信息</h2>
  <ul>
    <li v-for="(value,k) of car" :key="k">
      {{value}}--{{k}}
    </li>
  </ul>
  <!-- 遍历指定次数 -->
  <h2>循环指定次数</h2>
  <ul>
    <li v-for="n in 5" :key="n">
      {{n}}
    </li>
  </ul>
</div>

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

  new Vue({
    el: '#root',
    data: {
      persons:[
        {id: '001',name: '张三',age: 18}
        ,{id: '002',name: '李四',age: 19}
        ,{id: '003',name: '王五',age: 20}
      ],
      car:{
        name: '奔驰',
        price: '100万',
        color: '黑色'
      }
    }
  })
</script>

key的原理

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

列表过滤

html 复制代码
<div id="root">
  <!-- 遍历数组 -->
  <h2>人员列表</h2>
  <input type="text" placeholder="请输入名字" name="" id="" v-model="keyWord">
  <ul>
    <li v-for="(p,index) in filPersons" :key="index">
      {{p.name}}--{{p.age}}
    </li>
  </ul>
</div>

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

  // 用watch实现
  new Vue({
    el: '#root',
    data: {
      keyWord: '',
      persons: [
        { id: '001', name: '檀健次', age: 18 }
        , { id: '002', name: '赵丽颖', age: 19 }
        , { id: '003', name: '成毅', age: 20 }
      ],
      filPersons: []
    },
    watch: {
      keyWord: {
        immediate: true,
        handler(val) {
          this.filPersons = this.persons.filter((p) => {
            return p.name.indexOf(val) !== -1
          })
        }
      }
    }
  })

  // 用computed实现
  new Vue({
    el: '#root',
    data: {
      keyWord: '',
      persons: [
        { id: '001', name: '檀健次', age: 18 }
        , { id: '002', name: '赵丽颖', age: 19 }
        , { id: '003', name: '成毅', age: 20 }
      ]
    },
    computed:{
      filPersons(){
        return this.persons.filter((p) => {
          return p.name.indexOf(this.keyWord) !== -1
        })
      }
    }
  })
</script>

列表排序

html 复制代码
<div id="root">
  <!-- 遍历数组 -->
  <h2>人员列表</h2>
  <input type="text" placeholder="请输入名字" name="" id="" v-model="keyWord">
  <button @click="sortType = 2">年龄升序</button>
  <button @click="sortType = 1">年龄降序</button>
  <button @click="sortType = 0">原顺序</button>
  <ul>
    <li v-for="(p,index) in filPersons" :key="index">
      {{p.name}}--{{p.age}}
    </li>
  </ul>
</div>

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

  new Vue({
    el: '#root',
    data: {
      keyWord: '',
      sortType: 0,  // 0 原顺序 1 降序 2 升序
      persons: [
        { id: '001', name: '檀健次', age: 18 }
        , { id: '002', name: '檀小呆', age: 2 }
        , { id: '003', name: '赵丽颖', age: 19 }
        , { id: '004', name: '成毅', age: 20 }
        , { id: '005', name: '虞书欣', age: 20 }
      ]
    },
    computed: {
      filPersons() {
        const arr = this.persons.filter((p) => {
          return p.name.indexOf(this.keyWord) !== -1
        })
        if (this.sortType) {
          arr.sort((a, b) => {
            return this.sortType === 1 ? b.age - a.age : a.age - b.age
          })
        }
        return arr
      }
    }
  })
</script>
  1. 如何监测数组中的数据
    数组更新检测
    通过包裹数组更新元素的方法实现,本质就是做了两件事:
    a. 调用原生对应的方法对数组进行更新
    b. 重新解析模板,进而更新页面
    没有get、set方法,不能直接操作数组,通过索引值等修改,Vue不起效
    可通过七个方法修改:
    1). push 向数组的末尾添加一个或多个元素,并返回新的长度
    2). pop 向数组的末尾添加一个或多个元素,并返回新的长度
    3). shift 用于把数组的第一个元素从其中删除,并返回第一个元素的值。改变数组的长度
    4). unshift 向数组的开头添加一个或更多元素,并返回新的长度。该方法将改变数组的数目
    5). splice 用于添加或删除数组中的元素
    6). sort 用于对数组的元素进行排序。排序顺序可以是字母或数字,并按升序或降序。默认排序顺序为按字母升序
    注意 使用数字排序,你必须通过一个函数作为参数来调用。函数指定数字是按照升序还是降序排列。
    7). reverse 颠倒数组中元素的顺序
    原理:上述七个方法和原来数组的七个方法有所不同,是Vue继承后重新包装数组中长用的方法

    如果不是用上述方法,也可以用Vue.set()和vm.$set()
  2. Vue.set()
    返回值:设置的值
    用法:
    像响应式对象中添加一个property并确保这个新property同样是响应式的,且触发视图更新。它必须用于响应式对象上添加新property,因为Vue无法探测普通的新增property(比如 this.myObject.newProperty = 'hi)
    注意:对象不能是 Vue 实例,或者 Vue 实例的根数据对象。
html 复制代码
<div id="root">
  <h1>学校信息</h1>
  <h2>学校名称:{{name}}</h2>
  <h2>学校地址:{{address}}</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>

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

  new Vue({
    el: '#root',
    data: {
      name: '河南科技学院',
      address: '新乡',
      student: {
        name: '张三',
        // sex: '男',
        age: {
          rAge: 18,
          sAge: 19
        },
        friends: [
          { name: '李四', age: 20 },
          { name: '王五', age: 21 },
          { name: '赵六', age: 22 }
        ]
      }
    },
    methods: {
      addSex(){
        Vue.set(this.student, 'sex','女' )
      }
    }
  })
</script>
  1. 数据劫持
    指的是在访问或者修改对象的某个属性时,通过一段代码拦截这个行为,进行额外的操作或者修改返回结果。
    比较典型的是Object.defineProperty()和 ES2016 中新增的Proxy对象。数据劫持最著名的应用当属双向绑定,这也是一个已经被讨论烂了的面试必考题。例如 Vue 2.x 使用的是Object.defineProperty()(Vue 在 3.x 版本之后改用 Proxy 进行实现)。
  2. 大合集
html 复制代码
<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="updateFriendName">修改第一个朋友的名字为:张三</button><br>
  <button @click="updateHobby">修改第一个爱好为:开车</button><br>


  <h2>学校名称:{{name}}</h2>
  <h2>学校地址:{{address}}</h2>
  <hr>
  <h1>学生信息</h1>
  <h2>姓名:{{student.name}}</h2>
  <h2>年龄:{{student.age}}</h2>
  <h2 v-if="student.sex">性别:{{student.sex}}</h2>
  <ul>
    <li v-for="item in student.hobby" :key="item">
      {{item}}
    </li>
  </ul>
  <h2>朋友</h2>
  <ul>
    <li v-for="(f,index) in student.friends" :key="index">
      {{f.name}}--{{f.age}}
    </li>
  </ul>
</div>

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

  const vm = new Vue({
    el: '#root',
    data: {
      name: '河南科技学院',
      address: '新乡',
      student: {
        name: '张三',
        // sex: '男',
        age: 18,
        hobby: ['吃饭', '睡觉', '打游戏'],
        friends: [
          { name: '李四', age: 20 },
          { name: '王五', age: 21 },
          { name: '赵六', age: 22 }
        ]
      }
    },
    methods: {
      addSex(){
        Vue.set(this.student, 'sex','女' )
      },
      addFriend(){
        this.student.friends.unshift({name:'张三',age:18})
      },
      updateFriendName(){
        this.student.friends[0].name = '张三'  //  this.student.friends[0].name是对象
      },
      updateHobby(){
        this.student.hobby.splice(0,1,'开车')
        // Vue.set(this.student.hobby,0,'开车')
      }
    }
  })
</script>

收集表单中的数据 v-model

  1. ,则v-model收集的是value值,用户输入的就是value值
  2. ,则v-model收集的是value值,且要给标签配置value值

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

b. 配置input的value属性:

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

ⅱ. v-model的初始值是数组,那么收集的就是value组成的数组

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

lazy:失去焦点再收集数据

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

trim:输入首尾空格过滤

html 复制代码
<body>
  <div id="root">
    <form>
      账号:<input type="text" v-model.trim="username"><br></br>
      密码:<input type="password" v-model="password"><br></br>
      年龄:<input type="number" v-model.number="age"><br><br>
      性别:
      <input type="radio" name="sex" v-model="sex" value="男">男
      <input type="radio" name="sex" v-model="sex" value="女">女
      <br><br>
      爱好:
      <input type="checkbox" v-model="hobby" value="吃饭">吃饭
      <input type="checkbox" v-model="hobby" value="睡觉">睡觉
      <input type="checkbox" v-model="hobby" value="打游戏">打游戏
      <br><br>
      所属校区:
      <select name="" id="">
        <option value="">请选择校区</option>
        <!-- <option v-for="(city,index) in citys" :key="index" :value="city">{{city}}</option> -->
        <option value="beijing">北京</option>
        <option value="shanghai">上海</option>
        <option value="guangzhou">广州</option>
        <option value="shenzhen">深圳</option>
      </select><br><br>
      <button @click.prevent="submit">提交</button>
    </form>
  </div>
</body>

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

  const vm = new Vue({
    el: '#root',
    data: {
      username: '',
      password: '',
      age: '',
      sex: '',
      hobby: [],
      citys: 'beijing'
    },
    methods: {
      submit() {
        console.log(this.username, this.password, this.sex, this.hobby);
      }
    }
  })
</script>

过滤器(Vue3已移除)

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

  1. 注册过滤器:Vue.filter(name,callback) 或 new Vue { filters:{} }
  2. 使用过滤器:{{xxx | 过滤器名}} 或 v-bind:属性 = "xxx | 过滤器名"
    备注:
  3. 过滤器也可以接收额外参数、多个过滤器也可以串联
  4. 并没有改变原本的数据,是产生新的对应的数据
相关推荐
桂月二二4 小时前
探索前端开发中的 Web Vitals —— 提升用户体验的关键技术
前端·ux
CodeClimb5 小时前
【华为OD-E卷 - 第k个排列 100分(python、java、c++、js、c)】
java·javascript·c++·python·华为od
沈梦研5 小时前
【Vscode】Vscode不能执行vue脚本的原因及解决方法
ide·vue.js·vscode
hunter2062065 小时前
ubuntu向一个pc主机通过web发送数据,pc端通过工具直接查看收到的数据
linux·前端·ubuntu
qzhqbb5 小时前
web服务器 网站部署的架构
服务器·前端·架构
刻刻帝的海角5 小时前
CSS 颜色
前端·css
轻口味6 小时前
Vue.js 组件之间的通信模式
vue.js
浪浪山小白兔6 小时前
HTML5 新表单属性详解
前端·html·html5
lee5767 小时前
npm run dev 时直接打开Chrome浏览器
前端·chrome·npm
2401_897579657 小时前
AI赋能Flutter开发:ScriptEcho助你高效构建跨端应用
前端·人工智能·flutter