Vue3 学习笔记(八)——Vue语法

一、Vue数据类型

1、基础类型

  Number(数字)、String(字符串)、Boolean(布尔)、Date(日期)、Array(数组)、Object(基础对象)。

2、其他类型

  Function(方法)、Symbol(属性)

3、自定义类型

class Person {
  constructor(firstName, lastName) {
    this.firstName = firstName
    this.lastName = lastName
  }
}

二、控件数据绑定

1、文本赋值(文本插值)

  1)对象赋值为“js变量”,解析为文本

  最基本的数据绑定形式是文本插值,它使用的是“Mustache”语法 (即双大括号):

    <span>Message: {{ msg }}</span>  // 使用双括号把js中的变量括起来,msg会随js中的变量变化而变化
  2)对象赋值为“js变量”,解析为Html字符串
    <p>Using text interpolation: {{ rawHtml }}</p>  // 解析为文本;Using text interpolation: <span style="color: red">This should be red.</span>
    <p>Using v-html directive: <span v-html="rawHtml"></span></p>  // 解析为Html字符串;Using v-html directive: This should be red.

  注:v-html不能用来拼接组合模板(如拼接多个Vue组件)

2、Attribute 绑定(控件属性赋值)

  方式一

  使用 v-bind 指令;如果绑定的值是 null 或者 undefined,那么该 attribute 将会从渲染的元素上移除。

    <div v-bind:id="dynamicId"></div>

  方式二:简写

    <div :id="dynamicId"></div>

3、动态绑定多个值(控件绑定数据)

  通过不带参数的 v-bind进行绑定

    <div v-bind="objectOfAttrs"></div>
    
    ...
    data() {
      return {
        objectOfAttrs: {
          id: 'container',
          class: 'wrapper'
        }
      }
    }

4、使用JavaScript表达式

    {{ number + 1 }}
    
    {{ ok ? 'YES' : 'NO' }}
    
    {{ message.split('').reverse().join('') }}
    
    <div :id="`list-${id}`"></div>
    
    <!-- 这是一个语句,而非表达式 -->
    {{ var a = 1 }}
    
    <!-- 条件控制也不支持,请使用三元表达式 -->
    {{ if (ok) { return message } }}

5、调用函数

    <span :title="toTitleDate(date)">
      {{ formatDate(date) }}
    </span>

    <el-button type="primary" @click="onSubmit">Create</el-button>

  注:受限的全局访问:

    模板中的表达式将被沙盒化,仅能够访问到有限的全局对象列表。该列表中会暴露常用的内置全局对象,比如 Math 和 Date

    没有显式包含在列表中的全局对象将不能在模板内表达式中访问,例如用户附加在 window 上的属性。然而,你也可以自行在 app.config.globalProperties 上显式地添加它们,供所有的 Vue 表达式使用。

6、绑定响应式事件(计算属性;可以看作是一种特殊的方法)

  1)计算属性放在computed事件中,代替methods中的方法不可响应式更新到标签中。

<p>Has published books:</p>
<span>{{ publishedBooksMessage }}</span>

export default {
  data() {
    return {
      author: {
        name: 'John Doe',
        books: [
          'Vue 2 - Advanced Guide',
          'Vue 3 - Basic Guide',
          'Vue 4 - The Mystery'
        ]
      }
    }
  },
  computed: {
    // 一个计算属性的 getter
    publishedBooksMessage() {
      // `this` 指向当前组件实例
      return this.author.books.length > 0 ? 'Yes' : 'No'
    }
  }
}

  2)计算属性默认是只读的。当你尝试修改一个计算属性时,你会收到一个运行时警告。只在某些特殊场景中你可能才需要用到“可写”的属性,你可以通过同时提供 getter 和 setter 来创建“可写计算属性

export default {
  data() {
    return {
      firstName: 'John',
      lastName: 'Doe'
    }
  },
  computed: {
    fullName: {
      // getter
      get() {
        return this.firstName + ' ' + this.lastName
      },
      // setter
      set(newValue) {
        // 注意:我们这里使用的是解构赋值语法
        [this.firstName, this.lastName] = newValue.split(' ')
      }
    }
  }
}

  注:

    ① Getter 不应有副作用,如:在 getter 中做异步请求或者更改 DOM;getter 的职责应该仅为计算和返回该值。可通过监听器来扩展副作用。

    ② 避免直接修改计算属性值,计算属性的返回值应该被视为只读的,并且永远不应该被更改。应该更新它所依赖的源状态以触发新的计算。

