Vue项目配置

一、npm init /初始化为一个npm的项目,执行完之后会生成package.json

二、npm i webpack vue vue-loader /执行完之后会生成node_modules

三、新建 webpack.config.js文件,配置出入口和loader /帮助打包前端资源

const path = require('path');
const webpack = require('webpack');
const HTMLPlugin = require('html-webpack-plugin');

/ webpack正式环境打包的时候会把css和js代码放到一个文件中,extract-text-webpack-plugin代码帮助打包非js的代码为单独的文件,提前要npm i extract-text-webpack-plugin
const ExtractPlugin = require('extract-text-webpack-plugin');
/ 启动dev时候设置的环境变量全部存放在process.env这个对象里面
const isDev = process.env.NODE_ENV === 'development'
const config = {
  / __dirname表示当前文件所在的目录
  entry: path.join(__dirname, 'src/index.js') / vue文件只是一个组件,不能当做入口文件,入口文件可以是js文件,在js中想办法把vue组件挂载上
  output: {
    /在开发环境只能使用hash,不能使用chunkhash
    filename: 'bundle.[hash:8].js',
    path: path.join(__dirname, 'dist')
  },
  / webpack原生只支持js文件类型和es5的语法,所以需要增加配置帮助扩展支持css,vue等文件
  module: {
    rules: [
      {
        / test是一个正则表达式,这句话表示匹配以vue为后缀名的文件
        test: /\.vue$/, 
        loader: 'vue-loader'
      },
      {
        / 对于jsx用babel-loader
        test: /\.jsx$/,
        loader: 'babel-loader',
      },
      {
        test: /\.(gif|jpg|svg|jpeg|png)$/,
        use: [
          {
            loader: 'url-loader',
            / 每个loader都有一些可选的配置选项
            options: {
              limit: 1024
              / 指定输出的名字,[name]表示图片原来的名字,[ext]表示扩展名
              name: '[name].[ext]' 
            }
          }
        ]
      }
    ]
  },
  plugins: [
      / vue项目必须要用的一个插件,根据不同的环境进行打包,开发环境包含更多错误信息的功能,方便调试,在正式环境中不引用这些功能可以节省开销,提高代码运行效率
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: isDev ? '"development"' : '"production"'
      }
    }),
    new HTMLPlugin()
  ]
}
if (isDev) {
  config.module.rules.push({
    test: /\.css$/,
    / loader: 'css-loader' 
    / css-loader只能处理css文件,但是项目中的css一般不仅仅以文件的形式存在,还有内部样式表等
    / css-loader没有样式热加载的功能,要使样式能够根据代码变动而随时更新,应该使用vue-style-loader
    use: [
      / style-loader把css-loader处理的结果外面包了一层js代码,然后放入html中去
      'style-loader', 
      /处理css文件
      'css-loader'  
    ]
  });
  / devServer是在webpack2以后才加入的
  / 在浏览器调试代码的时候是编译之后的代码,可能会看不懂,devTool帮助开发者看到的代码仍然是编译之前的代码
  config.devtool = '#cheap-module-eval-source-map'
  config.devServer = {
    port: 8000,
    / 设置为0.0.0.0的好处:既可以通过127.0.0.1来访问,也可以通过本机的ip在内网中访问
    host: '0.0.0.0',
    / 让基础错误显示在网页上,方便排查问题
    overlay: {
      errors: true, 
    },
    / open: true, 启动的时候自动打开浏览器
    / historyFallback: true 帮忙把webpack找不到的路由映射到入口
    hot: true, /修改组件之后不重新加载页面,只做局部渲染
  }
  config.plugins.push(
    / 启动config.devServer.hot所需要的插件
    new webpack.HotModuleReplacementPlugin() 
  )
} else {
  / 正式环境可以把类库文件和业务文件分开打包,因为类库文件比较稳定,单独打包可以作为静态资源或者缓存,这样浏览器不需要在每次业务逻辑代码变更时重新请求所有资源
  config.entry = {
    app: path.join(__dirname, 'src/index.js'),
    vendor: ['vue']
  }
  / 在正式环境中使用chunkhash的原因是:每生成一个打包文件都会生成不同的hash值
  config.output.filename = '[name].[chunkhash:8].js'
  config.module.rules.push({
    test: /\.css$/,
    use: ExtractPlugin.extract({
      fallback: 'style-loader',
      use: [
        'css-loader',
      ]
    })
  })
  config.plugins.push(
    new ExtractPlugin('styles.[contentHash:8].css')
    new webpack.optimize.CommonsChunkPlugin({
      name: 'vendor'
    }),
    / vendor一定要放在runtime前面
    / runtime的作用是: webpack会为每个模块生成一个id,在有新的模块加入的时候这个模块可能会插到中间,这样的话其他模块的hash值可能会发生变化,导致静态资源作为浏览器缓存可能会失去效果,使用这种方法可以规避这个问题
    new webpack.optimize.CommonsChunkPlugin({
      name: 'runtime'
    }),
  )
}
module.exports = config

