vue 相关

1.vue v-for 循环一个数组,key值报错,但是数据是正常显示的

报错:

v-for使用key,需要在key前加上:key;
srcList是个数组,key值绑定不能是数据类型Object的item,应该绑定item对象下一个属性,这个属性不能重复出现,否则依旧会出现key值报错;你这里可以改成v-for="(item,index) in srcList" :key="index",index对象数组里的索引,不会重复出现,也就不会报错

 

2.计算属性 和 watch 的区别

计算属性是自动监听依赖值的变化,从而动态返回内容,监听是一个过程,在监听的值变化时,可以触发一个回调,并做一些事情

所以区别来源于用法,只是需要动态值,那就用计算属性需要知道值的改变后执行业务逻辑,才用 watch,用反或混用虽然可行,但都是不正确的用法

watch 用法: 例如有请求需要再也没初始化的时候就执行一次,然后监听他的变化,很多人这么写:

created(){
  this.fetchPostList()
},
watch: {
  searchInputValue(){
    this.fetchPostList()
  }
}

上面这种写法,我们完全可以如下写:

watch: {
  searchInputValue:{
    handler: 'fetchPostList',
immediate:
true } }

immediate:true代表如果在 wacth 里声明了之后,就会立即先去执行里面的handler方法,如果为 false就跟我们以前的效果一样,不会在绑定的时候就执行。

 

3.keep-alive

简单来说,就是把一个组件的编译缓存起来

 

4.router 与 route 的区别

$route对象表示当前的路由信息,包含了当前 URL 解析得到的信息。包含当前的路径,参数,query对象等。

 // 1.$route.path
      字符串,对应当前路由的路径,总是解析为绝对路径,如 "/foo/bar"// 2.$route.params
      一个 key/value 对象,包含了 动态片段 和 全匹配片段,
      如果没有路由参数,就是一个空对象。
 // 3.$route.query
      一个 key/value 对象,表示 URL 查询参数。
      例如,对于路径 /foo?user=1,则有 $route.query.user == 1,
      如果没有查询参数,则是个空对象。
 // 4.$route.hash
      当前路由的 hash 值 (不带 #) ,如果没有 hash 值,则为空字符串。锚点
 // 5.$route.fullPath
      完成解析后的 URL,包含查询参数和 hash 的完整路径。
 // 6.$route.matched**
      数组,包含当前匹配的路径中所包含的所有片段所对应的配置参数对象。
 // 7.$route.name    当前路径名字**
 // 8.$route.meta  路由元信息

$router对象是全局路由的实例,是router构造方法的实例。

路由实例方法:

1. $router.push()

// 字符串
      this.$router.push('home')
// 对象
      this.$router.push({ path: 'home' })
// 命名的路由
      this.$router.push({ name: 'user', params: { userId: 123 }})
// 带查询参数,变成 /register?plan=123
      this.$router.push({ path: 'register', query: { plan: '123' }})


// push方法其实和<router-link :to="...">是等同的。
// 注意:push方法的跳转会向 history 栈添加一个新的记录,当我们点击浏览器的返回按钮时可以看到之前的页面。

2. $router.go()

// 页面路由跳转 前进或者后退
this.$router.go(-1) // 后退

3. $router.replace()

//push方法会向 history 栈添加一个新的记录,而replace方法是替换当前的页面,不会向 history 栈添加一个新的记录

// 一般使用replace来做404页面
this.$router.replace('/')

// 配置路由时path有时候会加 '/' 有时候不加,以'/'开头的会被当作根路径,就不会一直嵌套之前的路径。

 

5.vue base64编码

// 项目根目录下安装
npm install --save js-base64

// 项目文件中引入
let Base64 = require('js-base64').Base64

// base64编码
Base64.encode('dankogai');  // ZGFua29nYWk=
// base64解码
Base64.decode('5bCP6aO85by-');  // 小飼弾

// base64加密后的内容,如果放到 url中传输,就会出现空格问题,即经过加密的字符串中如果有‘+’号,就会变成空格
encodeURIComponent(Base64.encode('dankogai'))

 

6.vue 实现消息的无缝滚动效果

<template>
<div id="box" @mouseover="pause" @mouseout="goon">
  <ul id="con1" ref="con1" :class="{anim:animate==true}">
    <li v-for='item in items'>{{item.name}}</li>
  </ul>
</div>
</template>

<script>
 
 export default {
data() {
 return {
   animate:false,
    timer: null,
   items:[  //消息列表对应的数组
     {name:"马云"},
     {name:"雷军"},
     {name:"王勤"}
   ]
 }
},
created(){
  setInterval(this.scroll,1000) // 在钩子函数中调用我在method 里面写的scroll()方法,注意此处不要忘记加this,我在这个位置掉了好几次坑,都是因为忘记写this。
},
methods: {
  play () {
    this.timer = setInterval(this.scroll, 2000)
  },
    pause () {
      clearInterval(this.timer)
    },
    goon () {
      this.timer = setInterval(this.scroll, this.val.scrollSpeed *     1000)
    },
  scroll(){
    let con1 = this.$refs.con1;
    con1.style.marginTop='-30px';
    this.animate=!this.animate;
    var that = this; // 在异步函数中会出现this的偏移问题,此处一定要先保存好this的指向
    setTimeout(function(){
        that.items.push(that.items[0]);
        that.items.shift();
        con1.style.marginTop='0px';
        that.animate=!that.animate;  // 这个地方如果不把animate 取反会出现消息回滚的现象,此时把ul 元素的过渡属性取消掉就可以完美实现无缝滚动的效果了
    },500)
  }
}
}
</script>
 
<style>
 
*{
  margin: 0 ;
  padding: 0;
}
#box{
  width: 300px;
  height: 32px;
  line-height: 30px;
  overflow: hidden;
  padding-left: 30px;
  border: 1px solid black;
  transition: all 0.5s;
}
.anim{
  transition: all 0.5s;
}
#con1 li{
  list-style: none;
  line-height: 30px;
  height: 30px;
}
</style>

 

