迁移指南:https://v3.cn.vuejs.org/guide/migration/introduction.html
好用的插件:https://vueuse.org/,被遗忘了的几个指令 v-pre、v-once、this.$forceUpdate()、this.nextTick()
编程总结:在setup中应该如何去规划代码?如何模块化?如何才不会一团乱?
vue3 不同构建版本
Vue3中不再构建UMD模块化的方式,因为UMD会让代码有更多的冗余,它要支持多种模块化的方式。
Vue3中将CJS、ESModule和自执行函数的方式分别打包到了不同的文件中。在packages/vue中有Vue3的不同构建版本。
相关说明:https://cn.vuejs.org/v2/guide/installation.html
1.cjs
两个版本都是完整版,包含编译器
vue.cjs.js、vue.cjs.prod.js(开发版,代码进行了压缩)
2.global
这四个版本都可以在浏览器中直接通过scripts标签导入,导入之后会增加一个全局的Vue对象
vue.global.js(完整版,包含编译器和运行时) vue.global.prod.js(完整版,包含编译器和运行时,这是开发版本,代码进行了压缩) vue.runtime.global.js vue.runtime.global.prod.js
3.browser
四个版本都包含esm,浏览器的原生模块化方式,可以直接通可以直接通过<script type="module" />的方式来导入模块
vue.esm-browser.js vue.esm-browser.prod.js vue.runtime.esm-browser.js vue.runtime.esm-browser.prod.js
4.bundler
这两个版本没有打包所有的代码,只会打包使用的代码,需要配合打包工具来使用,会让Vue体积更小
vue.esm-bundler.js bue.runtime.esm-bundler.js
setup 组件选项
在 setup 中你应该避免使用 this,因为它不会找到组件实例。setup 的调用发生在 data property、computed property 或 methods 被解析之前,所以它们无法在 setup 中被获取。
setup 选项是一个接收 props 和 context 的函数,setup 返回的所有内容都暴露给组件的其余部分 (计算属性、方法、生命周期钩子等等) 以及组件的模板。
setup的执行在beforeCreate之前。只执行一次(参数都是包装后的proxy对象)
- props,代表给组件传递的参数
- context,组件所处的上下文对象(props、emit、slots);
思考
在setup如何高效的、准确的把各种逻辑抽离出来?使用组合式API时,在实践中尝试MVC,尽量不要把主要的业务逻辑写在组件里。setup 只是为 组件载入逻辑
提供了一个入口,而不应该把所有东西都写在里面。
Vue3 Composition API中的提取和重用逻辑:https://blog.csdn.net/duninet/article/details/105716706
<script setup>:https://blog.csdn.net/wu_xianqiang/article/details/120939405
Vue3中的响应式
- 基本数据类型还是使用get、set的方式(ref函数)。
- 对象数据类型使用的是Vue3的新函数reactive(基于Es6 Proxy)
- Proxy知识点总结:Proxy 用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种“元编程”(meta programming),即对编程语言进行编程。Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy 这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”。
- Proxy语法:https://es6.ruanyifeng.com/#docs/proxy可进行多种多样的数据拦截。
- ref函数使用的依然是Object的get、set方法实现响应式,而reactive函数式通过Proxy实现的数据劫持,同时使用Reflect反射对象去操作对象的属性。基本数据类型一般使用ref,对象或者数组则使用reactive函数。
增加配置项emits
用于组件指定可以接受的自定义事件。使用未被定义的自定义时间将会报错。
代码语言:javascript复制let emits=defineEmits(['refresh']); //定义事件
emits.emit("refresh"); //触发事件
对于setup新增的api函数
响应式相关:https://v3.cn.vuejs.org/api/refs-api.html
1.ref函数
在setup内创建响应式数据,如果将对象分配为 ref 值,则它将被 reactive 函数处理为深层的响应式对象。
代码语言:javascript复制const count = ref(0)
2.reactive函数
在setup内定义响应式数据(包括对象所有层次的属性);
代码语言:javascript复制const obj = reactive({ count: 0 })
3.readonly函数
接受一个对象 (响应式或纯对象) 或 ref 并返回原始对象的只读代理。只读代理是深层的:任何被访问的嵌套 property 也是只读的。
代码语言:javascript复制const original = reactive({ count: 0 })
const copy = readonly(original)
watchEffect(() => {
/* 用于响应性追踪 */
console.log(copy.count)
})
/* 变更 original 会触发依赖于副本的侦听器 */
original.count
/* 变更副本将失败并导致警告 */
copy.count /* 警告! */
4.toRaw
返回 reactive 或 readonly 代理的原始对象。
5.markRaw
标记一个对象,使其永远不会转换为 proxy。返回对象本身。
6.shallowReactive、shallowReadonly
创建一个响应式代理,它跟踪其自身 property 的响应性,但不执行嵌套对象的深层响应式转换 (暴露原始值)。只转换对象的自身的属性,不追踪内部属性的对象的属性
7.toRefs
在不丢失响应性的前提下,解构数据对象。
代码语言:javascript复制function useFeatureX() {
const state = reactive({
foo: 1,
bar: 2
})
/*操作 state 的逻辑*/
/*返回时转换为ref*/
return toRefs(state)
}
export default {
setup() {
/*可以在不失去响应性的情况下解构*/
const { foo, bar } = useFeatureX()
return {
foo,
bar
}
}
}
适合简化在层级较多的响应式对象调用。
说明:ref与toRef的区别
ref复制, 修改响应式数据,不会影响以前的数据,界面会更改。 toRef引用, 修改响应式的数据,会影响以前的数据,界面不会更新。
(1).ref本质是拷贝,修改响应式数据不会影响原始数据;toRef的本质是引用关系,修改响应式数据会影响原始数据 (2).ref数据发生改变,界面会自动更新;toRef当数据发生改变是,界面不会自动更新 (3).toRef传参与ref不同;toRef接收两个参数,第一个参数是哪个对象,第二个参数是对象的哪个属性
8.类型判断相关
- isReactive、isReadOnly,判断是否为响应式数据对象。
- isProxy,检查对象是否是由 reactive 或 readonly 创建的 proxy。
9.配置项相关
- computed,在setup内定义计算属性
- watch,在setup内定义监视属性
- watchEffect,用到谁就监视谁。类似computed,但是watchEffect更注重过程,computed注重返回的结果。
- 各种生命周期的函数和钩子。setup内定义的生命周期钩子在生命周期配置项定义的之前被调用(例如onCreated)。
- defineProps 和 defineEmits在 <script setup> 中必须使用 defineProps 和 defineEmits API 来声明 props 和 emits ,它们具备完整的类型推断并且在 <script setup> 中是直接可用。
Provide和Inject
父组件有一个 provide
选项来提供数据,后代组件有一个 inject
选项来开始使用这些数据。无论组件层次结构有多深,父组件都可以作为其所有子组件的依赖提供者。
作为配置项使用:https://v3.cn.vuejs.org/guide/component-provide-inject.html
组合式API中使用:https://v3.cn.vuejs.org/guide/composition-api-provide-inject.html
异步组件、Fragment和Teleport
官方文档:https://v3.cn.vuejs.org/guide/component-dynamic-async.html
1.Teleport
提供了一种干净的方法,允许我们控制在 DOM 中哪个父节点下渲染了 HTML,而不必求助于全局状态或将其拆分为两个组件。
代码语言:javascript复制<teleport to="body">
<div v-if="modalOpen" class="modal">
<div>
I'm a teleported modal!
(My parent is "body")
<button @click="modalOpen = false">
Close
</button>
</div>
</div>
</teleport>
2.Fragment
组件有多个根节点时将隐式产生。
script setup
1.在单文件组件中,当使用 <script setup> 的时候,任何在 <script setup> 声明的顶层的绑定 (包括变量,函数声明,以及 import 引入的内容) 都能在模板中直接使用。
2.当使用 <script setup> 的时候,任何在 <script setup> 声明的顶层的绑定 (包括变量,函数声明,以及 import 引入的内容) 都能在模板中直接使用。
3.使用 <script setup> 的组件是默认关闭的,也即通过模板 ref 或者 $parent 链获取到的组件的公开实例,不会暴露任何在 <script setup> 中声明的绑定。为了在 <script setup> 组件中明确要暴露出去的属性,使用 defineExpose 编译器宏。
提示
普通的 <script> 只在组件被首次引入的时候执行一次不同,<script setup> 中的代码会在每次组件实例被创建的时候执行。其模板会被编译成与其同一作用域的渲染函数,没有任何的中间代理
官方文档:https://v3.cn.vuejs.org/api/sfc-script-setup.html
v-bind.sync的改变
官方文档:https://v3.cn.vuejs.org/guide/migration/v-model.html#使用-v-bind-sync
在 3.x 中,自定义组件上的 v-model 相当于传递了 modelValue prop 并接收抛出的 update:modelValue 事件:
代码语言:javascript复制<ChildComponent v-model="pageTitle" />
<!-- 是以下的简写: -->
<ChildComponent
:modelValue="pageTitle"
@update:modelValue="pageTitle = $event"
/>
对比
1.setup内可结合vue的各种特性,而且可以结合传统的模块化编程思维,,复用各种代码使逻辑更加清晰。而vue更像是纯粹的新思维(自定义setup中的hook,封装composition API)。
迁移文档:https://v3.cn.vuejs.org/guide/migration/introduction.html
Vue-Router:https://next.router.vuejs.org/zh/guide/migration/index.html
在setup中获取$router,需要使用useRouter方法调用。
Element-plus:https://element-plus.gitee.io/zh-CN/
相关收集
1.Vue项目模板Vitesse:https://github.com/antfu/vitesse/blob/main/README.zh-CN.md
选项API变化
无法在 <script setup> 声明的选项,例如 inheritAttrs 或通过插件启用的自定义的选项。
代码语言:javascript复制<script>
// 普通 <script>, 在模块范围下执行(只执行一次)
runSideEffectOnce()
// 声明额外的选项
export default {
inheritAttrs: false,
customOptions: {}
}
</script>
1.inheritAttrs
默认情况下父作用域的不被认作 props 的 attribute 绑定 (attribute bindings) 将会“回退”且作为普通的 HTML attribute 应用在子组件的根元素上。当撰写包裹一个目标元素或另一个组件的组件时,这可能不会总是符合预期行为。通过设置 inheritAttrs 到 false,这些默认行为将会被去掉。而通过实例 property $attrs 可以让这些 attribute 生效,且可以通过 v-bind 显性的绑定到非根元素上。
该 property 包括组件 props 和 emits property 中未包含的所有属性 (例如,class、style、v-on 监听器等)。
与单个根节点组件不同,具有多个根节点的组件不具有自动 attribute fallthrough (隐式贯穿) 行为。如果未显式绑定 $attrs,将发出运行时警告。
2.compilerOptions
compilerOptions 用于设置编译模板的时候的一些配置
代码语言:javascript复制const Foo = {
// ...
compilerOptions: {
delimiters: ['${', '}'],
comments: true
}
}
组件中的style样式
1.深度选择器:deep()
处于 scoped 样式中的选择器如果想要做更“深度”的选择,也即:影响到子组件,可以使用 :deep() 这个伪类;
代码语言:javascript复制<style scoped>
.a :deep(.b) {
/* ... */
}
</style>
2.插槽选择器:slotted()
默认情况下,作用域样式不会影响到 渲染出来的内容,因为它们被认为是父组件所持有并传递进来的。使用 :slotted 伪类以确切地将插槽内容作为选择器的目标:
代码语言:javascript复制<style scoped>
:slotted(div) {
color: red;
}
</style>
3.全局选择器:global(.red)
如果想让其中一个样式规则应用到全局,比起另外创建一个 <style>,可以使用 :global 伪类来实现
代码语言:javascript复制<style scoped>
:global(.red) {
color: red;
}
</style>
4.css module
<style module> 标签会被编译为 CSS Modules 并且将生成的 CSS 类作为 $style 对象的键暴露给组件
5.状态驱动的动态 CSS
单文件组件的 <style> 标签可以通过 v-bind 这一 CSS 函数将 CSS 的值关联到动态的组件状态上
代码语言:javascript复制<script setup>
const theme = {
color: 'red'
}
</script>
<template>
<p>hello</p>
</template>
<style scoped>
p {
color: v-bind('theme.color');
}
</style>
实际的值会被编译成 hash 的 CSS 自定义 property,CSS 本身仍然是静态的。自定义 property 会通过内联样式的方式应用到组件的根元素上,并且在源值变更的时候响应式更新。
低级静态组件与 v-once
在 Vue 中渲染纯 HTML 元素的速度非常快,但有时你可能有一个包含很多静态内容的组件。在这些情况下,可以通过向根元素添加 v-once 指令来确保只对其求值一次,然后进行缓存,如下所示:
代码语言:javascript复制app.component('terms-of-service', {
template: `
<div v-once>
<h1>Terms of Service</h1>
... a lot of static content ...
</div>
`
})
提示
再次提醒,不要过度使用这种模式。虽然在需要渲染大量静态内容的极少数情况下使用这种模式会很方便,但除非你注意到先前的渲染速度很慢,否则就没有必要这样做——另外,过度使用这种模式可能会在以后引起很多混乱。例如,假设另一个开发人员不熟悉 v-once 或者没有在模板中发现它,他们可能会花上几个小时来弄清楚为什么模板没有正确更新。
异步组件
在大型应用中,我们可能需要将应用分割成小一些的代码块,并且只在需要的时候才从服务器加载一个模块。为了实现这个效果,Vue 有一个 defineAsyncComponent 方法
官方文档:https://v3.cn.vuejs.org/guide/component-dynamic-async.html#异步组件
代码语言:javascript复制import { defineAsyncComponent } from 'vue'
const AsyncComp = defineAsyncComponent(() =>
import('./components/AsyncComponent.vue')
)
app.component('async-component', AsyncComp)
异步组件可以搭配vite的import.meta.glob,批量引入某个目录下的所有组件作为异步组件。
问题总结
1.直接在浏览器内通过script引入Vue3,需要注意以下几点
- setup选项内,不能像在Cli内一样使用Vue的APi(如ref、reactive等),需要使用 Vue.ref 的形式才能调用。
- 闭包指的是在函数内定义的函数,所以它能直接使用上一个函数内的所有数据对象,而普通函数被调用时,是无法使用上一个执行的函数的局部变量的。在浏览器环境下需要将ref、reactive等API注册为全局变量。从而实现在setup内的模块化。
- 在浏览器环境下,组件标签必须正常闭合,否则会导致模板解析错误。
- 使用Vant库时,例如loading这些API,因为无法使用this调用vue实例,所以在setup内需要通过vant对象去调用。(CLI下通过Use引入入的Toast对象)
- v-slot:slotName,指定插槽名(只能在template标签上使用,只有一种特殊情况),v-slot 也有缩写,即把参数之前的所有内容 (v-slot:) 替换为字符 #。
2.setup异步请求
在开发 vue3 中,因为通过接口数据为异步函数获取,导致最后数据无法成功赋值进 return 中的数据。所以需要setup函数异步转同步,后设置了async 后异步转同步,结果导致页面空白不显示。在Vue3中,如果当前组件的setup使用了async/await,那么其调用组件的父组件(父组件中引用defineAsyncComponent定义异步组件)的外层需要嵌套一个suspense标签
异步组件不需要作为 的直接子节点。它可以出现在组件树任意深度的位置,且不需要出现在和 自身相同的模板中。只有所有的后代组件都准备就绪,该内容才会被认为解析完毕。
3.Vue.use 必须在 Vue.mount之前
Vue.use 必须在 Vue.mount之前,否则会报错。use is not a fucntion.
4.vant自动引入样式出错时
将安装的vite-plugin-style-import 插件1.2.0版本改为 1.4.1版本即可
代码语言:javascript复制npm install vite-plugin-style-import@1.4.1
5.在setup中操作dom节点
业务场景:echarts在指定的div上画图。
代码语言:javascript复制/*示例模板*/
<div ref="dom"></div>
/*定义一个ref*/
let dom=ref(null)
/*这里打印的就是节点*/
onMounted(()=>{
console.log(dom.value);
})
6.async setup中注册生命周期钩子时,必须写在第一个await之前;以下来自源代码的提示:
代码语言:javascript复制onMounted is called when there is no active component instance to be associated with.
Lifecycle injection APIs can only be used during execution of setup().
If you are using async setup(), make sure to register lifecycle hooks before the first await statement.
7.setup 自定义事件注册与触发
定义可接收的自定义事件:https://v3.cn.vuejs.org/api/sfc-script-setup.html#defineprops-和-defineemits
代码语言:javascript复制<script setup>
const emit = defineEmits(['change', 'delete'])
/* setup code */
</script>
使用setup配置项时,通过emits配置项定义。
触发自定义事件:
- 配置项setup中通过setup 函数的参数context.emit去触发。
- 语法糖script setup中通过difineEmit返回的对象去触发
/*传递context,用于触发自定义事件*/
onMounted(()=>{
mounted(context);
}); //挂载生命周期
8.传递的props不是响应式的
传递的props不建议去修改,基础类型和对象的引用修改时都会报错,传递的props值是一个对象时,属性值是可以修改的。
provide/inject可以看作是“长距离的 prop”,默认情况下,provide/inject 绑定并不是响应式的。我们可以通过传递一个 ref property 或 reactive 对象给 provide 来改变这种行为。
9.object
object["prop"] 和 object.prop 是通用的。
10.script setup内接受传参和自定义事件
代码语言:javascript复制/*定义注册自定义事件,设置模块的显示*/
let emit=defineEmits(["set"])
/*定义接受模块的设置*/
let props=defineProps([
"modules"
])
11.transition和transition-group
transition:用于给单独一个组件定义动画
transition-group:用于给多个组件同时定义动画
12.动态组件
代码语言:javascript复制<component :name="item.name" :is="item.component"></component>
13.通过props传递一个响应式数据
传递的props属性,对于基础类型和对象的引用修改时都会报错,但是修改对象的值是可以的,并且父组件会保持对这个属性的响应。
14.整个对象的替换,保持响应式
不管是vue2还是3,对于响应式对象的替换和修改都只能在对象内部进行,而不能直接去替换这一整个响应式对象,例如vue2中data返回的对象,直接替换之后就成为一个普通对象了,vue根本没机会去执行Object.defineProperty,对于Proxy对象,同样是如此。所有要想替换一整个对象,只能用Proxy对象的一个属性去进行操作。
15.vue绑定事件时传递事件对象
有时也需要在内联语句处理器中访问原始的 DOM 事件。可以用特殊变量 $event
把它传入方法
<button v-on:click="warn('Form cannot be submitted yet.', $event)">
Submit
</button>
16.setup内的异步操作
provide、inject、生命周期钩子都需要在异步操作之前,不然会导致获取不到值或者无法正常执行。
17.script setup内使用动态组件
不同于之前的直接使用字符串的组件名,在script setup中使用动态组件 is必须是一个代表引入组件的变量名,假如使用record组件(通过import引入),作为动态组件时必须把组件变量作为is的属性值。
代码语言:javascript复制/*通时通次*/
import record from './workspace/record.vue'
/*将引入的组件作为变量*/
let component={record,add,achievement,enter,sign,effective};
/*is值为引入的组件配置对象*/
<component :is="record"/>
18.异步数据加载(suspense)
- 使用suspense和await。await等待期间显示suspense的加载效果。
- 通过一个加载状态的标志,异步请求结束后变更为加载完成,显示主内容,未加载完时显示一个加载效果。
- 主要是要搞清楚,如果必须要同步那就await,不需要的话就可以使用加载标志。
- 什么时候需要使用await操作,那就是有多个异步行为的时候,后一个异步依赖于前一个异步的结果,可以避免大量的回调操作
/*获取各种排名数据*/
let rank=ranks();
场景举例
如上,ranks内有一个异步请求,按照js的运行逻辑,不会等待请求完毕,而是继续往下运行,所以最终rank为undefine;那么该如何解决,一是使用await同步执行,而是返回一个响应式的变量,让异步更新时,同步数据值。 使用异步组件时,同样适用于此。
19.keep-alive理解
当组件在 <keep-alive> 内被切换时,它的 mounted 和 unmounted 生命周期钩子不会被调用,取而代之的是 activated 和 deactivated。(这会运用在 <keep-alive> 的直接子节点及其所有子孙节点)。配合动态组件时,组件实例能够被在它们第一次被创建的时候缓存下来。
- avtived和deactived,在keeplive内任意一个组件注册时,路由组件从缓存中被激活、隐藏时触发。
- vue-router是基于动态组件实现的。
- keep-alive不支持多级路由缓存,对于一个单独的层级可以单独定义keep-alive。
- include - string | RegExp | Array。只有名称匹配的组件会被缓存。
- exclude - string | RegExp | Array。任何名称匹配的组件都不会被缓存。
- max - number | string。最多可以缓存多少组件实例。
官方文档:https://v3.cn.vuejs.org/guide/component-dynamic-async.html
18.模板相关知识
模板不仅可以使用data等响应式数据,也可以直接使用$route等api;
19.vue记录一次监视属性
通过watch监视一整个对象,对象和表单双向绑定。对象是通过axios从后端请求过来的,后赋值到reactive对象的属性(注意:此后这个数据对象、watch返回的new、old值都是这个对象的引用)。因为存在null值,绑定到表单的时候null会被转换为空字符串,导致对象属性发送改变,触发一次watch。在模板渲染和监视之前将null批量转换为空字符串,从而避免触发watch
代码语言:javascript复制null2str(data) {
if (typeof data != 'object'|| data === null|| data ==='null') {
data = '';
return data;
}else{
for (let x in data) {
if (data[x] === null || data[x] === 'null') { /*如果是null 把直接内容转为 ''*/
data[x] = '';
} else {
if (Array.isArray(data[x])) { /*是数组遍历数组 递归继续处理*/
data[x] = data[x].map(z => {
console.log(z)
return null2str(z);
});
}
if(typeof(data[x]) === 'object'){ /*是json 递归继续处理*/
data[x] = null2str(data[x])
}
}
}
return data;
}
}
20. v-model默认属性和事件的变化
官方文档:https://v3.cn.vuejs.org/guide/migration/v-model.html#概览
用于自定义组件时,v-model prop 和事件默认名称已更改:
- prop:value -> modelValue(model-value);
- 事件:input -> update:modelValue;
21.父组件操作子组件
在父组件中可以通过子组件的实例对象,调用子组件内的方法。
使用 <script setup> 的组件是默认关闭的,也即通过模板 ref 或者 $parent 链获取到的组件的公开实例,不会暴露任何在<script> 中声明的绑定。
为了在 script setup组件中明确要暴露出去的属性,使用 defineExpose 编译器宏.
当父组件通过模板 ref 的方式获取到当前组件的实例,获取到的实例会像这样 { a: number, b: number }
(ref 会和在普通实例中一样被自动解包)
22.组合式api中的computed
接受一个 getter 函数,并根据 getter 的返回值返回一个不可变的响应式 ref 对象。
23.Activated和deactivated
activated 和 deactivated。(这会运用在的直接子节点及其所有子孙节点。)
24.测试加载顺序。
从main.js开始,依次开始初始化状态管理器、路由对象,然后挂载Vue对象。
开始渲染App.vue,setup部分首先开始运行,然后开始加载路由守卫,之后依次加载组件。
25.组件间通信总结
props(父传子)、emit(子传父)、inject/provide(父子孙)、状态管理器(全局)
如果子组件需要共同操作和使用一项数据,这想数据应属于父组件的数据。子组件不应该直接修改父组件的数据,而是由父组件提供修改的方法,通过自定义事件传递给子组件,Vue通过inject响应式数据,实现所有子组件共同响应一项数据。同样的provide也可以直接传递方法。
26.provide和inject使用记录
当在setup语法糖内使用provide和inject时,如果代码在非阻塞的异步代码之后,控制台会输出异常警告(将初始的异步请求放在onMounted等生命周期内),但是在setup()函数内是没问题的,猜测是语法糖编译中的区别导致的。并且不只是provide、inject存在这个问题,其他的组合式api也可能出现这种情况。如果是阻塞式的方法(await),生命周期等函数必须在它之前运行
27.Vue组件拆分的新理解
1. 什么时候拆分路由?
很多功能相互独立、没有关联的时候拆分路由
2. 什么时候拆分组件?
按照功能的布局、功能的细化进行拆分,例如一个企业微信会话记录功能,可拆分为:左侧列表(列表可拆分上部分的用户信息、下部分的会话列表)、右侧聊天记录(上部分标题和搜索、下部分聊天记录框),也就是 1:2:4
3. 什么时候使用父子组件共享数据?
例如上面的2,就应该进行父子组件共享。选择的会话改变时,其他组件通过监视属性,触发数据更新。假如a、b都是c的子组件,a、b的共享数据应该定义在c,不应是c的父组件。父组件的父组件定义的应该是所有子组件用的,共享数据的层次感。。。!
28.v-for循环动态生成表单的时候,绑定循环的临时变量会保持响应式吗?
今天发现别人绑定是通过数组索引去绑定的,所以突然想到这个问题,事实上我一直是直接绑定的循环变量,响应式还是有的。也对,这么明显的问题,vue不可能考虑不到