实际项目中的编码技巧总结(Vue篇)

本文目录

  • 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

  1. 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

<style scoped>
    外层 >>> 第三方组件类名{
        样式
    }
</style>

有些Sass 、Less之类的预处理器无法正确解析 >>>。可以使用 /deep/操作符( >>> 的别名)

<style lang="sass" scoped>
/deep/  第三方组件类名 {
      样式
  }
</style>

10.监听组件生命周期

通常我们监听组件生命周期会使用 $emit ,父组件接收事件来进行通知
子组件代码:

export default {
    mounted() {
        this.$emit('listenMounted')
    }
}

父组件代码:

<template>
    <div>
        <List @listenMounted="listenMounted" />
    </div>
</template>

其实还有一种简洁的方法,使用 @hook 即可监听组件生命周期,组件内无需做任何改变。同样的, created 、 updated 等也可以使用此方法。

<template>
    <List @hook:mounted="listenMounted" />
</template>

12.v-for循环拿到的item值动态渲染文字内容

<div class="user_item" v-for="(item, index) in listData" :key="item.workid">
    <div>
        {{item.status === 1 ? '待确认' : item.status === 2 ? '已拒绝' :item.status === 3 ? '已绑定' :item.status === 100 ? '已过期' : '' }}
    </div>
</div>

总结:{{}}中是可以写三元表达式的。

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直接设置为路由的完整路径,一举两得。

<router-view :key="$route.fullpath"></router-view>

14.Vue部署与部署后刷新页面404

我们先来看一下打包出来的的dist文件


dist文件夹.png

可以看到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;

<router-link :to="{path: 'detail', query: {id: 1}}">前往detail页面</router-link>

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切换路由
<router-link :to="{path: 'Detail', query: { id: 1 }}">前往Detail页面</router-link>
// params通过name切换路由
<router-link :to="{name: 'Detail', params: { id: 1 }}">前往Detail页面</router-link>

2.query通过this.route.query来接收参数,params通过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没有定义
<router-link :to="{name: 'Detail', params: { id: 1, token: '123456' }}">前往Detail页面</router-link>

// 在详情页接收
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.子组件改变父组件传递过来的数据

引用的组件

<mp-dialog class="page_module_dialog_batch_store" title="配置助力榜" v-model="showFlag" :width="625">

会触发一些页面传入的数据

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(this.demoArr,[10,20,30,40,50])这样会报错吗 不会报错,但也不起作用 vue2中改变数组项和对象属性的正确方法:this.set(object, key, value)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,527评论 5 470
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,314评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,535评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,006评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,961评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,220评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,664评论 3 392
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,351评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,481评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,397评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,443评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,123评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,713评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,801评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,010评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,494评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,075评论 2 341

推荐阅读更多精彩内容

  • Vue学习总结(Vue基础,VueCli3,VueRouter,Vuex) 目录 vue基础知识(1-13)vue...
    Allenem阅读 4,144评论 0 22
  • vue是什么? vue是构建数据驱动的web界面的渐进式框架。Vue.js 的目标是通过尽可能简单的 API 实现...
    九四年的风阅读 8,693评论 2 131
  • Vue 双向绑定原理 mvvm 双向绑定,采用数据劫持结合发布者-订阅者模式的方式,通过 Object.defin...
    柠檬与断章阅读 848评论 0 3
  • 第一个 vue-router 路由 路由,其实就是指向的意思,当我点击页面上的home按钮时,页面中就要显示hom...
    索伦x阅读 2,432评论 0 3
  • 卵磷脂的神奇功效! 卵磷脂或磷脂酰胆碱同胆固醇一样,都是由肝脏不断地产生,并随同胆汁进入肠内,然后被血液所吸收。它...
    知识改变生活阅读 319评论 0 0