7.vue 项目结构启动原理

vue调用顺序: index.html → main.js → app.vue → index.js → components/组件

一般项目创建好后会有三个文件:index.html、main.js、app.vue

1、index.html :所有vue文件都是单页面形式开发,所有vue组件都是通过index.html进行渲染加载。

 

 

2、main.js:相当于

java的入口函数,控制初次启动vue项目要加载的组件

import Vue from 'vue' 引入vue

import App from './App' 引入App.vue文件

import router from './router' 引入一段路由配置

Vue.use(C)全局方法定义为C

el:'#app'这个和index.html中的app组件挂钩。官网解释为:模板将会替换挂载的元素。

watch:用来监听路由的变换,可以用来定义页面切换时的过渡效果。

 

 

3、App.vue默认为一个根组件

export 中的name属性组件名字

created:生命周期函数

 

 

4、index.js文件

引入组件的代码

routes定义时,path为你以后页面间路由跳转的路径

name为import进来的名字

component也为这个名字

 

 

其他文件:

-build

-build.js 生产环境构建脚本

-utils.js 构建相关工具方法

-webpack.base.conf.js webpack基础配置

-webpack.dev.conf.js webpack开发环境配置

-webpack.prod.conf.js 生产环境配置

-confg 项目配置

--dev.env.js 开发环境变量

--index.js 项目配置文件

--prod.env.js 生产环境变量

--test.env.js 测试环境变量

-package.json npm包配置文件,里面定义了项目的npm脚本,依赖包等信息

-src 源码目录

--main.js 入口js文件

--app.vue 根组件

--components 公共组件目录

--title.vue


————————————————
版权声明:本文为CSDN博主「No Silver Bullet」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/sunhuaqiang1/article/details/85099769

 

8.vue 生命周期相关

生命周期:Vue 实例从开始创建、初始化数据、编译模板、挂载Dom→渲染、更新→渲染、卸载等一系列过程,我们称这是 Vue 的生命周期,各个阶段有相对应的事件钩子

 

 

 

 

 

