Vue-cli知识点集锦

Vue-cli知识点集锦

  • 添加滚动监听事件

1、添加滚动监听事件

方法1: 在div里添加滚动事件函数

methods:{
	function onScroll () {
		var el = document.getElementById('text');
        const offsetHeight = el.offsetHeight;
        const scrollTop = el.scrollTop;
        const scrollHeight = el.scrollHeight;
        // 滚动条距离底部不到100px时需做处理
        if (offsetHeight + scrollTop >= scrollHeight-100) {
          // 需要执行的代码
          console.log('///');
        }
	}
}

方法2:在mounted中为某个div添加滚动监听事件

	mounted() {
      document.getElementById('text').addEventListener('scroll', () => {
        console.log('llllllllllll');
      });
    },

tips:addEventListener第二个参数为函数名时,需注意不能加‘()’

document.getElementById('text').addEventListener('scroll', this.onScroll);

函数加括号和不加括号的区别:
函数只要是要调用它进行执行的,都必须加括号。此时,函数实际上等于函数的返回值或者执行效果,当然,有些没有返回值,但已经执行了函数体内的行为,就是说,加括号的,就代表将会执行函数体代码。
不加括号的,都是把函数名称作为函数的指针,一个函数的名称就是这个函数的指针,此时不是得到函数的结果,因为不会运行函数体代码。它只是传递了函数体所在的地址位置,在需要的时候好找到函数体去执行。

2、将axios设为全局变量

axios需要在每个Vue文件中引入才能用,但是如果如果文件过多的话每个文件引入一次太多余繁琐,因此可以将其在main.js中引入

import axios from 'axios';
Vue.prototype.$axios = axios;

文件中这样用

this.$axios.get('/user/list').then((res) => {
          console.log(res);
        }, (res) => {
          console.log(res);
        });

3、使用mock可模拟数据

首先在main.js中引入mock.js:

require('./mock.js');

mock.js中代码如下:

// 引入mockjs
const Mock = require('mockjs');
// 获取 mock.Random 对象
const Random = Mock.Random;
// mock一组数据
const produceUserData = function () {
  let users = [];
  for (let i = 0; i < 10; i++) {
    let newUserObject = {
      name: Random.cname(), // Random.cname() 随机生成一个常见的中文姓名
      isAuthor: Random.boolean(),
      color: Random.color(),
      weiboUrl: Random.url(),
      address: Random.region(),
      helper: Random.shuffle(),
      miscellaneous: Random.guid,
      intro: Random.csentence(5, 30), //  Random.csentence( min, max )
      avatarUrl: Random.dataImage('300x250', 'mock的图片'), // Random.dataImage( size, text ) 生成一段随机的 Base64 图片编码
      date: Random.date() + ' ' + Random.time(), // Random.date()指示生成的日期字符串的格式,默认为yyyy-MM-dd;Random.time() 返回一个随机的时间字符串
      addr: Mock.mock('@county(true)'), //随机生成一个地址
      float: Random.float(1,2,3,4), //随机生成一个浮点数,参数:(整数部分最小,整数部分最大,小数部分最小,小数部分最大)
      birth: Mock.Random.datetime(), //随机生成一个日期
      sex: Mock.Random.integer(0, 1),//随机生成一个整数,0/1 ,根据这个来给“男” “女”
      email: Mock.mock('@EMAIL()'), //随机生成一个邮箱
      time: Mock.Random.date('yyyy/MM/dd'),
      list: Random.range(1, 20, 2)   // 生成一个数组,最小是1,最大事20,间隔是2
    };
    users.push(newUserObject);
  }

  return {
    users: users
  };
};

// Mock.mock( url, post/get , 返回的数据);
Mock.mock('/user/list', 'get', produceUserData);

在UserManagement.vue中使用时中代码如下:

this.$axios.get('/user/list').then((res) => {
          console.log(res);
          this.userList = res.data.users;
        }, (res) => {
          console.log(res);
        });