四、index.js文件(入口文件)

import Vue from 'vue'
import App from 'app.vue'

new Vue({
  render: (h)=> h(App) /声明组件来渲染出app的内容
})

五、在package.json中“scripts”加入打包的命令行

/ –config 用于指定config文件
“build”: “webpack –config webpack.config.js”

六、webpack-dev-server的配置和使用

1.npm i webpack-dev-server
2.npm i cross-env /在不同的开发平台,环境变量是不一样的,cross-env可以保证用同一套环境变量即可
3.build和dev

  • “build”: “cross-env NODE_ENV=production webpack –config webpack.config.js”
  • “dev”: “cross-env NODE_ENV=development webpack-dev-server –config webpack.config.js”

4. npm i html-webpack-plugin /webpack插件,帮助js文件嵌入到html从而正确展示

(719) 733-2352

一、dom事件的级别

DOM0:element.onlick = function() {}
DOM2:element.addEventListener(‘click’, function(){}, false)
true – 事件捕获阶段执行。
false- 默认,事件冒泡阶段执行。
DOM3:element.addEventListener(‘key’, function(){}, false)
在DOM2的基础上扩充了事件类型,比如鼠标事件和键盘事件

二、dom事件模型

捕获和冒泡

三、dom事件流

捕获-》目标阶段-》冒泡

四、描述dom事件捕获的具体流程

接收window-》接收document-》html标签-》body-》目标元素

五、event对象的常见应用

1.event.preventDefault() /阻止默认事件

2.event.stopPropagation()
stopPropagation方法作用在后续节点上,目的在执行完绑定到当前元素上的所有事件处理程序之后,停止执行所有后续节点的事件处理程序

3.event.stopImmediatePropagation() /处理事件优先级的函数
stopImmediatePropagation方法作用在当前节点以及事件链上的所有后续节点上,目的是在执行完当前事件处理程序之后,停止当前节点以及所有后续节点的事件处理程序的运行

4.event.currentTarget
当前绑定的事件

5.event.target
表示当前被点击的元素

tips:event.currentTarget和event.target可以配合做时间委托

六、自定义事件(模拟事件)

var eve = new Event(‘custome’); /声明一个自定义事件,事件名称是custome
div.addEventListener(‘custome’, function() { /
console.log(‘custome’);
});
div.dispatchEvent(eve); /触发绑定的事件

tips:CustomeEvent和Event的区别:CustomeEvent可以自定义传入的参数

539-221-2193

一、class1 .class2
中间有空格的情况:是选择到.class1类下的.class2类子节点,即.class2类的节点要是.class1类子节点
二、.class1.class2
无空格情况:是选择到同时拥有.class1和.class2的节点

.class1 { color: black; }
.class1 .class2 { color: red; }
.class1.class2 { color: blue; }
/*注意优先级,.class1 .class2的优先级比.class1.class2高,.class1 .class2写在.class1.class2后,.class1.class2会被覆盖*/

