const count = ref(1)
const plusOne = computed(() => count.value + 1)
console.log(plusOne.value) // 2
plusOne.value++ // 错误
const count = ref(1)
const plusOne = computed({
get: () => count.value + 1,
set: (val) => {
count.value = val - 1
}
})
plusOne.value = 1
console.log(count.value) // 0
watch 的第一个参数可以是不同形式的“数据源”:它可以是一个 ref (包括计算属性)、一个响应式对象、一个 getter 函数、或多个数据源组成的数组
你不能直接侦听响应式对象的属性值 ,因为属性值不为响应式监听,使用getter函数方式可以
const y = ref(0)
// 单个 ref
watch(x, (newX) => {
console.log(x is ${newX}
)
})
// getter 函数
watch(
() => x.value + y.value,
(sum) => {
console.log(sum of x + y is: ${sum}
)
}
)
// 多个来源组成的数组
watch([x, () => y.value], ([newX, newY]) => {
console.log(x is ${newX} and y is ${newY}
)
})
watchEffect,则会在副作用发生期间追踪依赖。它会在同步执行过程中,自动追踪所有能访问到的响应式属性。这更方便,而且代码往往更简洁,但有时其响应性依赖关系会不那么明确
对于这种只有一个依赖项的例子来说,watchEffect() 的好处相对较小。但是对于有多个依赖项的侦听器来说,使用 watchEffect() 可以消除手动维护依赖列表的负担。此外,如果你需要侦听一个嵌套数据结构中的几个属性,watchEffect() 可能会比深度侦听器更有效,因为它将只跟踪回调中被使用到的属性,而不是递归地跟踪所有的属性。
const todoId = ref(1)
const data = ref(null)
watch(todoId, async () => {
const response = await fetch(
https://jsonplaceholder.typicode.com/todos/${todoId.value}
)
data.value = await response.json()
}, { immediate: true })
简化
watchEffect(async () => {
const response = await fetch(
https://jsonplaceholder.typicode.com/todos/${todoId.value}
)
data.value = await response.json()
})
如果该值无法被 parseFloat() 处理,那么将返回原始值。
number 修饰符会在输入框有 type=“number” 时自动启用。
当使用@click.prevent修饰符时,点击事件将不会触发默认行为(例如将链接打开或提交表单),而只会执行绑定的方法。
点击按钮将调用submitForm方法来提交表单,而不会触发按钮的默认行为,即重新加载页面
,提供的响应式状态使后代组件可以由此和提供者建立响应式的联系。
import { ref, provide } from ‘vue’
Provide除了在一个组件中提供依赖,我们还可以在整个应用层面提供依赖:
import { createApp } from ‘vue’
const app = createApp({})
app.provide(/* 注入名 / ‘message’, / 值 */ ‘hello!’)
在应用级别提供的数据在该应用内的所有组件中都可以注入。这在你编写插件时会特别有用,因为插件一般都不会使用组件形式来提供值。
import { inject } from ‘vue’
const message = inject(‘message’,‘这是默认值’)
有的时候,我们可能需要在注入方组件中更改数据。在这种情况下,我们推荐在供给方组件内声明并提供一个更改数据的方法函数
export default {
setup(props) {
// 将 props
转为一个其中全是 ref 的对象,然后解构
const { title } = toRefs(props)
// title
是一个追踪着 props.title
的 ref
console.log(title.value)
// 或者,将 `props` 的单个属性转为一个 ref
const title = toRef(props, 'title')
}
}
const obj = reactive({
nested: { count: 0 },
arr: [‘foo’, ‘bar’]
})
function mutateDeeply() {
// 以下都会按照期望工作
obj.nested.count++
obj.arr.push(‘baz’)
}
shallowReactive()是 reactive() 的浅层作用形式
reactive() 返回的是一个原始对象的 Proxy,它和原始对象是不相等的
reactive() API 有两条限制:
仅对对象类型有效(对象、数组和 Map、Set 这样的集合类型),而对 string、number 和 boolean 这样的 原始类型 无效。
因为 Vue 的响应式系统是通过属性访问进行追踪的,因此我们必须始终保持对该响应式对象的相同引用。这意味着我们不可以随意地“替换”一个响应式对象,因为这将导致对初始引用的响应性连接丢失:
reactive() 的种种限制归根结底是因为 JavaScript 没有可以作用于所有值类型的 “引用” 机制。
TIP 不推荐使用 reactive() 的泛型参数,因为处理了深层次 ref 解包的返回值与泛型参数的类型不同。
允许我们创建可以使用
任何值类型的响应式 ref
const count = ref(0)
// 这是响应式的替换
objectRef.value = { count: 1 }
当 ref 在模板中作为顶层属性被访问时,它们会被自动“解包”,所以不需要使用 .value
当一个 ref 被嵌套在一个响应式对象中,作为属性被访问或更改时,它会自动解包,因此会表现得和一般的属性一样
只有当嵌套在一个深层响应式对象内时,才会发生 ref 解包。当其作为浅层响应式对象的属性被访问时不会解包。
const reactiveFoo = reactive(foo)
console.log(toRaw(reactiveFoo) === foo) // true
2、组件应该在一个单独的文件中进行定义,文件名应该与组件名相同,并以.vue为后缀。
import { ref } from ‘vue’
export default {
setup() {
const count = ref(0)
return { count }
},
template:
// 或者 template: '#my-template-element'
}
const props = defineProps([‘title’])
console.log(props.title)
接收任意类型的 JavaScript 值作为 props
export default {
props: [‘title’],
setup(props) {
console.log(props.title)
}
}
const props = defineProps({
foo: String
})
const emit = defineEmits([‘change’, ‘delete’])
// setup 代码
…
@enlarge-text=“postFontSize += 0.1”
/>
vue
props: {
value: {
type: String,
required: true
}
},
setup(props, { emit }) {
function onInput(event) {
emit(‘update:value’, event.target.value);
}
return {
onInput
};
}
});
为子组件传递一些模板片段,让子组件在它们的组件中渲染这些片段。
Click me!
*
插槽内容无法访问子组件的数据。Vue 模板中的表达式只能访问其定义时所处的作用域,这和 JavaScript 的词法作用域规则是一致的。换言之:
父组件模板中的表达式只能访问父组件的作用域;子组件模板中的表达式只能访问子组件的作用域。
*
A paragraph for the main content.
And another one.
Here’s some contact info
*
A paragraph for the main content.
And another one.
Here’s some contact info
我们也确实有办法这么做!可以像对组件传递 props 那样,向一个插槽的出口上传递 attributes:
template
可用于登录验证
进行了${++counter}路由跳转
) // if (to.path.indexOf(“/home”) !== -1) { // return “/login” // } if (to.path !== “/login”) { const token = window.localStorage.getItem(“token”); if (!token) { return “/login” } }router.addRoute({ path: ‘/about’, component: About }) 添加后不会调转,需要调用调转 push,replace
// 我们也可以使用 this.$route
或 route = useRoute() (在 setup 中) router.replace(router.currentRoute.value.fullPath)
// 删除路由
router.removeRoute(‘about’) router.hasRoute():检查路由是否存在。
router.getRoutes():获取一个包含所有路由记录的数组。
上的 name
属性匹配 RightSidebar, }, }, ], })routes:[
{
//第一组路由规则
path:'/home',
component:Home
children:[//为什么是数组形式?因为可能有多个子路由
{
path:'news',//这里的路径就不要加'/'了,因为底层给你遍历这一堆规则的时候人家已经给你加上'/'了
component:News,
}
]
},
]
})
News
Message
http://localhost:8080/#/news
1
为什么?
因为没有对应规则;刚才的路径/home变成了/news是一种路径的改变
路径改变了,前端路由器就监测到了,然后路由器拿着你的/news回到路由规则(router > index.js)里面进行匹配(在routes里面问)对比完毕没有对的上的,所以页面什么都不成现
News
Message
Getter 完全等同于 store 的 state 的计算值。可以通过 defineStore() 中的 getters 属性来定义它们。推荐使用箭头函数,并且它将接收 state 作为第一个参数
在使用常规函数定义 getter 时,我们也可以通过 this 访问到整个 store 实例,但(在 TypeScript 中)必须定义返回类型。这是为了避免 TypeScript 的已知缺陷,不过这不影响用箭头函数定义的 getter,也不会影响不使用 this 的 getter。
Action 相当于组件中的 method。它们可以通过 defineStore() 中的 actions 属性来定义,并且它们也是定义业务逻辑的完美选择。也可通过 this 访问整个 store 实例
不同的是,action 可以是异步的,你可以在它们里面 await 调用任何 API,以及其他 action!
getters
mutations
Vuex 的 store 中的状态的唯一方法是提交 mutation,Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的事件类型 (type)和一个回调函数 (handler)。它会接受 state 作为第一个参数
一条重要的原则就是要记住 mutation 必须是同步函数
actions
Action 类似于 mutation,不同在于: Action 提交的是 mutation,而不是直接变更状态。 Action 可以包含任意异步操作。
Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此你可以调用 context.commit 提交一个 mutation,或者通过 context.state 和 context.getters 来获取 state 和 getters
ES2015 的参数解构来简化代码(特别是我们需要调用 commit 很多次的时候)
发起网络请求的工具
Axios是一个基于Promise的HTTP客户端,可以用于发送HTTP请求并处理响应。它支持更多的浏览器,包括IE8及以上版本,并提供了更多的功能,如请求取消、拦截请求和响应等。同时,在错误处理和配置方面,Axios也比Fetch更加全面和灵活。
.then(response => console.log(response.data))
.catch(error => console.error(error));
axios.post(‘https://api.example.com/login’, {
username: ‘example’,
password: ‘password’
})
.then(response => console.log(response.data))
.catch(error => console.error(error));
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error(error));
get() {},
set() {},
})
当项目里“读取 obj.title”和“修改 obj.title”的时候被 defineProperty 拦截,但 defineProperty 对不存在的属性无法拦截,所以 Vue 2 中所有数据必须要在 data 里声明。
new Proxy(obj, {
get() { },
set() { },
})
需要注意的是,虽然 Proxy 拦截 obj 这个数据,但 obj 具体是什么属性,Proxy 则不关心,统一都拦截了。而且 Proxy 还可以监听更多的数据格式,比如 Set、Map,这是 Vue 2 做不到的。