三、指令 Directives

1、v-if与v-else-if、v-else条件渲染

<!-- v-if示例 -->
<p v-if="seen">Now you see me</p>

<!-- v-if、v-else-if、v-else示例 -->
<div v-if="Math.random() > 0.8">Now you see me</div>
<div v-else-if="Math.random() > 0.5">Now you see me</div>
<div v-else>Now you don't</div>

<!-- 切换不止一个元素进行“条件渲染”时的方案:使用<template>进行包裹;v-show 不支持在 <template> 元素上使用-->
<template v-if="ok">
  <h1>Title</h1>
  <p>Paragraph 1</p>
  <p>Paragraph 2</p>
</template>

2、v-show元素的可见性

    <h1 v-show="ok">Hello!</h1>

3、v-text更新元素的文本内容

    <!-- v-text 通过设置元素的 textContent 属性来工作,因此它将覆盖元素中所有现有的内容。 -->
    <span v-text="msg"></span>
    <!-- 等同于 -->
    <span>{{msg}}</span>

4、v-html更新元素的innerHTML

    <div v-html="html"></div>

5、v-pre跳过该元素及其子元素的编译(原分不动的输出内容)

  下面示例的“原始双大括号标签”及“内容”都将被保留。

    <span v-pre>{{ this will not be compiled }}</span>

6、v-bind数据绑定

    <a v-bind:href="url"> ... </a>

    <!-- 简写为: -->
    <a :href="url"> ... </a>

    <!--
    动态参数绑定
    举例:如果你的组件实例有一个数据属性 attributeName,其值为 "href",那么这个绑定就等价于 v-bind:href
    注意,参数表达式有一些约束,
    参见下面“动态参数值的限制”与“动态参数语法的限制”章节的解释
    -->
    <a v-bind:[attributeName]="url"> ... </a>
    <a :[attributeName]="url"> ... </a>

7、v-model数据双向绑定

  1)简单示例
    <!-- 示例一:页面元素或表单数据的绑定Start -->
    <!-- 不使用v-model时 -->
    <input
      :value="text"
      @input="event => text = event.target.value">
    <!-- 使用v-model时 -->
    <input v-model="text">
    <!-- 示例一:页面元素或表单数据的绑定End -->


    <!-- 示例二:组件使用v-model_Start -->
    <!--①将内部原生 <input> 元素的 value attribute 绑定到 modelValue prop
        ②当原生的 input 事件触发时,触发一个携带了新值的 update:modelValue 自定义事件 -->
    <!-- CustomInput.vue -->
	<script>
	export default {
	  props: ['modelValue'],
	  emits: ['update:modelValue']
	}
	</script>
	<template>
	  <input
	    :value="modelValue"
	    @input="$emit('update:modelValue', $event.target.value)"
	  />
	</template>
    <!-- 组件使用的地方 -->
    <CustomInput v-model="searchText" />
    <!-- 示例二:组件使用v-model_End -->
  2)多行文本使用v-model,需结合placeholder="add multiple lines"使用
<template>
  <span>Multiline message is:</span>
  <p style="white-space: pre-line;">{{ message }}</p>
  <textarea v-model="message" placeholder="add multiple lines"></textarea>
</template>

<script>
export default {
  data() {
    return {
      message: ''
    }
  }
}
</script>

    注:注意在 <textarea> 中是不支持插值表达式的,如:<textarea>{{ text }}</textarea>

  3)复选框使用v-model

    ① 在复选框中使用v-model一般赋值为布尔值;但是也可以赋值为数组,会把复选框勾选结果作为该数组的一个元素

    ② 复选框的值绑定使用true-valuefalse-valuetrue-valuefalse-value仅支持和v-model配套使用。