<div class="class1">
I'm class1
<div class="class2">I'm class2,son of class1</div>
<div class="class1 class2">I'm class1class2,son of class1</div>
</div>

tips: 还有一种情况是:在IE浏览器的“怪异模式”下,.class1.class2 会没有效果,因为不支持 multiple selectors ,这时需要在文件开始加上 DOCTYPE ,像<!DOCTYPE html> 或者其他 DOCTYPE 。

8185949388

一、vue实例的创建和作用

import Vue from 'vue';
/*
*vue给我们提供了很多不同的功能,默认import进来的vue是node_modules/vue/dist/vue.runtime.common.js,runtime不支持在创建vue实例的时候将template写进去,所以要改为用vue.esm.js,具体做法如下
*/

/ 在webpack.config.dev.js中指定用vue.esm.js
/ resolve: {
/ alias: {
/ 'vue': path.join(__dirname,'../node_modules/vue/dist/vue.esm.js')
/ }
/ }

/ const div = document.createElement('div');
/ document.body.appendChild(div)


const app = new Vue({
  template: '<div>this is a div</div>'
  / 在创建实例里面直接写data的时候不需要将data写成一个函数
  data: {
    text: 0
  },
  watch: {
    text (newText, oldText) {
      console.log(${newText} ${oldText})
    }
  }
});
app.$mount('#root')
/ 同样可以创建vue实例并挂载到root节点
/ new Vue({
/ 	/ template会把内容挂载到el指定的节点上
/ 	el: '#root', 
/ 	/ template会被vue编译成render funciton ,最终被插入html 
/ 	template: '<div>this is a div</div>'
/ })
/ 可以直接修改节点上的data
setInterval(()=> {
 app.text + = 1;
 / 直接通过$options修改数据是无效的,通过$data修改是生效的
 / app.$options.data.text + = 1;
 / app.$data.text + = 1;
}, 1000)

二、vue的属性

console.log(app.$data)

console.log(app.$props)
console.log(app.$el)
console.log(app.$props)
console.log(app.$options)
/ 通过 $options写render是在template中的data变化时触发
/ app.$options.render = (h)=> {
/ return ('div', {}, 'new render func')
/ }

console.log(app.$root) /app.$root === app
console.log(app.$slots)
console.log(app.$scopedSlots)
console.log(app.$children)
console.log(app.$refs)
console.log(app.$isServer) /只有在有服务端渲染的情况下才会用到


/ const unWatch = app.$watch('text', (newText, oldText) => {
/ es6的字符串模板
/ console.log(${newText} ${oldText})
/ })
/ watch方法写在外面的时候需要在vue实例被销毁的时候自己去调用unWatch方法,否则会wacth不会停
/ unWatch()


/ $once和$on的区别:$once只渲染一次
/ app.$on('test', (a, b)=> {
/ console.log(test emited ${a} ${b})
/ })
/ app.$emit('test', 1, 2)

三、添加到对象上的新属性不会触发更新

<template>
  <div>
    {{a}}
  </div>
</template>
<script>
export default {
  data() {
    return {
      a: {},
    };
  },
  created() {
    setTimeout(() => {this.a.b = 1;}, 1000) /watch检测不到
    setTimeout(() => {this.a = {b: 1,};}, 500); /新建一个对象并赋值给已有对象
  },
  watch: {
    a(newVal, oldVal) {
      console.log(${oldVal}现在变成了${newVal});
    },
  },

}
</script>

(313) 492-5651

一、过程

created会完成数据观测(data observer),属性和方法的运算,watch/event事件回调,此时挂载阶段还没开始,$el属性目前不可见,之后实例会去检查有没有el选项,如果有的话在挂载之前调用beforeMount,没有的话就等着我们自己调用vm.$mount去挂载vue实例,接着实例去判断有没有template选项,如果有的话将template解析成render函数(在使用.vue文件开发的过程中都没有template参数,.vue文件都经过了vue-loader的处理,直接变成render函数,放入到vue-loader解析过的结果里面,相当于loader替我们做了从template解析到render函数的过程)

