本文目录
- 1.node-sass安装失败
- 2.动态引入和绑定背景图片
- 3.写在data中的数据无法将改变动态渲染到页面上
-4.vue中定义全局变量的方法 - 5.beforeRouteEnter的书写位置
- 6.解决vue路由警告问题
- 7.让VScode保存时自动匹配ESlint规则
- 8.封装公用方法(以格式化数据为例)
- 9.修改第三方组件样式
- 10.监听组件生命周期
- 11.路由分区以及动态添加路由
- 12.v-for循环拿到的item值动态渲染文字内容
- 13.路由跳转,页面不刷新
- 14.Vue部署与部署后刷新页面404
- 15.列表进入详情页的传参问题
- 16.组件的事件拿到额外的参数
- 17.子组件改变父组件传递过来的数据
- 18.父组件调用子组件的方法
- 19.改变数组
1.node-sass安装失败
使用别人的一个模板项目的时候,在npm install的时候报错提示node-sass啊没装失败,出现原因是npm 安装 node-sass 依赖时,会从 github.com 上下载 .node 文件。由于国内网络环境的问题,这个下载时间可能会很长,甚至导致超时失败。
解决方法是首先把node_modules文件夹删除,然后运行指令npm i node-sass --sass_binary_site=https://npm.taobao.org/mirrors/node-sass/
先单独安装node-sass,再启用npm install安装其他依赖。
2.动态引入和绑定背景图片
vue中动态改变backgroundimage的写法
:style="{backgroundImage:'url(\''+themeBg+'\')'}"
动态的在data中引入路径的写法
themeBg: require("../../assets/images/e_center.png"),
这个themeBg也可以是在缓存中获取的
themeBg: sessionStorage.getItem("themeBg")
3.写在data中的数据无法将改变动态渲染到页面上
场景:数据确定会正常改变,但是变化不会自动触发页面上的显示,但是功能是正常的。
可能原因1:就算数据是在data存在了,但是赋值的时候把某个属性给丢失了,vue也就失去了对其的检测能力。也就是说,在data中存在的数据以及对象属性需要一直存在,否则vue就会失去对其变化的监控。
可能原因2:vue中在data里定义的变量,在ajax获取数据后进行改变,但是变量的改变无法动态渲染到视图中,折腾了很长时间发现是回调函数中的this的指向发生了改变,回调函数应该使用箭头函数来保持this指向的不变。
可能原因3:computed里面数据的改变不会自动触发视图的更新,写在data里的对象,需要新增加flag用来控制视图元素的显示和隐藏,需要进行动态的添加,如果flag本来就定义在data中,则可以直接赋值。
this.$set(this.regionOptions[i].options[si], 'flag', false);
如果像下面这样添加,则无法和视图进行实时动态渲染的绑定
this.regionOptions[i].options[si].flag = false;
4.vue中定义全局变量的方法
在mainjs中进行定义并将其挂载到vue实例中
var baseUrl = "http://110.50.111:8090";
Vue.prototype.$baseUrl = baseUrl
组件内进行使用
methods: {
asd() {
console.log(this.$baseUrl);
}
},
mounted() {
this.asd()
}
全局引用js直接在main.js中引用就可以,import remtools from './assets/js/setrem'
但是这个js只有在项目第一次加载的时候执行一次,切换路由的时候并不触发这个js
5.beforeRouteEnter的书写位置
beforeRouteEnter必须放在页面文件中,组件是监听不到路由的
beforeRouteEnter (to, from, next) {
if (from.path === '/detail') {
next((vm) => {
// 更新列表数据方法
vm.updateData()
})
}
next()
},
6.解决vue路由警告问题
下面这三行是解决vue项目路由出现message: "Navigating to current location (XXX) is not allowed"的方法,把代码放置到router文件夹的index.js文件中即可
const routerPush = VueRouter.prototype.push
VueRouter.prototype.push = function push(location) {
return routerPush.call(this, location).catch(error=> error)
}
7.让VScode保存时自动匹配ESlint规则
首先需要找到VScode配置文件setting.json
- ctrl+shift+p
2.输入setting
3.选择 首选项:打开设置(json)即可.
这个文件存放的是一个JSON格式的数据,在{}中的最后增加如下代码
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
}
这样的话,在修改代码只需要ctrl+s保存代码,代码规则就会自动按照ESlint的配置规则进行调整。
8.封装公用方法(以格式化数据为例)
我们封装组件在多个地方用到的不同的接口数据,这些请求来的数据有可能会名称不同,所以我们需要封装一个方法,专门用来格式化我们请求来的数据,从而能够在组件中得到统一的调用。
在src文件夹中新建一个common文件夹,然后再新建一个js文件夹,然后再新建一个util.js文件,这个文件是用来存放我们自己写的一些工具方法的。
export function formatSongDetail(val){
const newVal = []
val.forEach((item) =>{
const detail = {}
detail.id = item.id
detail.al = Object.assign({}, item.al || item.album || item.song.album)
//Object.assign方法的第一个参数是目标对象,后面的参数都是源对象。
//注意,如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性。
detail.ar = [].concat(item.ar || item.artists || item.song.artists)
detail.name = item.name
newVal.push(detail)
})
return newVal
}
接下来,在要格式化数据的组件中先引入这个方法
``import { formatSongDetail } from "../../common/js/util";`
然后可以在data中新建一个formatData,用来存放我们格式化之后的数据
data() {
return {
formatData: []
};
}
在ajax获取到数据的时候,调用formatSongDetail方法,然后将数据格式化之后的数据存储到formatData中
this.formatData = formatSongDetail(data.result);
9.修改第三方组件样式
在使用vue构建项目的时候,引用了第三方组件库,只需要在当前页面修改第三方组件库的样式以做到不污染全局样式。通过在样式标签上使用scoped达到样式只制作用到本页面,但是此时再修改组件样式不起作用。
解决方法:通过 >>> 穿透scoped
父组件中修改子组件的样式使用样式穿透
.parent >>> .child
父组件的 class或ID >>>(三个箭头表示样式穿透) 子组件的class或ID
有些Sass 、Less之类的预处理器无法正确解析 >>>。可以使用 /deep/操作符( >>> 的别名)
10.监听组件生命周期
通常我们监听组件生命周期会使用 $emit ,父组件接收事件来进行通知
子组件代码:
export default {
mounted() {
this.$emit('listenMounted')
}
}
父组件代码:
其实还有一种简洁的方法,使用 @hook 即可监听组件生命周期,组件内无需做任何改变。同样的, created 、 updated 等也可以使用此方法。
12.v-for循环拿到的item值动态渲染文字内容
{{item.status === 1 ? '待确认' : item.status === 2 ? '已拒绝' :item.status === 3 ? '已绑定' :item.status === 100 ? '已过期' : '' }}
总结:{{}}中是可以写三元表达式的。
13.路由跳转,页面不刷新
假设我们在写一个博客网站,需求是从/post-page/a,跳转到/post-page/b。然后我们惊人的发现,页面跳转后数据竟然没更新?!原因是vue-router"智能地"发现这是同一个组件,然后它就决定要复用这个组件,所以你在created函数里写的方法压根就没执行。通常的解决方案是监听$route的变化来初始化数据,如下:
data() {
return {
loading: false,
error: null,
post: null
}
},
watch: {
'$route': {
handler: 'resetData',
immediate: true
}
},
methods: {
resetData() {
this.loading = false
this.error = null
this.post = null
this.getPost(this.$route.params.id)
},
getPost(id){
}
}
bug是解决了,可每次这么写也太不优雅了吧。
其实可以借助router-view添加一个unique的key,这样即使是公用组件,只要url变化了,就一定会重新创建这个组件。(虽然损失了一丢丢性能,但避免了无限的bug)。
同时,注意我将key直接设置为路由的完整路径,一举两得。
14.Vue部署与部署后刷新页面404
我们先来看一下打包出来的的dist文件
可以看到dist下只有一个 index.html 文件及一些静态资源,这个是因为Vue是单页应用(SPA),只有一个index.html作为入口文件,其它的路由都是通过JS来进行跳转
我们只需要将这个目录上传至目标服务器即可
让web容器跑起来,以nginx为例
server {
listen 80;
server_name website.com;
location / {
index /data/dist/index.html;
}
}
配置完成记得重启nginx
// 检查配置是否正确
nginx -t
// 平滑重启
nginx -s reload
操作完后就可以在浏览器输入域名进行访问了
当然上面只是提到最简单也是最直接的一种布署方式
什么自动化,镜像,容器,流水线布署,本质也是将这套逻辑抽象,隔离,用程序来代替重复性的劳动。
接着我们再回头来看下web容器的 nginx 配置
server {
// 监听80端口
listen 80;
// 定义你的站点名称
server_name website.com;
// 根据请求 URI 设置配置
location / {
// 站点根目录,这里为 vue 构建出来的 dist 目录
root /www/dist;
// 站点初始页为index.html 或 index.htm
index index.html;
}
}
我们现在可以根据 nginx 配置得出,当我们在地址栏输入 website.com 时,这时会打开我们 dist 目录下的 index.html 文件,然后我们在跳转路由进入到 website.com/login
关键在这里,当我们在 website.com/login 页执行刷新操作,nginx location 是没有相关配置的,所以就会出现 404 的情况
为什么hash模式下没有问题
router hash 模式我们都知道是用符号#表示的,如 website.com/#/login, hash 的值为 #/login
它的特点在于:hash 虽然出现在 URL 中,但不会被包括在 HTTP 请求中,对服务端完全没有影响,因此改变 hash 不会重新加载页面
hash 模式下,仅 hash 符号之前的内容会被包含在请求中,如 website.com/#/login 只有 website.com 会被包含在请求中 ,因此对于服务端来说,即使没有配置location,也不会返回404错误
产生问题的本质是因为我们的路由是通过JS来执行视图切换的,
当我们进入到子路由时刷新页面,web容器没有相对应的页面此时会出现404
所以我们只需要配置将任意页面都重定向到 index.html,把路由交由前端处理
location / {
index /data/dist/index.html;
try_files $uri $uri/ /index.html;
}
这里有一个小细节,如果出现真的 404 页面了呢?比如 website.com/notfound
因为这么做以后,你的服务器就不再返回 404 错误页面,因为对于所有路径都会返回 index.html 文件。为了避免这种情况,应该在 Vue 应用里面覆盖所有的路由情况,然后在给出一个 404 页面
const router = new VueRouter({
mode: 'history',
routes: [
{ path: '*', component: NotFoundComponent }
]
})
15.列表进入详情页的传参问题
例如商品列表页面前往商品详情页面,需要传一个商品id;
前往detail页面
c页面的路径为http://localhost:8080/#/detail?id=1,可以看到传了一个参数id=1,并且就算刷新页面id也还会存在。此时在c页面可以通过id来获取对应的详情数据,获取id的方式是this.$route.query.id
vue传参方式有:query、params+动态路由传参。
说下两者的区别:
1.query通过path切换路由,params通过name切换路由
// query通过path切换路由
前往Detail页面
// params通过name切换路由
前往Detail页面
2.query通过this.route.params来接收参数。
// query通过this.$route.query接收参数
created () {
const id = this.$route.query.id;
}
// params通过this.$route.params来接收参数
created () {
const id = this.$route.params.id;
}
3.query传参的url展现方式:/detail?id=1&user=123&identity=1&更多参数
params+动态路由的url方式:/detail/123
4.params动态路由传参,一定要在路由中定义参数,然后在路由跳转的时候必须要加上参数,否则就是空白页面:
{
path: '/detail/:id',
name: 'Detail',
component: Detail
}
注意,params传参时,如果没有在路由中定义参数,也是可以传过去的,同时也能接收到,但是一旦刷新页面,这个参数就不存在了。这对于需要依赖参数进行某些操作的行为是行不通的,因为你总不可能要求用户不能刷新页面吧。例如
{
path: 'detail/:id',
name: 'Detail',
components: Detail
}
// template中的路由传参,
// 传了一个id参数和一个token参数
// id是在路由中已经定义的参数,而token没有定义
前往Detail页面
// 在详情页接收
created () {
// 以下都可以正常获取到
// 但是页面刷新后,id依然可以获取,而token此时就不存在了
const id = this.$route.params.id;
const token = this.$route.params.token;
}
16.组件的事件拿到额外的参数
本来的写法@search-keyup=keyupSearchItem"
自定义事件keyupSearchItem拿到默认的参数
keyupSearchItem (e){}
优化后的写法@search-keyup="argument => keyupSearchItem(index,argument)",自定义事件拿到额外的自定义参数
keyupSearchItem (index,e){}
index和argument的顺序更换也没问题
17.子组件改变父组件传递过来的数据
引用的组件
会触发一些页面传入的数据
props: {
show:{
type:Boolean,
default:false
}
},
设置computed的set和get完美解决
computed: {
showFlag:{
get() {
return this.show
},
set(v) {
this.$emit('closeHelpContainer')
}
}
},
如果只是下面这样
computed: {
showFlag (){
return this.show
}
},
则当关闭组件的时候,页面会报错
Computed property "showFlag" was assigned to but it has no setter.
18.父组件调用子组件的方法
this.$refs.Category.getFormData();
给子组件添加上ref="Category",上面的代码就直接可以调用到子组件的getFormData方法,并获取到其中的返回值。
19.改变数组
vue2中定义一个数组demoArr: [1,2,3,4,5],然后渲染到页面上,在methods中通过this.demoArr = [10,20,30,40,50]改变demoArr可以动态改变到页面上吗?
可以
this.set(object, key, value)