<template>
  <!-- 普通用法 v-model=布尔值 -->
  <input type="checkbox" id="checkbox" v-model="checked" />
  <label for="checkbox">{{ checked }}</label> 
    
  <!-- 值绑定用法1:true-value="yes"、false-value="no";这里 toggle 属性的值会在选中时被设为 'yes',取消选择时设为 'no' -->
  <input type="checkbox" v-model="toggle"
  true-value="yes" false-value="no" />

  <!-- 值绑定用法2:给true-value、false-value绑定js数据 -->
  <input type="checkbox" v-model="toggle"
  :true-value="dynamicTrueValue" :false-value="dynamicFalseValue" />

  <!-- 特殊用法 v-model=数组 -->
  <div>Checked names: {{ checkedNames }}</div>
  <input type="checkbox" id="jack" value="Jack" v-model="checkedNames" />
  <label for="jack">Jack</label>
  <input type="checkbox" id="john" value="John" v-model="checkedNames" />
  <label for="john">John</label>
  <input type="checkbox" id="mike" value="Mike" v-model="checkedNames" />
  <label for="mike">Mike</label>
</template>

<script>
export default {
  data() {
    return {
      checked: true,
      checkedNames: []
    }
  }
}
</script>
  4)单选按钮使用v-model

    ① 在复选框中使用v-model一般赋值为布尔值,value代表当前值;

    ② 复选框的值绑定使用v-model+:value

<template>
  <!-- 普通示例 -->
  <div>Picked: {{ picked }}</div>
  <input type="radio" id="one" value="One" v-model="picked" />
  <label for="one">One</label>
  <input type="radio" id="two" value="Two" v-model="picked" />
  <label for="two">Two</label>
    
  <!-- 值绑定示例;值绑定使用 v-model+:value;pick 会在第一个按钮选中时被设为 first,在第二个按钮选中时被设为 second -->
  <input type="radio" v-model="pick" :value="first" />
  <input type="radio" v-model="pick" :value="second" />
</template>

<script>
export default {
  data() {
    return {
      picked: 'One'
    }
  }
}
</script>
  5)选择器使用v-model
<template>
  <!-- 单选 -->
  <span> Selected: {{ selected }}</span>
  <select v-model="selected">
    <option disabled value="">Please select one</option>
    <option>A</option>
    <option>B</option>
    <option>C</option>
  </select>
    
  <!-- 多选 -->
  <div>Selected: {{ selected }}</div>
  <select v-model="selected" multiple>
    <option>A</option>
    <option>B</option>
    <option>C</option>
  </select>
    
  <!-- 值绑定示例;当某个选项被选中,selected 会被设为该对象字面量值 { number: 123 }。 -->
  <select v-model="selected">
    <!-- 内联对象字面量 -->
    <option :value="{ number: 123 }">123</option>
  </select>
</template>

<script>
export default {
  data() {
    return {
      selected: '',
      selected: []
    }
  }
}
</script>
  6)组件上使用v-model

    ① 组件简单使用v-model

  <CustomInput v-model="searchText" />

      组件内处理方式1:

<!-- CustomInput.vue -->
<script>
export default {
  props: ['modelValue'],
  emits: ['update:modelValue'],
  computed: {
    value: {
      get() {
        return this.modelValue
      },
      set(value) {
        this.$emit('update:modelValue', value)
      }
    }
  }
}
</script>

<template>
  <input v-model="value" />
</template>

      组件内处理方式2(简写方式一):

<!-- CustomInput.vue -->
<script>
export default {
  props: ['modelValue'],
  emits: ['update:modelValue']
}
</script>

<template>
  <input
    :value="modelValue"
    @input="$emit('update:modelValue', $event.target.value)"
  />
</template>

    ② 组件使用多个v-model

      多写几个propsemits就好。

<UserName v-model:first-name="first" v-model:last-name="last"/>

<!-- UserName.vue -->
<template>
  <input
    type="text"
    :value="firstName"
    @input="$emit('update:firstName', $event.target.value)"
  />
  <input
    type="text"
    :value="lastName"
    @input="$emit('update:lastName', $event.target.value)"
  />