注意:

  1. created阶段的ajax请求与mounted请求的区别:前者页面视图未出现,如果请求信息过多,页面会长时间处于白屏状态

  2. mounted 不会承诺所有的子组件也都一起被挂载。如果你希望等到整个视图都渲染完毕,可以用 vm.$nextTick

vue2.0之后主动调用$destroy()不会移除dom节点,作者不推荐直接destroy这种做法,如果实在需要这样用可以在这个生命周期钩子中手动移除dom节点

 

单个组件的生命周期

  1. 初始化组件时,仅执行了beforeCreate/Created/beforeMount/mounted四个钩子函数

  2. 当改变data中定义的变量(响应式变量)时,会执行beforeUpdate/updated钩子函数

  3. 当切换组件(当前组件未缓存)时,会执行beforeDestory/destroyed钩子函数

  4. 初始化和销毁时的生命钩子函数均只会执行一次,beforeUpdate/updated可多次执行

父子组件的生命周期

//父组件
<script>
import Child from './Child';
export default {
  components: {
    Child
  },
  beforeCreate() {
    console.log('parent before create');
  },
  created() {
    console.log('parent created');
  },
  beforeMount() {
    console.log('parent before mount');
  },
  mounted() {
    console.log('parent mounted')
  },
  render(h) {
    console.log('parent render');
    return (
      <div>
        <h1>Vue中父子组件的挂载顺序</h1>
        <h1>父亲</h1>
        <Child/>
      </div>
    )
  },
}
</script>

// 子组件
<script>
export default {
  beforeCreate() {
    console.log('child before create');
  },
  created() {
    console.log('child created');
  },
  beforeMount() {
    console.log('child before mount');
  },
  mounted() {
    console.log('child mounted')
  },
  render(h) {
    console.log('child render');
    return (
      <div>
        <h1>Vue中父子组件的挂载顺序</h1>
        <h1>孩子</h1>
      </div>
    )
  },
}
</script>

父子组件中使用render函数代替<template>,打印输出结果

 

 父组件先初始化 -> 父组件渲染完毕 -> 子组件开始初始化 -> 子组件挂载完毕 -> 父组件挂载完毕

  1. 仅当子组件完成挂载后,父组件才会挂载

  2. 当子组件完成挂载后,父组件会主动执行一次beforeUpdate/updated钩子函数(仅首次)

  3. 父子组件在data变化中是分别监控的,但是在更新props中的数据是关联的(可实践)

  4. 销毁父组件时,先将子组件销毁后才会销毁父组件

兄弟组件的生命周期

  1. 组件的初始化(mounted之前)分开进行,挂载是从上到下依次进行

  2. 当没有数据关联时,兄弟组件之间的更新和销毁是互不关联的

宏mixin的生命周期

  1. mixin中的生命周期与引入该组件的生命周期是仅仅关联的,且mixin的生命周期优先执行

 

9. 怎样监听vuex中的数据变化

将vuex中的数据映射成组件中的计算属性

import { mayState } from 'vuex';
.
.
.
computed: {
  ...mapState([ 'dataName' ])  
}

 

10. 自定义组件的v-model

// 父组件
<template>
  <div class="login">
   <BaseInput :value="message" @input="message = $event"/> 
  <p>文字: {{message}}</p>
  <hr/>
  <BaseCheckbox style="width:40px;height:40px;" :checked="checked" @change="checked = $event"></BaseCheckbox>
  <p>是否选中: {{checked}}</p> </div> </template> <script>

import BaseInput from "./baseInput" import BaseCheckbox from './baseCheckbox' export default { components: {
  BaseInput, BaseCheckbox }, data() {
return {
    message: 'Hello 输入框', checked:
true, } } }; </script>
// 子组件baseCheckbox
<template>
  <div>
    <input type="checkbox" :checked="checked" @change="handleChange" />
  </div>
</template>

