vue基础(一)补充3
模块导出导入#
ES中的模块导出导入#
export 和 export default
首先我们讲这两个导出,下面我们讲讲它们的区别
- export与export default均可用于导出常量、函数、文件、模块等
- 在一个文件或模块中,export、import可以有多个,export default仅有一个
- 通过export方式导出,在导入时要加{ },export default则不需要
- export能直接导出变量表达式,export default不行。
nodejs中模块导出导入#
exports、module.exports
尽量都用 module.exports
导出,然后用require
导入。
module.exports 提供了暴露接口的方法。
require方能看到的只有module.exports这个对象,它是看不到exports对象的,而我们在编写模块时用到的exports对象实际上只是对module.exports的引用。
**module.exports **返回的是模块对象本身#
先说说它们之间的区别:
- exports只能使用语法来向外暴露内部变量:如http://exports.xxx = xxx;
- module.exports既可以通过语法,也可以直接赋值一个对象。
我们要明白一点,exports和module.exports其实是一个东西,不信我们来输出一下
console.log(module.exports === exports);
//输出结果为:true
输出结果是true其实就说明它们就是一个东西,其实exports = module.exports,因为他们是引用类型的一个变量名,所以当exports再指向一个引用类型的时候,那么他们就不再全等。
exports = [0, 1];
console.log(exports === module.exports);
//输出结果为:false
当然,如果直接通过exports.xxx
的形式赋值,那么他们依然会指向同一个地址:
exports.array = [0, 1];
console.log(exports === module.exports);
//输出结果为:true
mixin混入对象#
mixin混入对象中声明了:如果是同名钩子函数将合并为一个数组,因此都被调用,但是混入对象的钩子将在自身实例钩子之前触发;
mixin混入对象和Vuex的区别:
Vuex是状态共享管理,所以Vuex中的所有变量和方法都是可以读取和更改并相互影响的;
mixin可以定义公用的变量或方法,但是mixin中的数据是不共享的,也就是每个组件中的mixin实例都是不一样的,都是单独存在的个体,不存在相互影响的;
mixin混入对象值为函数的同名函数选项将会进行递归合并为数组,两个函数都会执行,只不过先执行mixin中的同名函数;
mixin混入对象值为对象的同名对象将会进行替换,都优先执行组件内的同名对象,也就是组件内的同名对象将mixin混入对象的同名对象进行覆盖;
vue 中 关于路径 @ 以及 ~的意义#
样式里引入样式,需要用 @import这种开头。
还要在样式里引入样式,并且想要使用 @ 符号表示src目录, 在以上前提下,需要在 @ 前加上~波浪号代表根目录。
@import '~@/assets/styles/mixins'
background: url("~@/assets/home/author-bg.png") no-repeat center/cover;
::v-deep深度作用选择器#
直接在 <style lang="scss" scoped> .... </style>
中编写的话只会影响当前组件内的样式,但如果去掉scoped
话又会影响全局样式。
<style lang="scss" scoped>
::v-deep .van-swipe__indicators {
}
如果你希望 scoped 样式中的一个选择器能够作用得“更深”,例如影响子组件,你可以使用 >>> 操作符:
<style scoped> .a >>> .b { /* ... */ } </style>
上述代码将会编译成:
.a[data-v-f3f3eg9] .b { /* … */ }
有些像 Sass 之类的预处理器无法正确解析 >>>。这种情况下你可以使用 /deep/ 或 ::v-deep 操作符取而代之——两者都是 >>> 的别名,同样可以正常工作。
sass 插值语句 #{}
#
通过 #{}
插值语句可以在选择器或属性名中使用变量:
@for $i from 1 through 3 {
.my-scroll-item:nth-child(#{$i}) {
.plan-curry3 {
.badge {
background-image: url("../assets/home/plan-badge#{$i}-active.png") !important;
}
}
}
}
loader原理,css-loader与style-loader#
1.css-loader 的作用是处理css中的 @import 和 url 这样的外部资源
2.style-loader 的作用是把样式插入到 DOM中,方法是在head中插入一个style标签,并把样式写入到这个标签的 innerHTML里
loader的原理
loader能把源文件翻译成新的结果,一个文件可以链式经过多个loader编译。以处理scss文件为例:
- sass-loader把scss转成css
- css-loader找出css中的依赖,压缩资源
- style-loader把css转换成脚本加载的JavaScript代码
vue.config.js 配置#
vue-cli3 脚手架搭建完成后,项目目录中没有 vue.config.js 文件,需要手动创建
module.exports = {
publicPath: "./",
lintOnSave: false,
devServer: {
open:false, // 是否打开浏览器
host:'lx.hi-daas.com',
port:8080,
https:false,
hotOnly:false, // 热更新
disableHostCheck:true,
proxy: {
"/apis": {
target: "http://serviceapi.ixlcg.com/api", // 接口域名
secure: false, // 如果是https接口,需要配置这个参数
changeOrigin: true, //是否跨域
pathRewrite: {
"^/apis": "", //需要rewrite的,
},
},
},
},
chainWebpack: config => {
// 添加别名
config.resolve.alias
.set('vue$', 'vue/dist/vue.esm.js')
.set('@', resolve('src'))
.set('@assets', resolve('src/assets'))
.set('@scss', resolve('src/assets/scss'))
.set('@components', resolve('src/components'))
.set('@plugins', resolve('src/plugins'))
.set('@views', resolve('src/views'))
.set('@router', resolve('src/router'))
.set('@store', resolve('src/store'))
.set('@layouts', resolve('src/layouts'))
.set('@static', resolve('src/static'))
},
css: {
loaderOptions: {
// 默认情况下 `sass` 选项会同时对 `sass` 和 `scss` 语法同时生效
// 因为 `scss` 语法在内部也是由 sass-loader 处理的
// 但是在配置 `prependData` 选项的时候
// `scss` 语法会要求语句结尾必须有分号,`sass` 则要求必须没有分号
// 在这种情况下,我们可以使用 `scss` 选项,对 `scss` 语法进行单独配置
scss: {
additionalData: `@import "~@/styles/index.scss";`,
},
},
},
};
scss配置全局变量,由于sass-loader版本不同,loaderOptions 中 additionalData的键名也不同
sass-loader v8-,这个选项名是 "data" sass-loader v8 中,这个选项名是 "prependData" sass-loader v10+,这个选项名是 "additionalData"
配置选项#
- publicPath
Type: string
Default: '/'
部署应用包时的基本 URL, 用法和 webpack 本身的 output.publicPath 一致。
这个值也可以被设置为空字符串 ('') 或是相对路径 ('./'),这样所有的资源都会被链接为相对路径,这样打出来的包可以被部署在任意路径。
-
lintOnSave
Type: boolean | 'error'
Default: true
是否在保存的时候使用
eslint-loader
进行检查。 有效的值:ture
|false
|"error"
当设置为"error"
时,检查出的错误会触发编译失败。 -
crossorigin
Type: string
Default: undefined
设置生成的HTML
中<link rel="stylesheet">
和<script>
标签的crossorigin
属性。 -
css.loaderOptions
Type: Object
Default: {}
向 CSS 相关的 loader 传递选项。
支持的 loader 有:
-
devServer
Type: Object
所有 webpack-dev-server 的选项都支持。注意:
有些值像 host、port 和 https 可能会被命令行参数覆写。
有些值像 publicPath 和 historyApiFallback 不应该被修改,因为它们需要和开发服务器的 publicPath 同步以保障正常的工作。
-
devServer.proxy
Type: string | Object
如果你的前端应用和后端 API 服务器没有运行在同一个主机上,你需要在开发环境下将 API 请求代理到 API 服务器。这个问题可以通过 vue.config.js 中的 devServer.proxy 选项来配置。
嵌套路由#
实际生活中的应用界面,通常由多层嵌套的组件组合而成。同样地,URL 中各段动态路径也按某种结构对应嵌套的各层组件,例如:
/user/foo/profile /user/foo/posts
+------------------+ +-----------------+
| User | | User |
| +--------------+ | | +-------------+ |
| | Profile | | +------------> | | Posts | |
| | | | | | | |
| +--------------+ | | +-------------+ |
+------------------+ +-----------------+
借助 vue-router
,使用嵌套路由配置,就可以很简单地表达这种关系。
创建的 app:
<div id="app">
<router-view></router-view>
</div>
这里的 <router-view>
是最顶层的出口,渲染最高级路由匹配到的组件。同样地,一个被渲染组件同样可以包含自己的嵌套 <router-view>
。例如,在 User
组件的模板添加一个 <router-view>
:
const User = {
template: `
<div class="user">
<h2>User {{ $route.params.id }}</h2>
<router-view></router-view>
</div>
`
}
要在嵌套的出口中渲染组件,需要在 VueRouter
的参数中使用 children
配置:
const router = new VueRouter({
routes: [
{
path: '/user/:id',
component: User,
children: [
{
// 当 /user/:id/profile 匹配成功,
// UserProfile 会被渲染在 User 的 <router-view> 中
path: 'profile',
component: UserProfile
},
{
// 当 /user/:id/posts 匹配成功
// UserPosts 会被渲染在 User 的 <router-view> 中
path: 'posts',
component: UserPosts
}
]
}
]
})
Vue 开发必须知道的 36 个技巧#
对 Axios 的插件化封装:#
import axios from 'axios'
// 创建一个错误
function errorCreate(msg) {
const error = new Error(msg)
throw error
}
// 创建一个 axios 实例
const service = axios.create({
// baseURL: process.env.NODE_ENV == "development" ? "/apis" : "http://xxx.com/api",
baseURL: process.env.NODE_ENV == "development" ? "/apis" : "http://xxx.com/api",
timeout: 6000 // 请求超时时间
})
// 请求拦截器
service.interceptors.request.use(
// 传入的config就是当前Axios对象
config => {
// 判断 发送的请求地址不止login时,一律添加请求头
//if(conf.url !== 'login'){
// conf.headers.Authorization = localStorage.getItem('token');
//}
config.headers['api-token'] = JSON.parse(window.localStorage.getItem('token'));
console.log(config);
// 将拦截器的操作返回给axios 对象
return config
},
error => {
// 发送失败 //对响应错误做点什么
console.log(error)
Promise.reject(error)
}
)
// 响应拦截器
service.interceptors.response.use(
response => {
// dataAxios 是 axios 返回数据中的 data
const dataAxios = response.data
// 这个状态码是和后端约定的
const { code } = dataAxios
// 根据 code 进行判断
if (code == "200") {
// 如果没有 code 代表这不是项目后端开发的接口 比如可能是 D2Admin 请求最新版本
return dataAxios.data
} else {
// 有 code 代表这是一个后端接口 可以进行进一步的判断
switch (code) {
case 0:
// [ 示例 ] code === 0 代表没有错误
return dataAxios
case 'xxx':
// [ 示例 ] 其它和后台约定的 code
errorCreate(`[ code: xxx ] ${dataAxios.msg}: ${response.config.url}`)
break
default:
// 不是正确的 code
errorCreate(`${dataAxios.msg}: ${response.config.url}`)
break
}
}
},
error => {
if (error && error.response) {
switch (error.response.status) {
case 400: error.message = '请求错误'; break
case 401: error.message = '未授权,请登录'; break
case 403: error.message = '拒绝访问'; break
case 404: error.message = `请求地址出错: ${error.response.config.url}`; break
case 408: error.message = '请求超时'; break
case 500: error.message = '服务器内部错误'; break
case 501: error.message = '服务未实现'; break
case 502: error.message = '网关错误'; break
case 503: error.message = '服务不可用'; break
case 504: error.message = '网关超时'; break
case 505: error.message = 'HTTP版本不受支持'; break
default: break
}
}
return Promise.reject(error)
}
)
export default service
导航守卫#
导航守卫: https://router.vuejs.org/zh/guide/advanced/navigation-guards.html
// 配置路由的导航守卫
import router from "./router";
// 当前用户是否登录
router.beforeEach((to, form, next) => {
if (to.name === 'Login') {
next();
} else {
// 如果请求的不是登录页面,验证token
// 1. 获取本地存储中的
token const token = localStorage.getItem('token');
if (!token) {
// 2. 如果没有token,跳转到登录
next({ name: 'Login'
}); } else {
// 3. 如果有token,继续往下执行
next();
}
}
});
// // 跳转页面后统一回到顶部
router.afterEach((to, form, next) => {
window.scrollTo(0, 0);
});
es6新增语法之${}
#
这是es6中新增的字符串方法
可以配合反单引号完成拼接字符串的功能
用法:
step1: 定义需要拼接进去的字符串变量
step2: 将字符串变量用${}包起来,再写到需要拼接的地方
step3:一定是用反单引号引起来的!不要写成单引号了!!
element-ui#
element-ui表格中加入按钮等元素时,需要使用 template 进行包裹:
而在 template 标签中有一个 slot-scope="scope" 属性, scope 的值就是本列中所有数据的值,参考: Table
表格->固定列,利用scope 中的值,争取显示用户状态
<el-table-column label="操作" width="210px">
<template>
<el-button type="primary" icon="el-icon-edit" plain></el-button>
<el-button type="primary" icon="el-icon-check" plain></el-button>
<el-button type="primary" icon="el-icon-delete" plain></el-button>
</template>
</el-table-column>
只要在 el-table 元素中定义了 height=500 属性,即可实现固定表头的表格,而不需要额外的代码。
要注意,以 /
开头的嵌套路径会被当作根路径。 这让你充分的使用嵌套组件而无须设置嵌套的路径。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?