关于mock的其他数据类型的设置请参考https://segmentfault.com/a/1190000010211622#articleHeader17

4、watch属性

watch属性:watch是vue实列的一个属性,它是一个对象,键是需要观察的表达式,值是对应回调函数。值也可以是方法名,或者包含选项的对象。

var vm = new Vue({
  data: {
    a: 1,
    b: 2,
    c: 3
  },
  watch: {
    //第一种写法 适用于普通变量(简单类型的值的观测写法)
    a: function (val, oldVal) {
      console.log('new: %s, old: %s', val, oldVal)
    },
    // 第二种写法:方法名
    b: 'someMethod',
    // 第三种写法:深度 watcher(能观测对象c下多重属性变化)(复杂类型的值的观测写法)
    c: {
      //当c变化后会回调handler函数
      handler: function (newVal, oldVal) { /* ... */ },
      deep: true
    }
  }
})
vm.a = 2 // -> new: 2, old: 1

当被监听的值是对象(若为数组,数组项为对象)时需要使用深度监听,即上述c
** 注意:不能使用箭头函数定义watcher(回调)函数,因为箭头函数绑定了父级作用域的上下文,所以里面的 this 将不会按照期望指向 Vue 实例**
子组件监听父组件传过来的对象:
情况1:父组件:原始:obj:{},变化:obj = {…} 子组件可检测到(obj指针发生变化),此时不需使用深度检测
情况2:父组件:原始:obj:{},变化:obj.key=‘abc’ 子组件不可检测到,此时使用深度检测也无效
情况3:父组件:原始:obj:{name: ‘abc’},变化:obj.name=‘123’ 子组件不可检测到,此时需使用深度检测

5、v-if 和 v-show

区别:
v-show 会在app初始化的时候编译并且渲染,并且在之后一直存在。当切换v-show模块时,只是简单的更改css。
v-if 当切换v-if模块时,Vue.js 有一个局部编译/卸载过程,因为 v-if 之中的模板也可能包括数据绑定或子组件。v-if 是真实的条件渲染,因为它会确保条件块在切换当中合适地销毁与重建条件块内的事件监听器和子组件。 v-if 是惰性的,如果为false,则什么也不错-不编译,不渲染。 当第一次条件为真时,才开始编译。

建议:
v-show的切换消耗比较低,但是不会重新渲染子组件,所以最好用于静态的内容或者不需要重新构建结构的组件。而 v-if 比较适合不太频繁的切换状态的组件。所以项目设计的时候,不要对复杂的业务设计模块太频繁的视图切换。尽量将静态内容和动态内容分离到不同的模块中。

在el-table-column中使用v-if时需要几个v-if紧挨着,否则会出现只有行没有列的情况,也没有数据,不是很明白为什么会这样,本人猜测切换太过频繁消耗太高每列宽度无法正常显示。
在el-table-column中使用v-show无效,本人猜测el-table-column里封装的template,本质上并不是一个元素。而v-show是通过控制元素的display来进行显示隐藏的,所以el-table-column也就不会有display 这个css属性。同理slot也不能使用v-show

6、.native用法

vue里的某些标签如router-link和自定义的组件本身没有点击事件,此时直接用@click无效,而所有HTML5标签天生拥有点击事件,加上.native后将那些组件转化成HTML5标签,可以添加点击事件,这些同样适用于其他事件。
官方解释:在某个组件的根元素上监听一个原生事件。
总结:native就是把组件变回原生DOM的一种方式。
举例说明:
parent.vue


children.vue

click

此时handleClickChange无效,需修改为


等价于为id为btn的元素添加点击事件。

7、.sync用法

父组件通过prop传给子组件的值可以用.sync进行修改并同步到父组件。
举例说明:
parent.vue


{{name}}

children.vue

click
	methods: {
      changeName () {
        this.$emit('update:foo', 'Kate');
      }
    },

点击按钮后父组件中name会更新。

8、slot和scope-slot

  • slot: 是在组件模板中设置的用于在父组件中插入其孙子组件(即自身的子组件)或DOM片段的插槽。

