Vue的Key属性vfor和vifvifvshowvpre不渲染vonce只渲染一次

25次阅读

共计 8389 个字符,预计需要花费 21 分钟才能阅读完成。

key 属性
为什么要加

key — api 解释

key 的特殊属性主要用在 vue 的虚拟 dom 算法,如果不适用 key,vue 会使用一种最大限度减少动态元素并且尽可能的尝试修复 / 再利用相同类型元素的算法。使用 Key,它会基于 Key 的变化重新排列元素顺序,并且会移除 Key 不存在的元素。

v-for 为什么要加 Key

<div id="app">
 <div>
  <input type="text" v-model="name">
    <button @click="add"> 添加 </button>
</div>

<ul>
<li v-for="(item, i) in list">
<input type="checkbox">
{{item.name}}
</li>
</ul>

<script>
// 创建 vue 实例,得到 viewmodel
var vm = new Vue({
el: '#app',
data: {
 name: '',
 newId: 3,
 list: [{id:1,name''}
 ]
 },
 methods: {add() {
     this.list.unshift({ 
     id: ++this.newId,  
     name: this.name })
     this.name=""
     }
     }
    });
</script>
</div>

有 key

  <div id="app">
    <div>
      <input type="text" v-model="name">
      <button @click="add"> 添加 </button>
    </div>
    <ul>
      <li v-for="(item, i) in list" :key="item.id">
        <input type="checkbox"> {{item.name}}
      </li>
    </ul>
<script>
    // 创建 Vue 实例,得到 ViewModel
    var vm = new Vue({
      el: '#app',
      data: {
        name: '',
        newId: 3,
        list: [{ id: 1, name: ''},
          {id: 2, name: ''},
          {id: 3, name: ''}
        ]
      },
      methods: {add() {
         // 注意这里是 unshift
          this.list.unshift({id: ++this.newId, name: this.name})
          this.name = ''
        }
      }
    });
  </script>
  </div>

为什么使用 v -for 时必须添加唯一的 key?

const list = [
    {
        id: 1,
        name: 'test1',
    },
    {
        id: 2,
        name: 'test2',
    },
    {
        id: 3,
        name: 'test3',
    },
]
<div v-for="(item, index) in list" :key="index" >{{item.name}}</div>
const list = [
    {
        id: 1,
        name: 'test1',
    },
    {
        id: 2,
        name: 'test2',
    },
    {
        id: 3,
        name: 'test3',
    },
    {
        id: 4,
        name: '我是在最后添加的一条数据',
    },
]
const list = [
    {
        id: 1,
        name: 'test1',
    },
    {
        id: 4,
        name: '我是插队的那条数据',
    }
    {
        id: 2,
        name: 'test2',
    },
    {
        id: 3,
        name: 'test3',
    },
]

两个相同的组件产生类似的 dom 结构,不同的组件产生不同的 dom 结构。

同一层级的一组节点

特殊特性
key

预期:number | string

key 的特殊属性主要用在 vue 的虚拟 dom 算法,在新旧 nodes 对比时辨识 vnodes。

<ul>
<li v-for="item in items" :key="item.id"></li>
</ul>

它可以用于强制替换元素,组件而不是重复使用它。

完整地触发组件的生命周期钩子
触发过渡

<transition>
<span :key="text">{{text}}</span>
</transition>

ref 被用来给元素或子组件注册引用信息,引用信息将会注册在父组件的 $refs 对象上。如果在普通的 dom 元素上使用,引用指向就是 dom 元素,如果用在子组件上,引用就指向组件实例:

<p ref="p"> hello </p>

<child-component ref="child"></child-component>

v-for 用于元素或组件的时候,引用信息将包含 dom 节点或组件实例的数组

is
用于动态组件且基于 dom 内模板的限制来工作

<component v-bind:is="currentView"></compoent>

<table>
<tr is="my-row"></tr>
</table>
data: function () {
  return {
    todos: [
      {
        id: 1,
        text: '学习使用 v-for'
      },
      {
        id: 2,
        text: '学习使用 key'
      }
    ]
  }
}
<ul>
  <li v-for="todo in todos">
    {{todo.text}}
  </li>
</ul>
<ul>
  <li
    v-for="todo in todos"
    :key="todo.id"
  >
    {{todo.text}}
  </li>
</ul>

永远不要把 v-if 和 v-for 同时用在同一个元素上。

为了过滤一个列表中的项目

v-for="user in users" v-if="user.isActive"
v-for="user in users"
v-if="shouldShowUsers"
<ul>
 <li v-for="user in users"
 v-if="user.isActive"
 :key="user.id">
 {{user.name}}
 </li>
</ul>
this.users.map(function (user) {if (user.isActive) {return user.name}
})
computed: {activeUsers: function() {return this.user.filter(function (user) {return user.isActive})
}
}
<ul>
<li v-for="user in activeUsers"
 :key="user.id">
 {{user.name}}
 </li>
 </ul>
