# 创建项目
npm create vite@latest my-vue-app -- --template vue
# 安装依赖
npm i
# 运行
npm run dev
文本插值
最基本的数据绑定形式是文本插值,它使用的是“Mustache”语法 (即双大括号):
Message: {{ msg }}
双大括号标签会被替换为相应组件实例中 msg
属性的值。同时每次 msg
属性更改时它也会同步更新。
原始 HTML
双大括号会将数据解释为纯文本,而不是 HTML。若想插入 HTML,你需要使用 v-html 指令:
{{ num }}
Message: {{ msg }}
Using text interpolation: {{ html }}
Using v-html directive:
Attribute 绑定
双大括号不能在 HTML attributes 中使用。想要响应式地绑定一个 attribute,应该使用 v-bind 指令
let dynamicId=1
v-bind
指令指示 Vue 将元素的 id
attribute 与组件的 dynamicId
属性保持一致。如果绑定的值是 null
或者 undefined
,那么该 attribute 将会从渲染的元素上移除。
简写
因为 v-bind
非常常用,我们提供了特定的简写语法:
开头为 :
的 attribute 可能和一般的 HTML attribute 看起来不太一样,但它的确是合法的 attribute 名称字符,并且所有支持 Vue 的浏览器都能正确解析它。此外,他们不会出现在最终渲染的 DOM 中。简写语法是可选的,但相信在你了解了它更多的用处后,你应该会更喜欢它。
接下来的指引中,我们都将在示例中使用简写语法,因为这是在实际开发中更常见的用法。
布尔型 Attribute
布尔型 attribute 依据 true / false 值来决定 attribute 是否应该存在于该元素上。disabled 就是最常见的例子之一。
v-bind
在这种场景下的行为略有不同:
当 isButtonDisabled
为真值或一个空字符串 (即 ) 时,元素会包含这个
disabled
attribute。而当其为其他假值时 attribute 将被忽略。
动态绑定多个值
如果你有像这样的一个包含多个 attribute 的 JavaScript 对象:
const objectOfAttrs = {
id: 'container',
class: 'wrapper'
}
通过不带参数的 v-bind,你可以将它们绑定到单个元素上:
233
至此,我们仅在模板中绑定了一些简单的属性名。但是 Vue 实际上在所有的数据绑定中都支持完整的 JavaScript 表达式:
{{ number + 1 }}
{{ ok ? 'YES' : 'NO' }}
{{ message.split('').reverse().join('') }}
let number = 1
let ok = 1
let message = '如何快速进行多任务切换:多任 务切换的关键在 于能不能在一 段 时间内集 中火力, 把一件事做好,再去做下一件事。如果已经定下具 体的目标,一切的工具都只是辅助 ,必要时可以全都 舍弃掉。 '
let id = 1
这些表达式都会被作为 JavaScript ,以当前组件实例为作用域解析执行。
在 Vue 模板内,JavaScript 表达式可以被使用在如下场景上:
在文本插值中 (双大括号)
在任何 Vue 指令 (以 v-
开头的特殊 attribute) attribute 的值中
仅支持表达式
每个绑定仅支持单一表达式,也就是一段能够被求值的 JavaScript 代码。一个简单的判断方法是是否可以合法地写在 return
后面。
因此,下面的例子都是无效的:
{{ var a = 1 }}
{{ if (ok) { return message } }}
调用函数
可以在绑定的表达式中使用一个组件暴露的方法:
TIP
绑定在表达式中的方法在组件每次更新时都会被重新调用,因此不应该产生任何副作用,比如改变数据或触发异步操作。
受限的全局访问
模板中的表达式将被沙盒化,仅能够访问到有限的全局对象列表。该列表中会暴露常用的内置全局对象,比如 Math
和 Date
。
没有显式包含在列表中的全局对象将不能在模板内表达式中访问,例如用户附加在 window
上的属性。然而,你也可以自行在 app.config.globalProperties 上显式地添加它们,供所有的 Vue 表达式使用。
指令 Directives
指令是带有 v-
前缀的特殊 attribute。Vue 提供了许多内置指令,包括上面我们所介绍的 v-bind
和 v-html
。
指令 attribute 的期望值为一个 JavaScript 表达式 (除了少数几个例外,即之后要讨论到的 v-for
、v-on
和 v-slot
)。一个指令的任务是在其表达式的值变化时响应式地更新 DOM。以 v-if 为例:
Now you see me
这里,v-if
指令会基于表达式 seen
的值的真假来移除/插入该 元素。
参数 Arguments
某些指令会需要一个“参数”,在指令名后通过一个冒号隔开做标识。例如用 v-bind
指令来响应式地更新一个 HTML attribute:
...
...
这里 href 就是一个参数,它告诉 v-bind 指令将表达式 url 的值绑定到元素的 href attribute 上。在简写中,参数前的一切 (例如 v-bind:) 都会被缩略为一个 : 字符。
另一个例子是 v-on 指令,它将监听 DOM 事件:
...
...
这里的参数是要监听的事件名称:click
。v-on
有一个相应的缩写,即 @
字符。我们之后也会讨论关于事件处理的更多细节。
动态参数
同样在指令参数上也可以使用一个 JavaScript 表达式,需要包含在一对方括号内:
...
...
这里的 attributeName
会作为一个 JavaScript 表达式被动态执行,计算得到的值会被用作最终的参数。举例来说,如果你的组件实例有一个数据属性 attributeName
,其值为 "href"
,那么这个绑定就等价于 v-bind:href
。
相似地,你还可以将一个函数绑定到动态的事件名称上:
...
在此示例中,当 eventName
的值是 "focus"
时,v-on:[eventName]
就等价于 v-on:focus
。
动态参数值的限制
动态参数中表达式的值应当是一个字符串,或者是 null
。特殊值 null
意为显式移除该绑定。其他非字符串的值会触发警告。
动态参数语法的限制
动态参数表达式因为某些字符的缘故有一些语法限制,比如空格和引号,在 HTML attribute 名称中都是不合法的。例如下面的示例:
...
如果你需要传入一个复杂的动态参数,我们推荐使用计算属性替换复杂的表达式,也是 Vue 最基础的概念之一,我们很快就会讲到。
当使用 DOM 内嵌模板 (直接写在 HTML 文件里的模板) 时,我们需要避免在名称中使用大写字母,因为浏览器会强制将其转换为小写:
...
上面的例子将会在 DOM 内嵌模板中被转换为 :[someattr]
。如果你的组件拥有 “someAttr” 属性而非 “someattr”,这段代码将不会工作。单文件组件内的模板不受此限制。
修饰符 Modifiers
修饰符是以点开头的特殊后缀,表明指令需要以一些特殊的方式被绑定。例如 .prevent
修饰符会告知 v-on
指令对触发的事件调用 event.preventDefault()
:
之后在讲到 v-on 和 v-model 的功能时,你将会看到其他修饰符的例子。
最后,在这里你可以直观地看到完整的指令语法:
{{ text }}
{{ user }}
成年人:{{ user.age }}
未成年
长大了...
和v-if区别:始终会被渲染并保留在dom中,只是css被隐藏了 "display: none;"
{{ friends.name }} - {{ friends.age }} - {{ index }}
Class 与 Style 绑定
{{i}}
ref 和 reactive 是 Vue 3 中用于管理数据的两个方法。
ref 用于创建一个可响应的指针。指针可以指向任何值,包括原始值、对象或数组。当指针指向的值发生变化时,Vue 会自动更新指针的值。
reactive 用于创建一个响应式的对象。对象的所有属性都将成为响应式变量。当对象的属性发生变化时,Vue 会自动更新该属性的值。
name
、age
和 friends
。当这些属性发生变化时,user 对象的值也会发生变化。使用场景
ref 通常用于以下场景:
reactive 通常用于以下场景:
导入其他vue组件
{{ count }}
{{ data }}
{{ getStr }}
{{ getStr2 }}
name:{{ name }}
toRefs: toRefs是一个方法,它可以把一个响应式对象转换成普通对象,同时保留它的响应性。
比如有一个响应式对象:
const state = reactive({ foo: 1, bar: 2 })
如果我们解构它:
const { foo, bar } = state
那么foo和bar就失去了响应性。
但是如果我们使用toRefs:
const state = reactive({ foo: 1, bar: 2 });
const { foo, bar } = toRefs(state);
这样foo和bar仍然是响应式的!
所以toRefs的作用就是让解构后的变量也保持响应式。
computed: computed是一个方法,它可以创建一个计算属性。计算属性会根据它的依赖进行缓存和更新。监听一个值
比如:
const count = ref(1)
const plusOne = computed(() => count.value + 1)
console.log(plusOne.value) // 2
count.value++
console.log(plusOne.value) // 3
这里plusOne会跟踪count的变化并实时更新自己的值。
所以computed的作用就是创建一个有缓存的属性,避免重复计算。
相同效果
import { ref, reactive, computed, watch, watchEffect, toRefs } from "vue";
const state = reactive({ foo: 1, bar: 2 });
function changeData() {
state.foo++
state.bar++
}
const state = reactive({ foo: 1, bar: 2 });
const { foo, bar } = toRefs(state);
function changeData() {
foo.value++
bar.value++
}
unplugin-auto-import插件
解决 import { ref , reactive ..... } from 'vue'
大量引入的问题
配置后可以不用引入,直接使用
npm install -g cnpm --registry=https://registry.npm.taobao.org
cnpm i -D unplugin-auto-import
vite.config.js
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import AutoImport from "unplugin-auto-import/vite";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
AutoImport({
imports: ["vue", "vue-router"],
}),
],
});
一、配置
法一
vue3.4版本之后废除
vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [
vue({
reactivityTransform: true, // 启用响应式语法糖 $ref $computed $toRef ...
})
]
})
法二
https://vue-macros.sxzz.moe/zh-CN/features/reactivity-transform.html
tips: store(pinia版) 中使用 $ref 无法正常持久化数据!!!
cnpm i -D @vue-macros/reactivity-transform
vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import ReactivityTransform from '@vue-macros/reactivity-transform/vite';
export default defineConfig({
plugins: [
vue(),
ReactivityTransform(), // 启用响应式语法糖 $ref ...
]
})
解决ESLint警告: '$ref' is not defined.
.eslintrc.cjs
module.exports = {
globals: { $ref: 'readonly', $computed: 'readonly', $shallowRef: 'readonly', $customRef: 'readonly', $toRef: 'readonly' },
};
二、测试
原本 .value 响应式
{{ count }}
现在 $ref 去除 .value
{{ count }}
三、注意事项
$ref 在以下情况无法直接使用
store pinia
watch 监听器
通信方式:
一、props & emit
:list
传值defineProps
接收父组件值,defineEmits
调用父组件方法传值到父组件中 eg: proxy.$emit('handle-succ', data);父组件 https://cn.vuejs.org/api/sfc-script-setup.html#defineprops-defineemits
{{ count }}
子组件:
子组件
{{ list }}
二、v-model 父子组件双向绑定
v-model
props
接收父组件值modelValue
,proxy.$emit("update:modelValue", 666);
传值tips: 如果父组件是
v-model:num
,那么子组件的modelValue
变更为num
uniapp中可通过 props 来获取页面参数 (tips:子组件内无法通过这种方式获取到路径参数!) eg: /pages/index/index?code=xxx
==> const props = defineProps({ code: { type: String, required: false } });
父组件
父组件:{{ data }}
子组件
子组件:{{ modelValue }}
三、provide/inject:跨代传值
父组件
import { provide } from 'vue'
provide('msg', xxx)
子子组件
import { inject } from 'vue'
const msg = inject('msg')
const msg = inject('msg', 'hello') // 没值的话使用默认值hello
如果父组件想要调用子组件的方法
- 子组件为选项式api 可以在父组件中使用 `proxy.$refs.helloRef.changeData();` 调用
- 子组件为组合式api 需在子组件中使用 `defineExpose` 暴露需要调用的方法
父组件
```
```
子组件
```
count:{{ count }}
```
### 父组件
```
```
### 子组件
法一:
```
```
法二:
```
```
这是一个使用 Vue 3 的组件插槽(slots)的示例。
标签内定义了一个名为
HelloWorld
的组件。
这个组件有以下几种类型的插槽:
具名插槽(Named Slots)
使用方法:
...
...
作用域插槽(Scoped Slots)
可以将组件内的数据(item)传递给插槽。
使用方法:
...
动态插槽(Dynamic Slots)
插槽的名称可以动态绑定。
使用方法:
...
这里的 xx 可以是一个变量。
主要功能是组件内通过不同类型的插槽向组件外暴露数据或标记点,以便组件外插入自定义内容。
这提高了组件的灵活性和可复用性。
Vue 的插槽(slot)允许组件内注入自定义内容。它的工作原理可以简单概括为:
组件内部使用 标签作为插槽容器并定义名称
默认内容
...
组件外部使用特殊的 template 语法插入自定义内容到插槽中
Vue 渲染组件时:
如果有插入内容,则替换 对应位置为自定义内容
如果没有插入内容,则保留 的默认内容
所以,插槽允许用户决定组件内部的某些部分应显示什么内容,提高了组件的灵活性和可复用性。
同时为了模块化,插槽内容和组件其他部分相互独立。这就是插槽的工作原理。
作用域插槽(Scoped Slots)
在组件中,可以为插槽传递数据:
{{ user.lastName }}
组件使用方可以接收传递的数据并自定义插槽内容:
{{ slotProps.user.firstName }}
这样就实现了从组件内部将数据传递给插槽。
动态插槽(Dynamic Slots)
插槽名可以是动态绑定的:
...
使用模板引用作为插槽名:
...自定义内容
好的,举两个例子说明 Vue 插槽的高级用法:
slotName 可以是一个变量,这样插槽名就可以动态变化了。
这种方式非常灵活,允许根据条件自定义不同的插槽内容。
所以这两种机制都大大提高了插槽的可扩展性。
父组件:
具名插槽-right
作用域插槽:{{ data }}
动态插槽
子组件:
hello
具名插槽-left
组合式 API:生命周期钩子 | Vue.js
hello
1. setup()
```
// 组件初始化时执行,通常用于定义数据、方法等
setup(){
// 代码逻辑
}
```
2. onBeforeMount()
```
// 在组件渲染到页面之前执行
onBeforeMount(){
// 获取渲染前的 DOM 状态
}
```
3. onMounted()
```
// 组件渲染 complet 后执行
// 可以获取到 DOM 元素
onMounted(){
// 已经可以通过 ref 获取到 DOM
}
```
4. onBeforeUpdate()
```
// 数据更新前执行
onBeforeUpdate(){
// 可以在这里获取更新前的状态
}
```
5. onUpdated()
```
// 数据更新后执行(在组件的任意 DOM 更新后被调用)
onUpdated(){
// 组件重新渲染完成
}
```
这个钩子会在组件的任意 DOM 更新后被调用,这些更新可能是由不同的状态变更导致的,因为多个状态变更可以在同一个渲染周期中批量执行(考虑到性能因素)。如果你需要在某个特定的状态更改后访问更新后的 DOM,请使用 nextTick() 作为替代。
不要在 updated 钩子中更改组件的状态,这可能会导致无限的更新循环!
6. onBeforeUnmount()
```
// 组件销毁前执行
onBeforeUnmount(){
// 清除定时器、事件监听等
}
```
这些钩子函数可以让我们在不同阶段执行自定义逻辑,非常实用。
https://cn.vuejs.org/guide/built-ins/teleport.html
可以将一个组件内部的一部分模板“传送”到该组件的 DOM 结构外层的位置去。
Hello from the modal!
组件基础 | Vue.js
有些场景会需要在两个组件间来回切换,比如 Tab 界面
-
{{ item.name }}
A组件
B组件
这段代码实现了一个 tab 切换不同组件的功能。
主要逻辑是:
1. 定义了一个 tabList 数组,里面是不同的 tab 项,每个项包含 name 和 com 两个属性。
- name:tab 的名称
- com:对应的组件,使用 markRaw 包装过可以直接当组件使用
2. 定义一个当前组件 currentComponent,里面有一个 com 属性,默认设置为组件 A。
3. 使用 v-for 渲染 tab 列表,当点击不同的 tab 时,调用 change 方法。
4. change 方法中,根据点击的 tab 索引,设置 currentComponent.com 为对应的组件,这样就切换了当前的组件。
5. 使用 component 标签,动态绑定 currentComponent.com,所以就可以渲染不同的组件了。
这样通过 tab 切换,动态渲染不同的组件,实现了组件的动态切换。
举个例子,默认情况下渲染 A 组件,当我们点击“显示组件 B”这个 tab 时,就会切换到 B 组件。
所以这个例子实现了一个通过 tab 动态切换组件的功能。
在 `` 组件中,`:is` 是用于指定动态组件的属性。
`:is="currentComponent.com"` 表示动态绑定 currentComponent.com 中指定的组件,并渲染该组件。
一些关键点:
- `` 是 Vue 提供的一个内置组件,用于动态渲染组件
- `:is` 特殊 attribute,可以用来指定要动态渲染的组件
- 其值 `currentComponent.com` 需要是一个组件对象,这里通过引入并 `markRaw` 包装了组件满足要求
- 当 `currentComponent.com` 更新时,`:is` 也会动态更新,实现组件切换
所以简单说,`:is` 指定了 `` 需要渲染的目标组件。其动态性允许我们实现组件的动态切换。
这样通过 `currentComponent.com` 和 `:is` 的配合,我们就可以灵活地切换不同的组件了。
标题
描述
{{ item.title }}
{{ item.description }}
这两个代码示例的主要区别在于使用了不同的 HTTP 客户端来获取数据:
1. 使用 axios 获取数据:
```
const response = await axios.get('http://127.0.0.1:8000/api/data');
items.value = response.data;
```
axios 是一个流行的 HTTP 客户端,它会自动为我们转换响应数据到 JSON。所以我们可以直接通过 `response.data` 来访问 JSON 数据。
2. 使用原生 fetch 获取数据:
```
const response = await fetch('http://127.0.0.1:8000/api/data');
const data = await response.json();
items.value = data;
```
fetch 是浏览器原生提供的 API。它获取到的响应体是一个流数据,我们需要通过调用 `response.json()` 方法来自己把它转换成 JSON 对象。然后才能保存到 `data` 变量中,最后赋值给 `items.value`。
总结主要区别:
- axios 会自动转换响应数据,fetch 需要手动转换
- axios 是第三方库,fetch 是原生 API
- 语法上 axios 更简单直观,fetch 需要额外转换步骤
所以对于大多数用例来说,使用 axios 会更加便捷。但 fetch 作为原生 API 也有其优势,比如体积更小,兼容性更好。
vue-element-admin是一个后台前端解决方案,它基于vue和element-ui实现。它使用了最新的前端技术栈,内置了 i18 国际化解决方案,动态路由,权限验证,提炼了典型的业务模型,提供了丰富的功能组件,它可以帮助你快速搭建企业级中后台产品原型。
一上来就看到那么多文件夹确实头疼,咱先不管别的,主要先了解标注部分文件
├── build # 构建相关
├── config # 配置相关
├── mock # 项目mock 模拟数据
├── plop-templates
├── public # 静态资源
│ ├── favicon.ico
│ └── index.html
├── src # 源代码
│ ├── api # 所有请求
│ ├── assets # 主题 字体等静态资源
│ ├── components # 全局公用组件
│ ├── directive # 全局指令
│ ├── filters # 全局 filter
│ ├── icons # 项目所有 svg icons
│ ├── lang # 国际化 language
│ ├── layout # 布局相关
│ ├── mock # 项目mock 模拟数据
│ ├── router # 路由
│ ├── store # 全局 store管理
│ ├── styles # 全局样式
│ ├── utils # 全局公用方法
│ ├── vendor # 公用vendor
│ ├── views # view
│ ├── App.vue # 入口页面
│ ├── main.js # 入口 加载组件 初始化等
│ └── permission.js # 权限管理
├── tests
├── static # 第三方不打包资源
│ └── Tinymce # 富文本
├── .babelrc # babel-loader 配置
├── eslintrc.js # eslint 配置项
├── .gitignore # git 忽略项
├── favicon.ico # favicon图标
├── index.html # html模板
├── .env.xxx
├── .eslintrc.js
├── .travis.yml
├── vue.config.js # vue-cli 配置
└── package.json
# 克隆项目
git clone https://github.com/PanJiaChen/vue-element-admin.git
# 进入项目目录
cd vue-element-admin
# 建议不要用 cnpm 安装 会有各种诡异的bug 可以通过如下操作解决 npm 下载速度慢的问题
npm install --registry=https://registry.npm.taobao.org
# 安装依赖
npm install
# 本地开发 启动项目
npm run dev
新建一下request.js文件,修改如下
import request from '@/utils/request_new'
export function system_status() {
return request({
url: '/api/system_status',
method: 'get'
})
}
import axios from 'axios'
import { MessageBox, Message } from 'element-ui'
import store from '@/store'
import { getToken } from '@/utils/auth'
// create an axios instance
const service = axios.create({
baseURL:'http://127.0.0.1:8003', // url = base url + request url
// withCredentials: true, // send cookies when cross-domain requests
timeout: 5000, // request timeout
})
// request interceptor
service.interceptors.request.use(
config => {
// do something before request is sent
if (store.getters.token) {
// let each request carry token
// ['X-Token'] is a custom headers key
// please modify it according to the actual situation
config.headers['X-Token'] = getToken()
}
return config
},
error => {
// do something with request error
console.log(error) // for debug
return Promise.reject(error)
}
)
// response interceptor
service.interceptors.response.use(
/**
* If you want to get http information such as headers or status
* Please return response => response
*/
/**
* Determine the request status by custom code
* Here is just an example
* You can also judge the status by HTTP Status Code
*/
response => {
const res = response.data
return res
},
error => {
console.log('err' + error) // for debug
Message({
message: error.message,
type: 'error',
duration: 5 * 1000
})
return Promise.reject(error)
}
)
export default service
参考资料:手摸手,带你用vue撸后台 系列一(基础篇) - 掘金
快速上手 | Vue.js
vue-element-admin 跨域配置 - CSDN文库
vue配置多个服务端请求地址(使用vue-admin-template举例说明)_vue-admin-template改变请求地址-CSDN博客
https://github.com/qingqingxuan/vue-admin-work/blob/master/vue-admin-work%E6%93%8D%E4%BD%9C%E6%96%87%E6%A1%A3.md