二、关键时间点

1、创建前/后
在beforeCreated阶段,vue实例的挂载元素$el和数据对象data都为undefined。
在created阶段,vue实例的数据对象data有了,$el还没有。
2、挂载前/后
在beforeMount阶段,vue实例的$el和data都初始化了,但还是挂载之前为虚拟的dom节点,data的信息还未替换。
在mounted阶段,vue实例挂载完成,data的信息成功渲染。
3、更新前/后:当data变化时,会触发beforeUpdate和updated方法。
4、销毁前/后:在执行destroy方法后,对data的改变不会再触发周期函数,说明此时vue实例已经解除了事件监听以及和dom的绑定,但是dom结构依然存在

三、生命周期钩子函数(按照顺序)

new Vue({
  el: '#app',
  template: '<div>{{text}}</div>',
  data: {
    text: 0,
  },
  / 创建vue实例之前调用
  beforeCreate() {	
    / this.$el为undifined
    console.log(this.$el,'beforeCreate')
  },
  / 创建vue实例的时候调用
  created() {
    / this.$el为undifined
    console.log(this.$el,'created')
  },
  / 挂载到el之前调用(如果没有挂载节点el,则不会执行),mount跟dom操作有关,在服务端渲染的时候没有dom的环境,所以不会调用
  beforeMount() {
    / 打印结果为<div id="app"></div>
    console.log(this.$el,'beforeMount')
  },
  / 挂载到el完成(如果没有挂载节点el,则不会执行),mount跟dom操作有关,在服务端渲染的时候没有dom的环境,在服务端渲染的时候不会调用
  mounted() {
    / 打印结果为<div>0</div>
    console.log(this.$el,'mounted')
  },
  / 在有数据更新的时候执行
  beforeUpdate() {
    
  },
  / 在有数据更新的时候执行
  updated() {
    
  },
  activated() {

  },
  deactivated() {

  },
  beforeDestoryed() {

  },
  destoryed() {

  },
  / template解析的结果就是下面的render函数
  / render(h) {
  / h参数相当于createElement,传入3个参数,分别是要创建的标签,标签里面包含的内容(可以是二级标签或者内容等),标签的值
  / 	return h('div', {}, this.text)
  / 在render函数报错的时候会触发renderError
  / throw new TypeError('render error')
  / }

  / 在开发环境中使用,render函数报错的时候触发,子组件报错之后不会被调用
  / renderError(h, err) {
  / 	return h('div', {}, err.stack)
  / }

  / 正式环境中使用,捕获组件及其子组件在渲染render过程中的异常
  / errorCaptured() {
  / }
});

/ 帮助查看beforeUpdate和updated调用的时机
/ setInterval(()=> {
/ 	app.text = app.text + 1;
/ }, 1000)

/ 帮助查看beforeDestoryed和destoryed调用的时机
/ setTimeout(()=> {
/ 	app.$destoryed();
/ }, 1000);

vue动态组件和静态组件

一、使用方法

<template>
    <div>
        <test01-component><test01-component>
        <component :is="test"></component>
        <Button @click="changeComponent">动态改变组件</Button>
    </div>
</template>
<script>
import Test01Component from '../test01';
import Test02Component from '../test02';
import Test03Component from '../test03';
export default {
    data() {
        return {
            test: 'Test02Component',
        }
    },
    components: {
        Test01Component,/ 静态组件
        Test02Component, /动态组件
        Test03Component, /动态组件
    },
    methods: {
        changeComponent() {
            if (this.test == 'Test02Component') {
                this.test = 'Test03Component';
            } else {
                this.test = 'Test02Component';
            }
        }
    }
}
</script>

tips:改变挂载的组件,只需要修改is指令的值即可

二、多学一点

通俗易懂的blog:5816825804

  • <keep-alive>包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们
  • 当组件在<keep-alive>内被切换,它的activated和deactivated这两个生命周期钩子函数将会被对应执行
  • activated: keep-alive组件激活时调用
  • deactivated: keep-alive组件停用时调用