<ul>
<li v-for="user in users" v-if="shouldShowUsers" :key="use.id">
{{user.name}}
</li>
</ul>
<ul>
<li v-for = "user in users"
v-if="user.isActive"
:key="user.id">
{{user.name}}
</li>
</ul>

<ul>
<li v-for="user in users"
v-if="shouldShowUsers"
:key="user.id">
{{user.name}}
</li>
</ul>
<ul>
  <li
    v-for="user in activeUsers"
    :key="user.id"
  >
    {{user.name}}
  </li>
</ul>
<ul v-if="shouldShowUsers">
  <li
    v-for="user in users"
    :key="user.id"
  >
    {{user.name}}
  </li>
</ul>
<ul>
  <li
    v-for="user in activeUsers"
    :key="user.id"
  >
    {{user.name}}
  </li>
</ul>
<ul v-if="shouldShowUsers">
  <li
    v-for="user in users"
    :key="user.id"
  >
    {{user.name}}
  </li>
</ul>
<template>
  <button class="btn btn-close">X</button>
</template>

<style>
.btn-close {background-color: red;}
</style>
<template>
  <button class="button button-close">X</button>
</template>

<!-- 使用 `scoped` 特性 -->
<style scoped>
.button {
  border: none;
  border-radius: 2px;
}

.button-close {background-color: red;}
</style>
<template>
  <button :class="[$style.button, $style.buttonClose]">X</button>
</template>

<!-- 使用 CSS Modules -->
<style module>
.button {
  border: none;
  border-radius: 2px;
}

.buttonClose {background-color: red;}
</style>
<template>
  <button :class="[$style.button, $style.buttonClose]">X</button>
</template>

<!-- 使用 CSS Modules -->
<style module>
.button {
  border: none;
  border-radius: 2px;
}

.buttonClose {background-color: red;}
</style>
<template>
  <button class="c-Button c-Button--close">X</button>
</template>

<!-- 使用 BEM 约定 -->
<style>
.c-Button {
  border: none;
  border-radius: 2px;
}

.c-Button--close {background-color: red;}
</style>

虚拟 Dom 以及 Key 属性的作用

<template>
<div id="app">
<input v-model="message" >
<input :value="message" @input="handleChange">
{{message}} {{message * message}}
<div :id="message"></div>
<todo-list>
 <todo-item @delete="handleDelete" v-for="(item, index) in list" :key="index" :title="item.title" :del="">
  <template v-slot:pre-icon="{value}">
     <span>{{value}}</span>
    </template>
 </todo-item>
</todo-list>

vue 是如果触发组件更新的

<script>
export default{
 name: " ",
 props: {
 info: Object,
 name: String,
 list: Array
 },
 data(){
  return {
     a: ' ',
     b: ' '
    };
},
updated() {console.log(' ');
},
methods: {handleBChange() {this.b = "vue" +Date.now();
 }
}
};

合理应用计算属性和侦听器

减少模板中计算逻辑
数据缓存
依赖固定的数据类型(响应式数据)

计算属性:computed

<p>{{reversedMessage1}}</p>
<p>{{reversedMessage2() }}</p>
<p> {{now}} </p>
<button @click="() => $forceUpdate()">forceUpdate</button>
<br/>
<input v-model="message"/>