<script>
export default {
  model: {
    prop: 'checked',
    event: 'change'
  },
  props: ['checked'],
  methods: {
    handleChange(e) {
      this.$emit('change', e.target.checked);
    }
  }
};
</script>
// 子组件baseInput
<template>
  <div>
    <input type="text" :value="value" @input="handleInput" />
  </div>
</template>

<script>
export default {
  props: ['value'],
  methods: {
    handleInput(e) {
      this.$emit('input', e.target.value);
    }
  }
};
</script>

 

11. Vue异步组件

在项目当中有些组件不想马上加载,如点击按钮之后再加载组件,可以使用异步组件

<template>
  <div>
    <h1>vue异步组件的使用</h1>
    <button @click="handleClick">点击加载组件</button>
    <div v-if="show">
      <List />
    </div>
  </div>
</template>

<script>
export default {
  components: {
    // 使用异步组件,在需要的时候发送ajax请求,下载对应组件的代码
    // List: ()=> import('./list')
    // 为了便于查看,在控制台中设置文件名称为 list
    List: ()=> import(/* webpackChunkName: list */'./baseCheckbox')
  },
  data() {
    return {
      show: false
    }
  },
  methods: {
    handleClick() {
      this.show = !this.show;
    }
  }
}
</script>

或者使用异步组件工厂函数的形式,设置加载属性,如加载时间,延时时间,加载失败后组件等等

<template>  
 <div>
  <h1>vue异步组件的使用</h1> <button @click="handleClick">点击加载组件</button> <div v-if="show"> <AsyncList/> </div> </div> </template> <script> import LoadingComponent from './LoadingComponent';
import ErrorComponent from './ErrorComponent';
const AsyncList = () => {
  return {
    component: import('./list'),
    loading: LoadingComponent,
    error: ErrorComponent,
    delay: 200,
    timeout: 3000
  }
} export
default { components: { AsyncList }, data() { return { show: false } }, methods: { handleClick() { this.show = !this.show; } } } </script>

 

12. $attr/$listeners

最外层和最内层需要进行隔一代传参的时候

 

 

 使用B来做中转站,当A组件需要把信息传给C组件时,B接受A组件的信息,然后利用属性传给C组件,这是一种解决方案,但是如果嵌套的组件过多,会导致代码繁琐,代码维护比较困难;如果C中状态的改变需要传递给A, 使用事件系统一级级往上传递 。

 

// 父组件demo代码如下
<template>
   <div>
     <child-dom
      :foo="foo"
      :coo="foo"
     >
     </child-dom>
   </div>
</template>
<script>
   import childDom from "./ChildDom.vue";
   export default {
     data() {
        return {
          foo:"Hello, world",
          coo:"Hello,rui"
        }
     },
     components:{childDom},
   }
</script>


// 子组件child-dom代码如下
<template>
   <div>
      <p>foo:{{foo}}</p>
   </div>
</template>
<script>
export default {
 name:'child-dom'
 props:["foo"]
}
</script>

当显示父组件时,查看Dom结构,结构如下:

$attrs:

包含了父作用域中不被props接收拿到的 (class 和 style 除外)。当一个组件没有声明任何 props 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过 v-bind=”$attrs” 传入内部组件——在创建更高层次的组件时非常有用。
 
inheritAttrs:
默认情况下父作用域的不被认作 props 的特性绑定 (attribute bindings) 将会“回退”且作为普通的 HTML 特性应用在子组件的根元素上。当撰写包裹一个目标元素或另一个组件的组件时,这可能不会总是符合预期行为。通过设置 inheritAttrs 到 false,这些默认行为将会被去掉。而通过 (同样是 2.4 新增的) 实例属性 $attrs 可以让这些特性生效,且可以通过 v-bind 显性的绑定到非根元素上。如:
// 修改子组件代码如下
<template>
   <div>
      <p>foo:{{foo}}</p>
      <p>attrs:{{$attrs}}</p>
      <childDomChild v-bind="$attrs"></childDomChild>
   </div>
