毕设完成过程及遇到的问题
文章目录1.毕设开始2.流程3.遇到的问题1.Vue 报错:Module build failed: Error: Cannot find module 'node-sass'2.Vue日常踩坑日常 —— 在index.html中引入静态文件不生效问题3.vue项目中 favicon.ico不能正确显示的问题4.Module build failed: TypeError: this.getRes
文章目录
- 1.毕设开始
- 2.流程
- 3.遇到的问题
- 4.Vue3.0新特性
- 5.Vue3.0 生命周期函数
- 6.Vue Composition API
- 7.CSS中!important 作用
- 8.Normalize.css
- 9.vue中监控元素大小变化element-resize-detector
- 10.element-ui弹出层置于遮罩层下面问题
- 11.在项目中,遇到vue父子组件的传参问题,父组件传参给子组件,子组件在created和mounted等生命周期中获取不到,也无法使用父组件传递过来的参数。
- 12.Axios 各种请求方式传递参数格式
1.毕设开始
vue create erp-pc
vue create erp-app
2.流程
erp-pc
npm install @vue/composition-api --save
3.遇到的问题
1.Vue 报错:Module build failed: Error: Cannot find module ‘node-sass’
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dJmS00Gr-1594275653995)(https://images2017.cnblogs.com/blog/1163744/201711/1163744-20171106145442497-1646668115.png)]
解决方法:
输入命令:cnpm install node-sass@latest
2.Vue日常踩坑日常 —— 在index.html中引入静态文件不生效问题
本文针对的是Vue小白,不喜勿喷,谢谢
出现该问题的标志如下
控制台warning(Resource interpreted as Stylesheet but transferred with MIME type text/html
)
出现的原因及解决办法
第一种可能出现原因就是引入的静态文件在src文件夹内,这种的解决办法就是把资源引入静态资源的目录static
第二种可能出现的原因就是有单独的静态资源目录但是名字不叫static,这种的解决办法更改配置文件,把对应的几个配置文件内的static更改为你自己所创建的静态资源目录,由于网上大多教程所改的地方都不够完全,还是会出现该问题,所以这也是今天为什么要写这篇文章的原因。
需要更改的有3个文件,分别是config
文件夹下的index.js
,build
文件夹下的webpack.dev.conf.js
和webpack.prod.conf.js
假如你的静态资源文件夹叫public,和src文件夹同级,需要修改的如下
1. index.js
Copy dev: {
assetsSubDirectory: 'public',//原本是static,现在改为public
assetsPublicPath: `/${name}/`,
...
build: {
index: path.resolve(__dirname, '../dist/index.html'),
assetsRoot: path.resolve(__dirname, '../dist'),
assetsSubDirectory: 'public',//原本是static,现在改为public
2. webpack.dev.conf.js
Copy // copy custom static assets
new CopyWebpackPlugin([
{
//下面原本是static,现在改为public
from: path.resolve(__dirname, '../public'),
to: config.build.assetsSubDirectory,
ignore: ['.*']
}
])
3. webpack.prod.conf.js
Copy // copy custom static assets
new CopyWebpackPlugin([
{
//下面原本是static,现在改为public
from: path.resolve(__dirname, '../public'),
to: config.dev.assetsSubDirectory,
ignore: ['.*']
}
])
Ps:有任何问题欢迎在评论区探讨
3.vue项目中 favicon.ico不能正确显示的问题
首先将favicon.ico图片放在根目录下,通过以下两种方法使其显示正确。
方法一:修改index.html文件
<link rel="shortcut icon" type="image/x-icon" href="favicon.ico"/>
方法二:修改webpack配置文件
1、找到build下的webpack.dev.conf.js文件
new HtmlWebpackPlugin({
filename: 'index.html',
template: 'index.html',
inject: true,
favicon: path.resolve('favicon.ico') // 增加
}),
2、找到build下的webpack.prod.conf.js文件
new HtmlWebpackPlugin({
filename: config.build.index,
template: 'index.html',
inject: true,
favicon: path.resolve('favicon.ico'), //新增
minify: {
removeComments: true,
collapseWhitespace: true,
removeAttributeQuotes: true
...
}),
修改配置文件后重启npm run dev,大功告成。
注意:如果打包发布到线上,会导致ico图标不显示的问题,是因为执行npm run build
打包后只有static文件夹和index.html文件,找不到根目录下的ico图标,解决办法:把ico图标放到static文件夹下就OK啦。
4.Module build failed: TypeError: this.getResolve is not a function at Object.loader 安装node-sass运行报错
vue安装node-sass编译报错
安装node-scss报错
安装node-scss报错
在搭建vue脚手架 或者是在vue项目中,想使用sass的功能,
npm install node-sass --save-dev //安装node-sass
npm install sass-loader --save-dev //安装sass-loader
npm install style-loader --save-dev //安装style-loader
安装完成后,运行时出现了错误
Modele build failed: TypeError: this.getResolve is not a function at Object.loader…
这是因为当前sass的版本太高,webpack编译时出现了错误,这个时候只需要换成低版本的就行,下面说一下修改方法,很简单,如下,找到package.json文件,里面的 "sass-loader"的版本更换掉 就行了。
我本地是将 “sass-loader”: “^8.0.0”,更换成了 “sass-loader”: “^7.3.1”,
这时候重新跑项目,就运行成功了。
也可以先卸载当前版本,然后安装指定的版本
卸载当前版本 npm uninstall sass-loader
安装 npm install sass-loader@7.3.1 --save-dev
5.sass 在vue中报错
vue文件:
<style scoped lang="scss">
@import '~scss_vars';
</style>
错误提示:
File to import not found or unreadable: ~scss_vars.
Parent style sheet: stdin
in D:\vue\mock\src\views\Home.vue (line 79, column 1)
package.json:
"file-loader": "^1.1.5",
"mockjs": "^1.0.1-beta3",
"node-sass": "^4.6.0",
"sass-loader": "^6.0.6",
如果你要这么写就需要在webpack里配置resolve 如果你用的vue-cli的话就是在webpack.base.config.js里配置
resolve: {
extensions: ['.js', '.vue', '.json', '.scss'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'@': resolve('src'),
'scss': path.resolve(__dirname, '../src/style'),
}
}
这个样式根路径,如果指定某个文件就要在别名里指定即可
已经说了 这个scss resolve的是根路径,而你要引入的是styles里面的scss_vars.scss文件 那么你就要@import ‘~scss/scss_vars’
4.Vue3.0新特性
0. 基础要求
- 了解常见的 ES6 新特性
- ES6 的导入导出语法
- 解构赋值
- 箭头函数
- etc…
- 了解 vue 2.x 的基本使用
- 组件
- 常用的指令
- 生命周期函数
- computed、watch、ref 等
1. 相关资源
- 【知乎 - Vue Function-based API RFC】https://zhuanlan.zhihu.com/p/68477600
- 【github - vuejs/composition-api】https://github.com/vuejs/composition-api
- 【github - composition-api/CHANGELOG.md】https://github.com/vuejs/composition-api/blob/master/CHANGELOG.md
- 【开源中国 - 尤雨溪公布 Vue 3.0 开发路线:将从头开始重写 3.0】https://www.oschina.net/news/100515/plans-for-the-next-iteration-of-vue-js
2. 初始化项目
-
安装 vue-cli3
npm install -g @vue/cli # OR yarn global add @vue/cli
-
创建项目
vue create my-project # OR vue ui
-
在项目中安装
composition-api
体验 vue3 新特性npm install @vue/composition-api --save # OR yarn add @vue/composition-api
-
在使用任何
@vue/composition-api
提供的能力前,必须先通过Vue.use()
进行安装import Vue from 'vue' import VueCompositionApi from '@vue/composition-api' Vue.use(VueCompositionApi)
安装插件后,您就可以使用新的 Composition API 来开发组件了。
3. setup
setup()
函数是 vue3 中,专门为组件提供的新属性。它为我们使用 vue3 的 Composition API
新特性提供了统一的入口。
3.1 执行时机
setup 函数会在 beforeCreate 之后、created 之前执行
相当于 created, 只会执行一次
3.2 接收 props 数据
-
在
props
中定义当前组件允许外界传递过来的参数名称:props: { p1: String }
-
通过
setup
函数的第一个形参,接收props
数据:setup(props) { console.log(props.p1) }
3.3 context
setup
函数的第二个形参是一个上下文对象,这个上下文对象中包含了一些有用的属性,这些属性在 vue 2.x
中需要通过 this
才能访问到,在 vue 3.x
中,它们的访问方式如下:
const MyComponent = {
setup(props, context) {
context.attrs
context.slots
context.parent
context.root
context.emit
context.refs
}
}
注意:在
setup()
函数中无法访问到this
4. reactive
reactive()
函数接收一个普通对象,返回一个响应式的数据对象。
4.1 基本语法
等价于 vue 2.x
中的 Vue.observable()
函数,vue 3.x
中提供了 reactive()
函数,用来创建响应式的数据对象,基本代码示例如下:
import { reactive } from '@vue/composition-api'
// 创建响应式数据对象,得到的 state 类似于 vue 2.x 中 data() 返回的响应式对象
const state = reactive({ count: 0 })
4.2 定义响应式数据供 template 使用
-
按需导入
reactive
函数:import { reactive } from '@vue/composition-api'
-
在
setup()
函数中调用reactive()
函数,创建响应式数据对象:setup() { // 创建响应式数据对象 const state = reactive({count: 0}) // setup 函数中将响应式数据对象 return 出去,供 template 使用 return state }
-
在
template
中访问响应式数据:<p>当前的 count 值为:{{count}}</p>
5. ref
5.1 基本语法
ref()
函数用来根据给定的值创建一个响应式的数据对象,ref()
函数调用的返回值是一个对象,这个对象上只包含一个 .value
属性:
import { ref } from '@vue/composition-api'
// 创建响应式数据对象 count,初始值为 0
const count = ref(0)
// 如果要访问 ref() 创建出来的响应式数据对象的值,必须通过 .value 属性才可以
console.log(count.value) // 输出 0
// 让 count 的值 +1
count.value++
// 再次打印 count 的值
console.log(count.value) // 输出 1
5.2 在 template 中访问 ref 创建的响应式数据
-
在
setup()
中创建响应式数据:import { ref } from '@vue/composition-api' setup() { const count = ref(0) return { count, name: ref('zs') } }
-
在
template
中访问响应式数据:<template> <p>{{count}} --- {{name}}</p> </template>
5.3 在 reactive 对象中访问 ref 创建的响应式数据
当把 ref()
创建出来的响应式数据对象,挂载到 reactive()
上时,会自动把响应式数据对象展开为原始的值,不需通过 .value
就可以直接被访问,例如:
const count = ref(0)
const state = reactive({
count
})
console.log(state.count) // 输出 0
state.count++ // 此处不需要通过 .value 就能直接访问原始值
console.log(count) // 输出 1
注意:新的 ref 会覆盖旧的 ref,示例代码如下:
// 创建 ref 并挂载到 reactive 中
const c1 = ref(0)
const state = reactive({
c1
})
// 再次创建 ref,命名为 c2
const c2 = ref(9)
// 将 旧 ref c1 替换为 新 ref c2
state.c1 = c2
state.c1++
console.log(state.c1) // 输出 10
console.log(c2.value) // 输出 10
console.log(c1.value) // 输出 0
6. isRef
isRef()
用来判断某个值是否为 ref()
创建出来的对象;应用场景:当需要展开某个可能为 ref()
创建出来的值的时候,例如:
import { isRef } from '@vue/composition-api'
const unwrapped = isRef(foo) ? foo.value : foo
7. toRefs
toRefs()
函数可以将 reactive()
创建出来的响应式对象,转换为普通的对象,只不过,这个对象上的每个属性节点,都是 ref()
类型的响应式数据,最常见的应用场景如下:
import { toRefs } from '@vue/composition-api'
setup() {
// 定义响应式数据对象
const state = reactive({
count: 0
})
// 定义页面上可用的事件处理函数
const increment = () => {
state.count++
}
// 在 setup 中返回一个对象供页面使用
// 这个对象中可以包含响应式的数据,也可以包含事件处理函数
return {
// 将 state 上的每个属性,都转化为 ref 形式的响应式数据
...toRefs(state),
// 自增的事件处理函数
increment
}
}
页面上可以直接访问 setup()
中 return 出来的响应式数据:
<template>
<div>
<p>当前的count值为:{{count}}</p>
<button @click="increment">+1</button>
</div>
</template>
8. computed
computed()
用来创建计算属性,computed()
函数的返回值是一个 ref
的实例。使用 computed
之前需要按需导入:
import { computed } from '@vue/composition-api'
8.1 创建只读的计算属性
在调用 computed()
函数期间,传入一个 function
函数,可以得到一个只读的计算属性,示例代码如下:
// 创建一个 ref 响应式数据
const count = ref(1)
// 根据 count 的值,创建一个响应式的计算属性 plusOne
// 它会根据依赖的 ref 自动计算并返回一个新的 ref
const plusOne = computed(() => count.value + 1)
console.log(plusOne.value) // 输出 2
plusOne.value++ // error
8.2 创建可读可写的计算属性
在调用 computed()
函数期间,传入一个包含 get
和 set
函数的对象,可以得到一个可读可写的计算属性,示例代码如下:
// 创建一个 ref 响应式数据
const count = ref(1)
// 创建一个 computed 计算属性
const plusOne = computed({
// 取值函数
get: () => count.value + 1,
// 赋值函数
set: val => { count.value = val - 1 }
})
// 为计算属性赋值的操作,会触发 set 函数
plusOne.value = 9
// 触发 set 函数后,count 的值会被更新
console.log(count.value) // 输出 8
9. watch
watch()
函数用来监视某些数据项的变化,从而触发某些特定的操作,使用之前需要按需导入:
import { watch } from '@vue/composition-api'
9.1 基本用法
const count = ref(0)
// 定义 watch,只要 count 值变化,就会触发 watch 回调
// watch 会在创建时会自动调用一次
watch(() => console.log(count.value))
// 输出 0
setTimeout(() => {
count.value++
// 输出 1
}, 1000)
9.2 监视指定的数据源
监视 reactive
类型的数据源:
// 定义数据源
const state = reactive({ count: 0 })
// 监视 state.count 这个数据节点的变化
watch(() => state.count, (count, prevCount) => { /* ... */ })
监视 ref
类型的数据源:
// 定义数据源
const count = ref(0)
// 指定要监视的数据源
watch(count, (count, prevCount) => { /* ... */ })
9.3 监视多个数据源
监视 reactive
类型的数据源:
const state = reactive({ count: 0, name: 'zs' })
watch(
[() => state.count, () => state.name], // Object.values(toRefs(state)),
([count, name], [prevCount, prevName]) => {
console.log(count) // 新的 count 值
console.log(name) // 新的 name 值
console.log('------------')
console.log(prevCount) // 旧的 count 值
console.log(prevName) // 新的 name 值
},
{
lazy: true // 在 watch 被创建的时候,不执行回调函数中的代码
}
)
setTimeout(() => {
state.count++
state.name = 'ls'
}, 1000)
监视 ref
类型的数据源:
const count = ref(0)
const name = ref('zs')
watch(
[count, name], // 需要被监视的多个 ref 数据源
([count, name], [prevCount, prevName]) => {
console.log(count)
console.log(name)
console.log('-------------')
console.log(prevCount)
console.log(prevName)
},
{
lazy: true
}
)
setTimeout(() => {
count.value++
name.value = 'xiaomaolv'
}, 1000)
9.4 清除监视
在 setup()
函数内创建的 watch
监视,会在当前组件被销毁的时候自动停止。如果想要明确地停止某个监视,可以调用 watch()
函数的返回值即可,语法如下:
// 创建监视,并得到 停止函数
const stop = watch(() => { /* ... */ })
// 调用停止函数,清除对应的监视
stop()
9.5 在 watch 中清除无效的异步任务
有时候,当被 watch
监视的值发生变化时,或 watch
本身被 stop
之后,我们期望能够清除那些无效的异步任务,此时,watch
回调函数中提供了一个 cleanup registrator function
来执行清除的工作。这个清除函数会在如下情况下被调用:
- watch 被重复执行了
- watch 被强制
stop
了
Template 中的代码示例如下:
/* template 中的代码 */
<input type="text" v-model="keywords" />
Script 中的代码示例如下:
// 定义响应式数据 keywords
const keywords = ref('')
// 异步任务:打印用户输入的关键词
const asyncPrint = val => {
// 延时 1 秒后打印
return setTimeout(() => {
console.log(val)
}, 1000)
}
// 定义 watch 监听
watch(
keywords,
(keywords, prevKeywords, onCleanup) => {
// 执行异步任务,并得到关闭异步任务的 timerId
const timerId = asyncPrint(keywords)
// 如果 watch 监听被重复执行了,则会先清除上次未完成的异步任务
onCleanup(() => clearTimeout(timerId))
},
// watch 刚被创建的时候不执行
{ lazy: true }
)
// 把 template 中需要的数据 return 出去
return {
keywords
}
10. LifeCycle Hooks
新版的生命周期函数,可以按需导入到组件中,且只能在 setup()
函数中使用,代码示例如下:
import { onMounted, onUpdated, onUnmounted } from '@vue/composition-api'
const MyComponent = {
setup() {
onMounted(() => {
console.log('mounted!')
})
onUpdated(() => {
console.log('updated!')
})
onUnmounted(() => {
console.log('unmounted!')
})
}
}
下面的列表,是 vue 2.x 的生命周期函数与新版 Composition API 之间的映射关系:
-> usebeforeCreate
setup()
-> usecreated
setup()
beforeMount
->onBeforeMount
mounted
->onMounted
beforeUpdate
->onBeforeUpdate
updated
->onUpdated
beforeDestroy
->onBeforeUnmount
destroyed
->onUnmounted
errorCaptured
->onErrorCaptured
11. provide & inject
provide()
和 inject()
可以实现嵌套组件之间的数据传递。这两个函数只能在 setup()
函数中使用。父级组件中使用 provide()
函数向下传递数据;子级组件中使用 inject()
获取上层传递过来的数据。
11.1 共享普通数据
App.vue
根组件:
<template>
<div id="app">
<h1>App 根组件</h1>
<hr />
<LevelOne />
</div>
</template>
<script>
import LevelOne from './components/LevelOne'
// 1. 按需导入 provide
import { provide } from '@vue/composition-api'
export default {
name: 'app',
setup() {
// 2. App 根组件作为父级组件,通过 provide 函数向子级组件共享数据(不限层级)
// provide('要共享的数据名称', 被共享的数据)
provide('globalColor', 'red')
},
components: {
LevelOne
}
}
</script>
LevelOne.vue
组件:
<template>
<div>
<!-- 4. 通过属性绑定,为标签设置字体颜色 -->
<h3 :style="{color: themeColor}">Level One</h3>
<hr />
<LevelTwo />
</div>
</template>
<script>
import LevelTwo from './LevelTwo'
// 1. 按需导入 inject
import { inject } from '@vue/composition-api'
export default {
setup() {
// 2. 调用 inject 函数时,通过指定的数据名称,获取到父级共享的数据
const themeColor = inject('globalColor')
// 3. 把接收到的共享数据 return 给 Template 使用
return {
themeColor
}
},
components: {
LevelTwo
}
}
</script>
LevelTwo.vue
组件:
<template>
<div>
<!-- 4. 通过属性绑定,为标签设置字体颜色 -->
<h5 :style="{color: themeColor}">Level Two</h5>
</div>
</template>
<script>
// 1. 按需导入 inject
import { inject } from '@vue/composition-api'
export default {
setup() {
// 2. 调用 inject 函数时,通过指定的数据名称,获取到父级共享的数据
const themeColor = inject('globalColor')
// 3. 把接收到的共享数据 return 给 Template 使用
return {
themeColor
}
}
}
</script>
11.2 共享 ref 响应式数据
如下代码实现了点按钮切换主题颜色的功能,主要修改了 App.vue
组件中的代码,LevelOne.vue
和 LevelTwo.vue
中的代码不受任何改变:
<template>
<div id="app">
<h1>App 根组件</h1>
<!-- 点击 App.vue 中的按钮,切换子组件中文字的颜色 -->
<button @click="themeColor='red'">红色</button>
<button @click="themeColor='blue'">蓝色</button>
<button @click="themeColor='orange'">橘黄色</button>
<hr />
<LevelOne />
</div>
</template>
<script>
import LevelOne from './components/LevelOne'
import { provide, ref } from '@vue/composition-api'
export default {
name: 'app',
setup() {
// 定义 ref 响应式数据
const themeColor = ref('red')
// 把 ref 数据通过 provide 提供的子组件使用
provide('globalColor', themeColor)
// setup 中 return 数据供当前组件的 Template 使用
return {
themeColor
}
},
components: {
LevelOne
}
}
</script>
12. template refs
通过 ref()
还可以引用页面上的元素或组件。
12.1 元素的引用
示例代码如下:
<template>
<div>
<h3 ref="h3Ref">TemplateRefOne</h3>
</div>
</template>
<script>
import { ref, onMounted } from '@vue/composition-api'
export default {
setup() {
// 创建一个 DOM 引用
const h3Ref = ref(null)
// 在 DOM 首次加载完毕之后,才能获取到元素的引用
onMounted(() => {
// 为 dom 元素设置字体颜色
// h3Ref.value 是原生DOM对象
h3Ref.value.style.color = 'red'
})
// 把创建的引用 return 出去
return {
h3Ref
}
}
}
</script>
12.2 组件的引用
TemplateRefOne.vue
中的示例代码如下:
<template>
<div>
<h3>TemplateRefOne</h3>
<!-- 4. 点击按钮展示子组件的 count 值 -->
<button @click="showNumber">获取TemplateRefTwo中的count值</button>
<hr />
<!-- 3. 为组件添加 ref 引用 -->
<TemplateRefTwo ref="comRef" />
</div>
</template>
<script>
import { ref } from '@vue/composition-api'
import TemplateRefTwo from './TemplateRefTwo'
export default {
setup() {
// 1. 创建一个组件的 ref 引用
const comRef = ref(null)
// 5. 展示子组件中 count 的值
const showNumber = () => {
console.log(comRef.value.count)
}
// 2. 把创建的引用 return 出去
return {
comRef,
showNumber
}
},
components: {
TemplateRefTwo
}
}
</script>
TemplateRefTwo.vue
中的示例代码:
<template>
<div>
<h5>TemplateRefTwo --- {{count}}</h5>
<!-- 3. 点击按钮,让 count 值自增 +1 -->
<button @click="count+=1">+1</button>
</div>
</template>
<script>
import { ref } from '@vue/composition-api'
export default {
setup() {
// 1. 定义响应式的数据
const count = ref(0)
// 2. 把响应式数据 return 给 Template 使用
return {
count
}
}
}
</script>
13. createComponent
这个函数不是必须的,除非你想要完美结合 TypeScript 提供的类型推断来进行项目的开发。
这个函数仅仅提供了类型推断,方便在结合 TypeScript 书写代码时,能为 setup()
中的 props
提供完整的类型推断。
import { createComponent } from 'vue'
export default createComponent({
props: {
foo: String
},
setup(props) {
props.foo // <- type: string
}
})
5.Vue3.0 生命周期函数
在组件化的框架中,比如Angular、React或Vue,都为组件定义了生命周期这个概念,每个组件实例在被创建时都要经过一系列的初始化过程,例如:需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等。同时,在这个过程中也会运行一些叫做生命周期钩子的函数,它们提供给用户在组件的不同阶段添加自己的代码的机会。
使用过Vue2.x的朋友肯定对它的生命周期钩子很熟悉了,因为在实际的开发过程中我们多多少少会用到他们,比如 created、mounted、destoryed等等。而在Vue3.0中,Vue2.x Options API形式的生命周期钩子函数和新的Composition API都可以使用,来看个示例代码就明白了:
const { onMounted } = Vue
const MyComp = {
// Options API
mounted() {
console.log('>>>>>> mounted 1')
},
setup() {
// Composition API
onMounted(() => {
console.log('++++++ mounted 2')
})
}
}
两种形式的生命周期函数可以共存(当然实际使用的时候最好只选用一种),它们都会被执行。Composition API形式的生命周期函数都是在 setup 方法中被调用注册。
最后,在实际的开发过程中,请注意一下Options API形式的组件生命周期钩子和Composition API之间的实际对应关系:
- beforeCreate -> 请使用 setup()
- created -> 请使用 setup()
- beforeMount -> onBeforeMount
- mounted -> onMounted
- beforeUpdate -> onBeforeUpdate
- updated -> onUpdated
- beforeDestroy -> onBeforeUnmount
- destroyed -> onUnmounted
- errorCaptured -> onErrorCaptured
6.Vue Composition API
最近,Vue官方发布了 Composition API RFC。有关于Vue3.0 Function Base组件相关讨论正如火如荼。虽然Vue3.0还未发布,但是 Vue官方发布了关于 Composition API的官方插件,使广大用户可以在Vue2.x中享受 Function Base 带来的新体验。下面我会在一个简单的demo中介绍Composition API使用方法。
安装
yarn add @vue/compostion-api
等待composition-api包安装完成后,我们在项目入口文件中加入Composition API。
import Vue from "vue"
import CompositionApi from "@vue/compostion-apai"
Vue.use(CompositionApi)
setup
按照官方给出的说法,setup函数是一个新的Vue组件选项,是用于在组件中使用Composition API的入口。
setup函数在组件初始化了props之后,created之前调用,这时候我们才能通过setup来传递props。
ref
ref
是CompositionAPI引入的新概念。作用是使访问响应式的变量不依赖于实例的this
。如果使用了ref
,我们访问响应式的变量时使用.value
而不是从this
中获取。
import {ref} from "@vue/compostion-apai"
export default {
setup() {
const count = ref(0)//count初始值为0,会相应变化
count.value = 10;//设置count值为10,使用.value形式
return {
count//必须将count return 回去
}
}
}
生命周期函数
可以使用导入的onXXX
的形式注册生命周期函数,举个例子:
import {onCreated,onMounted} from "@vue/compostion-apai"
export default {
setup() {
onCreated(()=>{
console.log('created被触发')
})
onMounted(()=>{
console.log('mounted被触发')
})
///...其他类似
}
}
methods
在Composition API中,我们使用普通的函数定义方法,这样可以最大程度的增加复用性。例如:
<template>
<button @click="add">click me!</button>
</template>
<script>
export default {
setup() {
function add() {
console.log('add被触发')
}
return {
add//必须将函数return
}
}
}
</script>
props
定义props
和原来的方式一样,props
会通过参数的形式传入到setup
函数中:
export default {
props:{
name:String
},
setup(props) {
console.log(props.name)
}
}
computed
计算属性可以使用Composition API提供的computed
函数进行定义:
import {computed,ref} from "@vue/compostion-apai"
export default {
setup() {
const a = ref(0)
const b = ref(1);
const total = computed(()=>a.value+b.value)
return {
a,
b,
totla
}
}
}
这样我们就定义号了一个计算属性total
,total.value = a.value + b.value
。
watch
在组件中添加watch
监听我们可以采用Compostion API提供的watch
函数实现:
import {watch,ref} from "@vue/compostion-apai"
export default {
setup() {
const count = ref(100);
watch(()=>count.vlaue,()=>{
console.log('count数值发生变化了')
})
const.value = 200;
return {
count
}
}
}
获取Vue组件实例或者dom节点
在Composition API中使用ref
特性获取组件实例或者dom节点,举个例子说明:
<template>
<div>
<hello-world ref="helloWold"></hello-world>
<button ref="btn"></button>
</div>
</template>
import {ref} from "@vue/composition-api"
export default {
setup() {
const helloWorld = ref(null);//helloworld组件实例
const btn = ref(null);//button dom节点对象
return {
btn,
helloWorld
}
}
}
综合例子
<template>
<div>
<button @click="increment" ref="btn">{{titleCount}}</button>
</div>
</template>
<script>
import {onMounted,computed,ref,watch} from "@vue/composition-api"
export default {
props:{
prefix:String
},
setup(props) {
const btn = ref(null);
const count = ref(0);
const title = ref(`${props.prefix},vue composition api`);
const titleCount = computed(()=>title.value +':'+ count.value)
onMounted(()=>{
alert('mounted')
})
watch(()=>count.value,()=>alert('count改变了:'+count.value))
function increment() {
// eslint-disable-next-line no-console
count.value++;
// eslint-disable-next-line no-console
console.log(btn.value);
}
return {
btn,
increment,
title,
count,
titleCount
}
}
}
</script>
7.CSS中!important 作用
1、这个属性可以让浏览器优选执行这个语句,加上!importanrt可以覆盖父级的样式。具体的效果可以用一个案例演示,首先新建一个html文件,先新建一个外围div,在在里面设置两个子div,给父div设置class属性parent,第二个子div增加import的class属性:
2、然后在上方的style中设置样式,给div设置宽度和高度,并给它背景颜色;给import类设置背景色,并加入!important 属性就会覆盖父容器的背景颜色:
3、最后来到浏览器中,就可以看到第二个div的背景颜色被覆盖了:
CSS中“!important”可以使它之前的样式优先执行,比如说这样:
body {
color : red !important;
}
body {
color : black;
}
颜色color出现了两次,而加上“!important”的“color : red;”总会得到优先执行,浏览器将对另一个“color : black;”视而不见。
之所以会说得复杂,是因为“IE 6.0一直都不支持这个语法,而其他的浏览器都支持。因此可以利用这一点来分别给IE和其他浏览器不同的样式定义”,我认为这只不过是一个小技巧罢了。
8.Normalize.css
Normalize.css是一种CSS reset的替代方案。它在默认的HTML元素样式上提供了跨浏览器的高度一致性。相比于传统的CSS reset,Normalize.css是一种现代的、为HTML5准备的优质替代方案(https://necolas.github.io/normalize.css/7.0.0/normalize.css)
创造normalize.css有下面这几个目的:
保护有用的浏览器默认样式而不是完全去掉它们
一般化的样式:为大部分HTML元素提供
修复浏览器自身的bug并保证各浏览器的一致性
优化CSS可用性:用一些小技巧
解释代码:用注释和详细的文档来
Normalize.css支持包括手机浏览器在内的超多浏览器,同时对HTML5元素、排版、列表、嵌入的内容、表单和表格都进行了一般化。尽管这个项目基于一般化的原则,但我们还是在合适的地方使用了更实用的默认值。
Normalize vs Reset
\1. Normalize.css 保护了有价值的默认值
Reset通过为几乎所有的元素施加默认样式,强行使得元素有相同的视觉效果。相比之下,Normalize.css保持了许多默认的浏览器样式。这就意味着你不用再为所有公共的排版元素重新设置样式。当一个元素在不同的浏览器中有不同的默认值时,Normalize.css会力求让这些样式保持一致并尽可能与现代标准相符合。
2. Normalize.css 修复了浏览器的bug
它修复了常见的桌面端和移动端浏览器的bug。这往往超出了Reset所能做到的范畴。关于这一点,Normalize.css修复的问题包含了HTML5元素的显示设置、预格式化文字的font-size问题、在IE9中SVG的溢出、许多出现在各浏览器和操作系统中的与表单相关的bug。
3、Normalize.css 不会让你的调试工具变的杂乱
使用Reset最让人困扰的地方莫过于在浏览器调试工具中大段大段的继承链,如下图所示。在Normalize.css中就不会有这样的问题,因为在我们的准则中对多选择器的使用时非常谨慎的,我们仅会有目的地对目标元素设置样式。
4、Normalize.css 是模块化的
这个项目已经被拆分为多个相关却又独立的部分,这使得你能够很容易也很清楚地知道哪些元素被设置了特定的值。因此这能让你自己选择性地移除掉某些永远不会用到部分(比如表单的一般化)。
5. Normalize.css 拥有详细的文档
Normalize.css的代码基于详细而全面的跨浏览器研究与测试。这个文件中拥有详细的代码说明并在Github Wiki中有进一步的说明。这意味着你可以找到每一行代码具体完成了什么工作、为什么要写这句代码、浏览器之间的差异,并且你可以更容易地进行自己的测试。
如何使用 normalize.css
首先,安装或从Github下载Normalize.css,接下来有两种主要途径去使用它。
策略一:将normalize.css作为你自己项目的基础CSS,自定义样式值以满足设计师的需求。
策略二:引入normalize.css源码并在此基础上构建,在必要的时候用你自己写的CSS覆盖默认值。
vue框架中如何使用
NPM
npm install --save normalize.css
mianimport 'normalize.css' 如果报错
npm install css-loader style-loader
normalize.css 是什么?
它是css样式初始化的插件。
在实际的开发中,我们经常会将浏览器默认的样式重置,比如如下办法:
- {
margin: 0;
padding: 0;
border:0;
}
通过上述办法可以重置样式,但是太过于简单粗暴,*是通配符,需要把所有的标签都遍历一遍,当网站较大时,样式比较多,这样写就大大的加强了网站运行的负载,会使网站加载的时候需要很长一段时间,因此不建议使用。与此同时,normalize.css就诞生了,它与许多CSS重置不同,保留了有用的默认值,更正了常见浏览器不一致性等错误。
normalize.css 怎么使用?
1、安装
npm install --save normalize.css
2、引入
import ‘normalize.css/normalize.css’
9.vue中监控元素大小变化element-resize-detector
导入npm install element-resize-detector
1.可以浏览器统一导入 如放到index.html
<script src="node_modules/element-resize-detector/dist/element-resize-detector.min.js"></script>
2.也可以在vue中导入
如在
monted(){
var elementResizeDetectorMaker = require("element-resize-detector");//导入
// 创建实例
var erd = elementResizeDetectorMaker();
// 创建实例带参
var erdUltraFast = elementResizeDetectorMaker({
strategy: "scroll", //<- For ultra performance.
callOnAdd: true,
debug: true
});
//监听id为test的元素 大小变化
erd.listenTo(document.getElementById("test"), function(element) {
var width = element.offsetWidth;
var height = element.offsetHeight;
console.log("Size: " + width + "x" + height);
});
}
3.erd实例方法
RemoveListener(element,listener)
从元素中移除侦听器。
4.RemoveAllListener(element)
从元素中移除所有侦听器,但不完全删除检测器。如果以后可能会添加侦听器,并且不希望检测器再次初始化,请使用此函数。
5.uninstall(element)
完全删除检测器和所有侦听器。
10.element-ui弹出层置于遮罩层下面问题
有时页面结构复杂,多个嵌套MessageBox之类的情况时,MessageBox 弹框会出现置于遮罩层下面的问题,需要添加
:modal-append-to-body="false"属性。
注:该属性可以将弹出层的遮罩层在body内生成。
代码实例
11.在项目中,遇到vue父子组件的传参问题,父组件传参给子组件,子组件在created和mounted等生命周期中获取不到,也无法使用父组件传递过来的参数。
在项目中,遇到vue父子组件的传参问题,父组件传参给子组件,子组件在created和mounted等生命周期中获取不到,也无法使用父组件传递过来的参数。
父组件传参,一般分为两种情况:
1、父组中的原始数据 (即定义在父组件data中的原始数据),传输给子组件使用,子组件在生命周期中是可以获取并使用的。
2、父组件传给子组件的参数,是从接口中获取到的, 可能遇到的问题就是,如果在组件的created或mounted生命周期中定义要给方法,在子组件渲染时就获取父组件的传值,并进行新数据的获取并进行页面渲染,但此时父组件请求的数据可能还没有完全返回,子组件就开始使用此数据,该数据自然不存在,打印在控制台中的父组件穿给子组件的参数为undefined,因此就会出现父组件传参不及时,子组件使用数据较早,造成数据无法使用。
解决改问题的方法:
1、在子组件的created或者mounted等较早执行的生命周期中使用setTimeout定时器,来延缓执行生命周期中的函数, 使父组件从接口中获取的参数,有充分的时间传输,在子组件使用时,等待父组件的参数到来再执行,就不会出现拿不到父组件的传参问题了。
//----------------------------子组件--------------------------------
export default {
props:['fatherData'],
data(){
return {
}
},
created(){
this.setTime() // 延时1.5秒调用方法,等待父组件的传参返回
},
methods:{
setTime(){ // 定时器,延时调用方法
let win = this
setTimeout(function(){
win.getData() // 获取数据
},1500)
},
getData(){
// 使用父组件传过来的数据,进行新的请求
this.$api.getData(this.fatherData).then(res=>{
console.log(res)
}
}
}
}
// 该方法虽然可以解决上述问题,但延时调用影响了页面的响应速度,
// 不是一个很好的解决办法(不推荐)
该方法虽然可以解决上述问题,但延时调用影响了页面的响应速度,
不是一个很好的解决办法(不推荐)
2、另一种方法为watch侦听:
使用vue的监听方法,监听父组件的传参,一旦侦听到数据返回,便立即调用子组件的方法进行数据获取,相对于第一种方法,更加灵活和快速。
12.Axios 各种请求方式传递参数格式
- axios.request(config)
- axios.get(url[, config])
- axios.delete(url[, config])
- axios.head(url[, config])
- axios.post(url[, data[, config]])
- axios.put(url[, data[, config]])
- axios.patch(url[, data[, config]])
axios.request(config)
//原始的Axios请求方式
axios({
method: 'post',
url: '/user/12345',
data: {
firstName: 'Fred',
lastName: 'Flintstone'
},
timeout: 1000,
...//其他相关配置
});
axios.get(url[, config])
axios.get('demo/url', {
params: {
id: 123,
name: 'Henry',
},
timeout: 1000,
...//其他相关配置
})
axios.delete(url[, config])
//如果服务端将参数作为java对象来封装接受
axios.delete('demo/url', {
data: {
id: 123,
name: 'Henry',
},
timeout: 1000,
...//其他相关配置
})
//如果服务端将参数作为url参数来接受,则请求的url为:www.demo/url?a=1&b=2形式
axios.delete('demo/url', {
params: {
id: 123,
name: 'Henry',
},
timeout: 1000,
...//其他相关配置
})
axios.post(url[, data[, config]])
axios.post('demo/url', {
id: 123,
name: 'Henry',
},{
timeout: 1000,
...//其他相关配置
})
axios.put(url[, data[, config]])
axios.put('demo/url', {
id: 123,
name: 'Henry',
},{
timeout: 1000,
...//其他相关配置
})
axios.patch(url[, data[, config]])
axios.patch('demo/url', {
id: 123,
name: 'Henry',
},{
timeout: 1000,
...//其他相关配置
})
总结: 通过以上案例可以看出,get
delete
请求方式中,第一个参数为请求的url地址,第二个参数为请求的一些配置项,需要传递给后端的参数包含在配置项的data或者params属性中,而post
put
patch
请求则第一个参数为url地址,第二个参数是需要入参的json数据,第三个参数是入参以外的其他配置项。
更多推荐
所有评论(0)