</template>
<script>
export default {
  props: {
    firstName: String,
    lastName: String
  },
  emits: ['update:firstName', 'update:lastName']
}
</script>
  7)v-model的一些修饰符

    ①.lazy:默认情况下,v-model 会在每次 input 事件后更新数据 (IME 拼字阶段的状态例外)。你可以添加 lazy 修饰符来改为在每次 change 事件后更新数据。如:<input v-model.lazy="msg" />

    ②.number:如果你想让用户输入自动转换为数字,你可以在 v-model 后添加 .number 修饰符来管理输入。如:<input v-model.number="age" />

      注:如果该值无法被 parseFloat() 处理,那么将返回原始值。number 修饰符会在输入框有 type="number" 时自动启用。

    ③.trim:如果你想要默认自动去除用户输入内容中两端的空格,你可以在 v-model 后添加 .trim 修饰符。如:<input v-model.trim="msg" />

  8)自定义修饰符
<MyComponent v-model.capitalize="myText" />

<!-- MyComponent -->
<template>
  <!-- 定义:value与@input事件 -->
  <input type="text" :value="modelValue" @input="emitValue" />
</template>

<script>
export default {
  props: {
    modelValue: String,  // 
    modelModifiers: {   // 修饰符组
      default: () => ({})
    }
  },
  emits: ['update:modelValue'],
  methods: {
    emitValue(e) {  // input事件中写我们自定义的修饰符的处理逻辑
      let value = e.target.value
      if (this.modelModifiers.capitalize) {  // 使用了自定义的capitalize修饰符时,如:<MyComponent v-model.capitalize="myText" />
        value = value.charAt(0).toUpperCase() + value.slice(1)  // 处理逻辑
      }
      this.$emit('update:modelValue', value)
    }
  }
}
</script>

  注:对于又有参数又有修饰符的 v-model 绑定,生成的 prop 名将是 arg + "Modifiers"。举例来说:<MyComponent v-model:title.capitalize="myText">对应的声明就是:

export default {
  props: ['title', 'titleModifiers'],
  emits: ['update:title'],
  created() {
    console.log(this.titleModifiers) // { capitalize: true }
  }
}

8、v-for数据循环赋值

  注意v-if 比 v-for 的优先级更高。这意味着 v-if 的条件将无法访问到 v-for 作用域内定义的变量别名。

  1)页面控件使用示例:
<!-- v-for示例一;循环10次;注:此处 n 的初值是从 1 开始而非 0。 -->
<span v-for="n in 10">{{ n }}</span>

<!-- v-for示例二;注:v-for="item of items"也是可以的 -->
<div v-for="item in items">{{ item.text }}</div>

<!-- v-for可访问父类对象 -->
<li v-for="(item, index) in items">
  {{ parentMessage }} - {{ index }} - {{ item.message }}
</li>
<!-- 结果:
    Parent - 0 - Foo
    Parent - 1 - Bar
-->

<!-- v-for第二个参数默认情况下表示当前项的位置索引 -->
<div v-for="(value, index) in object">内容:{{ value}},位置:{{ index }}</div>
<!-- v-for也可以自定义第二个参数标识属性名,第三个参数表示位置索引 -->
<div v-for="(value, name, index) in object">内容:{{value}},名称{{ name }},位置:{{ index }}</div>

...
data() {
  return {
    parentMessage: 'Parent',
    items: [{ message: 'Foo' }, { message: 'Bar' }]
  }
}
  2)v-for+Key的示例:

    v-for的默认方式是尝试就地更新元素而不移动它们。要强制其重新排序元素,你需要用特殊 attributekey 来提供一个排序提示: 

    <div v-for="item in items" :key="item.id">{{ item.text }}</div>

    注:key 绑定的值期望是一个基础类型的值,例如字符串或 number 类型。不要用对象作为 v-for 的 key

  3)template上使用v-for
<ul>
  <template v-for="item in items">
    <li>{{ item.msg }}</li>
    <li class="divider" role="presentation"></li>
  </template>
</ul>
  4)在自定义组件上使用v-for
<MyComponent
  v-for="(item, index) in items"
  :item="item"
  :index="index"
  :key="item.id"
/>

  但是这样写对象item不会传递给“自定义组件”,需要使用props将对象传递给“自定义组件”,见Todo List 的例子

  5)v-for创建的数组的变化侦测

  Vue 能够侦听响应式数组的变更方法,并在它们被调用时触发相关的更新。这些变更方法包括:

  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • sort()
  • reverse()

   后补(https://cn.vuejs.org/guide/essentials/list.html)

9、v-on监听 DOM 事件

    <a v-on:click="doSomething"> ... </a>

    <!-- 简写为@字符 -->
    <a @click="doSomething"> ... </a>
  1)写法一:内联事件处理器