</template>
<script>
import childDomChild from './childDomChild';
export default {
 name:'child-dom'
 props:["foo"],
 inheritAttrs:false,
}
</script>

// 新增子组件 childDomChild
<template>
  <div>
   <p>coo:{{coo}}</p>
  </div>
</template>
<script>
  export default {
    name:'childDomChild'
    props:["coo"],
    inheritAttrs:false
  }
</script>

c组件的信息,怎么同步给a组件呢?

$listeners

包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on=”$listeners” 传入内部组件——在创建更高层次的组件时非常有用。

// A组件代码更新如下
<template>
 <div>
   <child-dom
    :foo="foo"
    :coo="coo"
     v-on:upRocket="reciveRocket"
   >
   </child-dom>
 </div>
</template>
<script>
 import childDom from "@/components/ChildDom.vue";
 export default {
   name:'demoNo',
   data() {
     return {
       foo:"Hello, world",
        coo:"Hello,rui"
    }
  },
 components:{childDom},
 methods:{
   reciveRocket(){
      console.log("reciveRocket success")
   }
 }
}
</script>

// b组件更新如下
<template>
 <div>
 <p>foo:{{foo}}</p>
 <p>attrs:{{$attrs}}</p>
 <childDomChild v-bind="$attrs" v-on="$listeners"></childDomChild>
 </div>
</template>
<script>
import childDomChild from './childDomChild';
export default {
 name:'child-dom'
 props:["foo"],
 inheritAttrs:false,
}
</script>

// c组件更新如下
<template> 
 <div>
 <p>coo:{{coo}}</p>
 <button @click="startUpRocket">我要发射火箭</button>
 </div>
</template>
<script>
 export default {
 name:'childDomChild',
 props:['coo'],
 methods:{
 startUpRocket(){
 this.$emit("upRocket");
 console.log("startUpRocket")
 }
 }
 }
</script>

 

12. tabs存在嵌套时,tab页显示混乱问题

 

 

 

 

 

 实际上‘手工输入‘和‘文件导入-增量’这两个tab页在子组件deviceWhiteList的子组件中,显示混乱,需要在tabs中添加name属性,并在tabpane中添加响应的tab属性,子组件中的tabs也需要同步添加。如:

 

 

 

 

13. select传递多个参数

// 方法1:
 @change="changeClassify($event, 'first')"
// 方法2:
 @change="e => {changeClassify(e, 'first')}"

 

14. vue-quill-editor 自动获取焦点问题 

问题:当editor编辑器在滚动容器底部时,由于会自动获取焦点导致滚动条默认滚动到底部,解决:先禁止获取焦点,获取到内容之后再开启(只这样好像也不起作用,需要将滚动容器顶部的输入框设置为获取焦点)

<el-form-item :prop="'productBase.productName'" label="商品名称:">
          <el-input
            ref="nameRef"
            class="input-w"
            :disabled="showDisabled"
            v-model="filtersData.productBase.productName"
            placeholder="请输入内容"
          ></el-input>
        </el-form-item>


this.$refs.nameRef.focus();

 

vue-quill-editor 在获取到接口传过来的内容之后会获取焦点,所以 思路就是调用接口之前先禁止获取焦点,获取到内容之后再开启。
放到mounted中

this.$refs.myQuillEditor.quill.enable(false);

接口调用之后 并获取到内容之后调用

this.$nextTick(()=>{
  this.$refs.myQuillEditor.quill.enable(true);
})

 

15. input设置disabled禁用时,点击无效问题

input标签 disabled属性说明

  • 被禁用的input标签 既不可用,也不可进行点击

解决方案

  • 使用readonly属性 来替换disabled属性
  • 外套一层父标签,给父标签添加点击事件,并设置input的样式为"pointer-events:none" 去掉鼠标事件,然后通过冒泡触发到父标签上的点击事件。

冒泡事件
点击子标签,会一层一层往上传,并触发父标签的绑定事件

取消冒泡事件

e.stopPropagation();
posted @ 2019-03-27 11:29  Lingn  阅读(185)  评论(0编辑  收藏  举报