export default {data() {
return {message: 'hello'};
},

computed: {
// 计算属性的 getter
reversedMessage1: function() {
 return this.message
  .split("")
    .reverse()
    .join("");
    },
    now: function() {return Date.now();
     }
    },
 methods: {reversedMessage2: function() {
 return this.message
 .split("")
 .reverse()
 .join("");
}

侦听器 watch
更加灵活,通用
watch 中可以执行任何逻辑,如函数节流,ajax 异步获取数据

<div>
{{$data}}
<br/>
<button @click="() => (a += 1)"><button>
</div>

wxport default {data: function() {
 return {
  a: 1,
    b: {c:2,d:3},
    e: {
     f: {g: 4}
    },
    h: []};
},
watch: {a: function(val, oldVal) {this.b.c += 1;},
 "b.c": function(val, oldVal) {this.b.d += 1;},
 "b.d": function(val, oldVal) {this.e.f.g += 1;}

computed vs watch

computed 能做的,watch 都能做,反之不行
能 computed 的尽量用 computed

<div>
{{fullName}}
<div> firstName: <input v-model="firstName"/></div>
<div> lastName: <input v-model="lastName"/></div>
</div>

export default {data: function() {
 return {
  firstName: 'foo',
    lastName: 'bar'
    };
},
computed: {fullName: function() {return this.firstName + " " + this.lastName;}
},
watch: {fullName: function(val, oldVal) {console.log("new",val,oldVal);
 }
}

vue 的生命周期的应用场景和函数式组件

生命周期:

创建阶段,更新阶段,销毁阶段

创建阶段:
beforeCreate
created
beforeMount
render
mounted

更新阶段
beforeUpdate
render
updated

销毁阶段
beforeDestory
destoryed

创建阶段:
beforeCreate
created
beforeMount
render
mounted

初始化事件和生命周期
beforeCreate
数据观测,属性,侦听器配置
created
模板编译到 render
beforeMount
render
mounted
异步请求,操作 dom,定时器等

更新阶段多次更新的阶段

更新阶段

beforeUpdate
render
updated

依赖数据改变或 $forceUpdate 强制刷新
beforeUpdate
移除已经添加的事件监听器等万万不可更改
render
updated
操作 dom 添加事件监听器等万万不更改依赖数据

销毁阶段:
beforedestory
destoryed

watch: {start() {this.startClock();
 }
},

函数式组件:
functional:true
无状态,无实例,没有 this 上下文,无生命周期

函数式组件:

vue 指令的本质

v-text

v-html

v-show

v-if

v-else

v-else-if

v-for

v-on

v-bind

v-model

v-slot

v-pre

v-cloak

v-once

自定义指令:
bind
inserted
update
componentUpdated
unbind

生命周期钩子

常用的高级特性 provide/inject

解决的问题为组件的通信问题

属性,通信
事件,通信

如何优雅地获取跨层级组件实例:
拒绝递归

引用信息

<p ref="p">hello</p>

<child-component ref="child"></child-component>

自动通知 setXXXref
主动获取 getxxxref

<button @click="getEH3Ref"></button

export default {
 components: {
  ChildrenB,
    ChildrenC,
    ChildrenD
    },
    provide() {
    return {setChildrenRef: (name, ref) => {this[name] = ref;
    },
    getChildrenRef: name => {return this[name];
    },
    getRef: () => {return this;}
};
},
<ChildrenH v-ant-ref="c => setChildrenRef("childrenH", c)"/>

export default {
components: {
ChildrenG,
ChildrenH,
ChildrenI
},
inject: {
setChildRef: {default: () = {}}
}
};

template 和 jsx 之间的区别

如何在 vue 中使用 vuex

import Vue from 'vue'
import Vuex from 'vuex'
import App from './App.vue'

Vue.use(Vuex)
Vue.config.productionTip = false

const store = Vue.Store({
 state: {count: 0,}
})

new Vue({
store,
render: h => h(App),
}).$mount('#app')
increment({commit}) {setTimeout(()=>{commit('increment')
  }, 3000)
}
<template>
<div id="app">
{{count}}
</div>
</template>

<script>
export default {
 name: 'app',
 computed: {count() {return this.$store.state.count}
    }
}
</script>
<button @click="$store.commit('increment', 2)">count++</button>
mutations: {increment(state, n) {state.count += n}
}

vuex 核心概念以及底层原理

核心概念
state->this.$store.state.xxx 取值
getter->this.$store.getters.xxx 取值

mutation->this.$store.commit(“xxx”)赋值
action->this.$store.dispatch(“xxx”) 赋值

module

底层原理:
State: 提供一个响应式数据
Getter: 借助 Vue 的计算属性 computed 来实现缓存

mutation: 更改 state 方法
action: 触发 mutaion 方法
module:Vue.set 动态添加 state 到响应式数据中

vuex 最佳实战

使用常量替代 mutation 事件类型

// mutation-type.js
export const SOME_MUTATION="SOME_MUTATION“// store.js
import Vuex from 'vues'
import {SOME_MUTATION} from ''

const store = new Vuex.Store({state: { ...},
mutations {[SOME_MUTATION] (state) {}}
})

传统开发模式

www.xxx.com - index.html
www.xxx.com/about -about.html


vue touter 的使用场景

监听 url 的变化,并在变化前后执行相应的逻辑

不同的 url 对应不同的不同的组件

提供多种方式改变 Url 的 api

使用方式:
提供一个路由配置表,不同 url 对应不同组件的配置
初始化路由实例 new VueRouter()

挂载到 vue 实例上
提供一个路由占位,用来挂载 Url 匹配到的组件

选择何种模式的路由以及底层原理

hash 模式:丑,无法使用锚点定位

Nuxt 解决了哪些问题?

Nuxt 核心原理,SSR 的核心原理

Ui 组件对比
Element UI,ANT design vue,iview

提升开发效率

Vetur,ESLint,Prettier,Vue DevTools

Vuex 是通过什么方式提供响应式数据的?

扩展简化版的 min-vuex,实现 getters,并实现 Vuex 的方式注入 $store

计算属性 computed 实现 getters 缓存

beforeCreate 中混入 $store 的获取方式


若本号内容有做得不到位的地方(比如:涉及版权或其他问题),请及时联系我们进行整改即可,会在第一时间进行处理。


请点赞!因为你们的赞同 / 鼓励是我写作的最大动力!

欢迎关注达达的简书!

这是一个有质量,有态度的博客

正文完
 0