<!-- 示例一:简单示例 -->
<button @click="count++">Add 1</button>
<p>Count is: {{ count }}</p>

<!-- 示例二:使用特殊的 $event 变量 -->
<button @click="warn('Form cannot be submitted yet.', $event)">
  Submit
</button>

<!-- 示例三:使用内联箭头函数 -->
<button @click="(event) => warn('Form cannot be submitted yet.', event)">
  Submit
</button>

data() {
  return {
    count: 0
  }
}

methods: {
  warn(message, event) {
    // 这里可以访问 DOM 原生事件
    if (event) {
      event.preventDefault()
    }
    alert(message)
  }
}
  2)写法二:方法事件处理器
<!-- 示例一:无参写法;`greet` 是定义过的方法名 -->
<button @click="greet">Greet</button>
<!-- 示例一:有参写法 -->
<button @click="say('hello')">Say hello</button>

data() {
  return {
    name: 'Vue.js'
  }
},
methods: {
  greet(event) {  // 没有类型标注时,这个 event 参数会隐式地标注为 any 类型;显式转化写法为 greet(event: Event) { }
    // 方法中的 `this` 指向当前活跃的组件实例
    alert(`Hello ${this.name}!`)
    // `event` 是 DOM 原生事件
    if (event) {
      alert(event.target.tagName)
    },
    say(message) {
      alert(message)
    }
  }
}
  3)事件修饰符

    后补(https://cn.vuejs.org/guide/essentials/event-handling.html#accessing-event-argument-in-inline-handlers)

  4)按键修饰符

    后补

  5)鼠标按键修饰符

    后补

10、v-slot组件中的占位属性(用于声明具名插槽或是期望接收 props 的作用域插槽)

  在某些场景中,我们可能想要为子组件传递一些模板片段,让子组件在它们的组件中渲染这些片段。以下为示例

  

  App.vue

<script>
    import FancyButton from './FancyButton.vue'
    import AwesomeIcon from './AwesomeIcon.vue'
      
    export default {
      components: { FancyButton, AwesomeIcon }
    }
    </script>
    
    <template>
      <FancyButton>
        Click me
     	</FancyButton>
    
      <FancyButton>
        <span style="color:red">Click me! </span>         <!-- 赋值到slot占位区域 -->
        <AwesomeIcon />
      </FancyButton>
    </template>

  FancyButton.vue

<template>
      <button class="fancy-btn">
        <!-- slot占位 -->
      	<slot/>
    	</button>
    </template>
    
    <style>
    .fancy-btn {
      color: #fff;
      background: linear-gradient(315deg, #42d392 25%, #647eff);
      border: none;
      padding: 5px 10px;
      margin: 5px;
      border-radius: 8px;
      cursor: pointer;
    }
    </style>

  AwesomeIcon.vue

    <!-- using an emoji just for demo purposes -->
    <template>❤️</template>

  v-slot详细介绍见:https://cn.vuejs.org/guide/components/slots.html

11、v-once仅渲染元素和组件一次

    <!-- 单个元素 -->
    <span v-once>This will never change: {{msg}}</span>
    <!-- 带有子元素的元素 -->
    <div v-once>
      <h1>comment</h1>
      <p>{{msg}}</p>
    </div>
    <!-- 组件 -->
    <MyComponent v-once :comment="msg" />
    <!-- `v-for` 指令 -->
    <ul>
      <li v-for="i in list" v-once>{{i}}</li>
    </ul>

12、v-memo当值与期望的值(或上次的值)不一样时渲染

    <!-- 示例1 :[valueA];当组件重新渲染的时候,如果valueA都维持不变,那么对这个<div>以及它的所有子节点的更新都将被跳过。-->
    <div v-memo="[valueA]">
      ...
    </div>
    
    <!-- 示例2 :[valueA, valueB];如果 valueA 和 valueB 都保持不变,这个 <div> 及其子项的所有更新都将被跳过-->
    <div v-memo="[valueA, valueB]">
      ...
    </div>
    
    <!-- 示例3:item.id === selected;下为“与 v-for 一起使用,有助于渲染海量 v-for 列表 (长度超过 1000 的情况)” -->
    <div v-for="item in list" :key="item.id" v-memo="[item.id === selected]">
      <p>ID: {{ item.id }} - selected: {{ item.id === selected }}</p>
      <p>...more child nodes</p>
    </div>

13、v-cloak隐藏尚未编译的 DOM 模板

  解决的Bug:当使用直接在 DOM 中书写的模板时,可能会出现一种叫做“未编译模板闪现”的情况:用户可能先看到的是还没编译完成的双大括号标签,直到挂载的组件将它们替换为实际渲染的内容。

  解决的对策:使用v-cloakv-cloak 会保留在所绑定的元素上,直到相关组件实例被挂载后才移除。配合像 [v-cloak] { display: none } 这样的 CSS 规则,它可以在组件编译完毕前隐藏原始模板。  

  示例:

    <div v-cloak>{{ message }}</div>
    
    [v-cloak] {
       display: none;
    }

14、自定义指令directives(后看)

  当在组件上使用自定义指令时,它会始终应用于组件的根节点。当应用到一个多根组件时,指令将会被忽略且抛出一个警告。和 attribute 不同,指令不能通过 v-bind="$attrs" 来传递给一个不同的元素。总的来说,推荐在组件上使用自定义指令。

  1)自定义指令(示例:当一个 input 元素被 Vue 插入到 DOM 中后,它会被自动聚焦)