举例说明:
parent.vue

  
    {{componentData.name}}
    {{componentData.age}}
    {{componentData.job}}
     // 内容为空则默认显示slot标签内的文本,即下方“其他内容”
  

children.vue

   

姓名:

年龄:

职业:

其他:其他内容

  • scope-slot: 允许在 Slots 中绑定当前组件的数据,然后经由父组件绑定到其孙子组件(即自身的子组件)的 Props 中传递给孙子组件(即自身的子组件),或绑定到DOM片段
    举例说明:
    parent.vue
    
      
  • {{props.text}}
  • children.vue

       
    

    9、nextTick

    什么时候需要用的Vue.nextTick()
    1、Vue生命周期的created()钩子函数进行的DOM操作一定要放在Vue.nextTick()的回调函数中。原因是在created()钩子函数执行的时候DOM 其实并未进行任何渲染,而此时进行DOM操作无异于徒劳,所以此处一定要将DOM操作的js代码放进Vue.nextTick()的回调函数中。与之对应的就是mounted钩子函数,因为该钩子函数执行时所有的DOM挂载和渲染都已完成,此时在该钩子函数中进行任何DOM操作都不会有问题 。
    2、在数据变化后要执行的某个操作,而这个操作需要使用随数据改变而改变的DOM结构的时候,这个操作都应该放进Vue.nextTick()的回调函数中。
    举例说明:

    • {{item}}

    效果如下:
    这里写图片描述

    10、新建组件对象并挂载

    VideoBox是自定义的组件名称,暂且称为子组件,当前组件称为父组件

    		// 引入Vue和子组件VideoBox
    		import Vue from 'vue';
    		import VideoBox from './VideoBox.vue';
    		
    		// 使用基础 Vue 构造器,创建一个“子类”
    		var VideoBoxClass = Vue.extend(VideoBox);
    		// 手动地挂载一个未挂载的实例,并赋给一个对象
            var VideoBoxObj = new VideoBoxClass({
            	// data必须为函数,此对象将与子组件自身的data合并
            	data: function () {
        			return {
         				firstName: 'Walter',
       				}
      			},
      			// 若子类中需要用到store,必须将当前this.$store传进子类对象
      			store: this.$store
            }).$mount();
            // 设置子组件props属性(即父组件向子组件传递参数)
            VideoBoxObj.videoInfo = {name: 'abc'};
            // 设置子组件事件(即子组件向父组件传递参数)
            VideoBoxObj.$on('deleteVideo', (param)=>{console.log(param)});
            var video = document.createElement('div');
            // 将子组件挂载到父组件下的一个div中
            video.appendChild(VideoBoxObj.$el);
    

    可以直接挂载到id为app的一个容器中,参数为选择器

    new VideoBoxClass().$mount('#app')
    

    11、子组件的created和mounted

    Parent包含两个Child,从Parent跳转到Second,created、mounted、activated的执行顺序:
    Vue-cli知识点集锦_第1张图片
    在这里插入图片描述
    A是B的父组件,B是C的父组件,created、mounted、activated的执行顺序:
    Vue-cli知识点集锦_第2张图片

    12、computed、watch、created、mounted、activated

    (1) 页面初始化时执行顺序:computed、created、mounted、activated
    (2) watch对象的key变化后才执行,执行顺序为:computed、watch、created、mounted、activated

    13、本地开启HTTPS服务

    (1)生成SSL证书
    输入命令:
    生成一个RSA私钥: openssl genrsa -des3 -out server.key 2048
    生成CSR(证书签名请求): openssl req -new -key server.key -out server.csr
    删除私钥中的密码: openssl rsa -in server.key -out server_no_passwd.key
    生成自签名证书: openssl x509 -req -days 365 -in server.csr -signkey server_no_passwd.key -out server.crt
    将SSL证书文件拷贝到project1/bin目录下
    (2)服务器

    // 引入https和fs,代替http
    var https = require('https');
    var fs = require('fs');
    // 读入密钥和证书文件
    var privatekey = fs.readFileSync('bin/server_no_passwd.key', 'utf8');
    var certificate = fs.readFileSync('bin/server.crt', 'utf8');
    // 构造https服务器选项
    var options={key:privatekey, cert:certificate};
    // 创建HTTPS服务器
    var server = https.createServer(options, app);
    server.listen(8080);
    server.listen(port,function () { console.log('Https server listening on port ' + port); });
    

    (3)前端(Vue-cli)
    a、在config/index.js中修改proxyTable:target改为https协议的域名,且添加secure: false(非常重要,否则报错)。
    b、build/webpack.dev.conf.js中devServer添加https: true。
    (一开始看文档这里也可以引入秘钥和证书两个文件,经尝试,引入文件报错,原因不明)

    14、父组件向子组件传值,该值在父组件中变化时,子组件的接收情况和监测情况

    (1)通过data接收
    (2)通过computed接收
    (3)通过watch监控

      props: {
       obj: {
          type: Object,
          default: function () {
            return {};
          }
        }
      },
      watch: {
        obj: {
          handler: function () {
            console.log('obj: ', this.obj);
          },
          deep: false
        }
      },
      computed: {
        itemObj () {
           return this.obj;
        }
      },
      data () {
        return {
          itemObj: this.obj
        };
      },
    

    以下表格中”否“代表子组件中属性不能随父组件中的值变化而变化,”是“代表会变化

    (1)对象

    原始数据:obj = {name: ‘abc’}

    data computed watch
    obj = {age: 12}
    obj.name = ‘def’
    obj.age = 12

    第二行中watch需使用深度监测才能监测到,其他情况中”是“均为非深度监测即可监测到,”否“均为深度监测也无法检测到

    (2)数组

    • 数组项为简单类型,原始数据:arr = [1]
    data computed watch
    arr.push(2)
    arr = [2]
    arr[0] = 2
    • 数组项为对象, 原始数据:arr = [{name: ‘abc’}]
    data computed watch
    arr.push({age: 12})
    arr = [{age: 12}]
    arr[0] = {age: 12}
    arr[0].name = ‘def’
    arr[0].age = 12

    (3)上述情况中的“否”与“是”同时存在时

    	// 原始数据:
    	arr: [1],
        arr2: ['abc'],
        arr3: [{name: 'abc'}],
        obj: {name: 'abc'},
        obj2: {name: 'abc'}
    
    	// 修改:
    	this.arr[0] = 2;
        this.arr2[0] = 'def';
        this.arr3 = [{age: 12}];
        this.obj.name = 'def';
        this.obj2.age = 12;
    

    data、computed都可以监测到变化,只有arr3可以用watch监测到(非深度监测),obj只有在深度监测下才可以监测到。推测:一个变量变化会触发监测机制,这个机制一旦启动,所有其他变量都会被监测到(个人观点,欢迎纠正)。

    15、父组件向子组件传值(provide/inject)

    一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效

    	// 父组件
    	name: 'parent',
    	provide: {
       		foo: 'hello'
     	},
     	
    	// 子孙组件
    	name: 'child',
    	inject: ['foo'], // 子组件接收foo变量,像props和data中的变量一样使用
    

    修改provide内的值

    	// 父组件
    	name: 'parent',
    	provide () {
        	return {
          		foo: this  // 将父组件实例传给子组件,子组件可通过foo获取父组件的变量
        	};
      	},
      	data () {
        	return {
          		val: 'hello'
        	};
      	},
      	
    	// 子孙组件1
    	name: 'child1',
    	inject: ['foo'], 
    	
    	// 子孙组件2
    	name: 'child2',
    	inject: {
        	foo: {
          		default: () => {}
        	}
      	},
      	
    	// 子孙组件3
    	name: 'child3',
    	inject: {
        	bar: {
          		from: 'foo', // 为foo起个别名,子组件内使用bar即可访问父组件
          		default: () => {}
        	}
      	},
    

    你可能感兴趣的:(前端)