<input v-focus />

...

const focus = {  // 指令对象
  mounted: (el) => el.focus()
}

export default {
  directives: {  // 在这里面自定义指令
    // 在模板中启用 v-focus
    focus
  }
}
  2)自定义全局指令
const app = createApp({})

// 使 v-focus 在所有组件中都可用
app.directive('focus', {
  /* ... */
})
  3)指令中使用钩子
// el: 指令绑定到的元素。这可以用于直接操作 DOM。
// binding:一个对象,包含以下属性
//   value:传递给指令的值。例如在 v-my-directive="1 + 1" 中,值是 2。
//   oldValue:之前的值,仅在 beforeUpdate 和 updated 中可用。无论值是否更改,它都可用。
//   arg:传递给指令的参数 (如果有的话)。例如在 v-my-directive:foo 中,参数是 "foo"。
//   modifiers:一个包含修饰符的对象 (如果有的话)。例如在 v-my-directive.foo.bar 中,修饰符对象是 { foo: true, bar: true }。
//   instance:使用该指令的组件实例。
//   dir:指令的定义对象。
// vnode:代表绑定元素的底层 VNode。
// prevVnode:之前的渲染中代表指令所绑定元素的 VNode。仅在 beforeUpdate 和 updated 钩子中可用。
const myDirective = {
  // 在绑定元素的 attribute 前
  // 或事件监听器应用前调用
  created(el, binding, vnode, prevVnode) {
    // 下面会介绍各个参数的细节
  },
  // 在元素被插入到 DOM 前调用
  beforeMount(el, binding, vnode, prevVnode) {},
  // 在绑定元素的父组件
  // 及他自己的所有子节点都挂载完成后调用
  mounted(el, binding, vnode, prevVnode) {},
  // 绑定元素的父组件更新前调用
  beforeUpdate(el, binding, vnode, prevVnode) {},
  // 在绑定元素的父组件
  // 及他自己的所有子节点都更新后调用
  updated(el, binding, vnode, prevVnode) {},
  // 绑定元素的父组件卸载前调用
  beforeUnmount(el, binding, vnode, prevVnode) {},
  // 绑定元素的父组件卸载后调用
  unmounted(el, binding, vnode, prevVnode) {}
}
  4)简化调用钩子

    对于自定义指令来说,一个很常见的情况是仅仅需要在 mounted 和 updated 上实现相同的行为,除此之外并不需要其他钩子。这种情况下我们可以直接用一个函数来定义指令,如下所示:

<div v-color="color"></div>

app.directive('color', (el, binding) => {
  // 这会在 `mounted` 和 `updated` 时都调用
  el.style.color = binding.value
})
  5)使用对象字面量

    如果你的指令需要多个值,你可以向它传递一个 JavaScript 对象字面量(JavaScript 表达式)。

<div v-demo="{ color: 'white', text: 'hello!' }"></div>

app.directive('demo', (el, binding) => {
  console.log(binding.value.color) // => "white"
  console.log(binding.value.text) // => "hello!"
})

15、一些指令的联合使用注意事项:

  1)v-if vs. v-show

     v-if 是“真实的”按条件渲染,因为它确保了在切换时,条件区块内的事件监听器和子组件都会被销毁与重建。

     v-if 也是惰性的:如果在初次渲染时条件值为 false,则不会做任何事。条件区块只有当条件首次变为 true 时才被渲染。

    相比之下,v-show 简单许多,元素无论初始条件如何,始终会被渲染,只有 CSS display 属性会被切换。

    总的来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要频繁切换,则使用 v-show 较好;如果在运行时绑定条件很少改变,则 v-if 会更合适。

  2)v-if 和 v-for

    当 v-if 和 v-for 同时存在于一个元素上的时候,v-if 会首先被执行。这意味着 v-if 的条件将无法访问到 v-for 作用域内定义的变量别名;在外新包装一层 <template> 再在其上使用 v-for 可以解决这个问题 (这也更加明显易读):

    <template v-for="todo in todos">
      <li v-if="!todo.isComplete">
        {{ todo.name }}
      </li>
    </template>

16、组件间传值(见Vue3 学习笔记(九)——Vue组件的使用

  1)props:子组件通过props属性监听父元素传过来的数据;子组件通过events给父组件发送消息;
  2)$emit():子组件通过$emit调用父组件的方法并传递数据;
  3)events:子组件通过events声明需要抛出的方法或变量

四、DOM 模板解析注意事项

1、大小写区分

  HTML 标签和属性名称是不分大小写的,所以浏览器会把任何大写的字符解释为小写。这意味着当你使用 DOM 内的模板时,无论是 PascalCase 形式的组件名称、camelCase 形式的 prop 名称还是 v-on 的事件名称,都需要转换为相应等价的 kebab-case (短横线连字符) 形式:

  原内容:

// JavaScript 中的 camelCase
const BlogPost = {
  props: ['postTitle'],
  emits: ['updatePost'],
  template: `
    <h3>{{ postTitle }}</h3>
  `
}

  解析后:

<!-- HTML 中的 kebab-case -->
<blog-post post-title="hello!" @update-post="onUpdatePost"></blog-post>

2、闭合标签

  这是因为 Vue 的模板解析器支持任意标签使用 /> 作为标签关闭的标志,如:<MyComponent />。然而在 DOM 模板中,我们必须显式地写出关闭标签,如:<my-component></my-component>。这是由于 HTML 只允许一小部分特殊的元素省略其关闭标签,最常见的就是 <input> 和 <img>。对于其他的元素来说,如果你省略了关闭标签,原生的 HTML 解析器会认为开启的标签永远没有结束,举例如下:

  原内容:

<my-component /> <!-- 我们想要在这里关闭标签... -->
<span>hello</span>

  解析后:

<my-component>
  <span>hello</span>
</my-component> <!-- 但浏览器会在这里关闭标签 -->

3、元素位置限制

  某些 HTML 元素对于放在其中的元素类型有限制,例如 <ul><ol><table> 和 <select>,相应的,某些元素仅在放置于特定元素中时才会显示,例如 <li><tr> 和 <option>

<table>
  <blog-post-row></blog-post-row>
</table>

  自定义的组件 <blog-post-row> 将作为无效的内容被忽略。 可写成下面的样式:

<table>
  <tr>
     <blog-post-row></blog-post-row>
  </tr>
</table>

<!-- 或者 -->
<table>
  <tr is="vue:blog-post-row"></tr>
</table>

4、组件名格式

  1)组件名官方推荐使用PascalCase命名规则,如:<PascalCase />;但是,PascalCase 的标签名在 DOM 模板中是不可用的。

  2)为了方便,Vue 支持将模板中使用 kebab-case 的标签解析为使用 PascalCase 注册的组件。这意味着一个以 MyComponent 为名注册的组件,在模板中可以通过 <MyComponent> 或 <my-component> 引用。

posted @ 2023-04-18 17:15  ꧁执笔小白꧂  阅读(110)  评论(0编辑  收藏  举报