原创不易,转载请注明出处,谢谢!

第一部分:Vue基础语法——组件化开发——模块化开发——webpack


Day 01


01.(了解)vue.js课程介绍

  • Vue.js课程学习路线
  • Vue基础语法——组件化开发——Vue CLI——vue-router——vuex详解——网络封装——项目实战——项目部署——Vue.js原理相关

02.(理解)vue.js的特点和认识介绍

  • Vue是一个渐进式框架,什么是渐进式呢?

渐进式意味着你可以将Vue作为你应用的一部分嵌入其中,带来更丰富的交互体验。

或者如果你希望将更多的业务逻辑使用Vue实现,那么Vue的核心库以及其生态系统。

比如Core+Vue-router+Vuex,也可以满足你各种各样的需求。

03.(掌握)vue.js安装方式

  • 方式一:直接CDN

  • 方式二:下载和引入

开发环境 https://vuejs.org/js/vue.js

生产环境 https://vuejs.org/js/vue.min.js

  • 方式三:NPM安装

后续通过webpack和CLI的使用,我们使用该方式。

04.(掌握)HelloVuejs初体验

  • 原生改变元素内容和vue改变元素内容区别
  • el:挂载管理的元素
<body><!-- vue模式html --><div id="app">{{message}}</div><!-- 原生模式html --><div id="dom"></div><!-- vue改变元素内容,叫声明式编程 --><script src="./js/vue.js"></script><script>//let变量、const常量const app = new Vue({el: '#app', //用于挂载要管理的元素data: { //定义一些数据message: '你好啊vue'},})</script><!-- 原生改变元素内容,叫命令式编程--><script>document.querySelector('#dom').innerHTML = '你好啊dom';</script>
</body>

05.(掌握)Vue列表的显示

  • 传统改变ul>li内容和vue的v-for遍历内容的区别
  • 响应式:app.movies.push("龙猫"),页面直接就显示新增内容,而传统的dom操作需要创建一个li,然后再加内容
<body><!-- vue替代遍历列表内容 --><div id="app"><ul><li v-for="item in movies">{{item}}</li></ul></div><script src="./js/vue.js"></script><script>const app = new Vue({el: '#app',data: {message: '',movies: ["功夫", "千与千寻", "肖申克救赎", "泰坦尼克号"]}})</script><!-- 传统dom遍历列表内容 --><ul class="con"><li>{{movies[0]}}</li><li>{{movies[1]}}</li><li>{{movies[2]}}</li><li>{{movies[3]}}</li></ul><script>document.querySelector('.con').querySelectorAll('li')[0].innerHTML = "功夫"document.querySelector('.con').querySelectorAll('li')[1].innerHTML = "千与千寻"document.querySelector('.con').querySelectorAll('li')[2].innerHTML = "肖申克救赎"document.querySelector('.con').querySelectorAll('li')[3].innerHTML = "泰坦尼克号"</script>
</body>

06.(掌握)小案例-计数器

  • 计数器代码:
<body><div id="app"><h2>计数器:</h2><button @click="sub">-</button><span>{{count}}</span><button @click="add">+</button></div><script src="./js/vue.js"></script><script>const app = new Vue({el: '#app',data: {count: 0,},methods: {sub: function() {this.count--   //this指向当前对象},add: function() {this.count++}},})</script>
</body>

07.(理解)Vue的MVVM模式

  • MVVM:MVVM是Model-View-ViewModel的简写。它本质上就是MVC 的改进版。MVVM 就是将其中的View 的状态和行为抽象化,让我们将视图 UI 和业务逻辑分开。

08.理解Vue的options选项

  • 创建new Vue({})的时候,就传入了一个options对象

    • 需要掌握的选项(不止这些):

      el

      类型:string | HTMLElement(“|”是或的意思)

      作用:决定之后Vue实例会管理哪一个DOM

      data

      类型:Object | Function

      作用:Vue实例对应的数据对象

      methods

      类型:{[key:string]:Function}

      作用:定义属于Vue的一些方法,可以在其他地方调用,也可以在指令中使用。

  • 方法和函数的区别:
方法 函数
英文单词 method function
定义 方法(method)是通过对象调用的javascript函数。也就是说,方法也是函数,只是比较特殊的函数。 函数(function)是一段代码,需要通过名字来进行调用。它能将一些数据(函数的参数)传递进去进行处理,然后返回一些数据(函数的返回值),也可以不返回数据。

09.(理解)什么是Vue的生命周期

10.Vue的生命周期函数有哪些

  • 生命周期:Vue实例有一个完整的生命周期,也就是说从开始创建、初始化数据、编译模板、挂在DOM、渲染-更新-渲染、卸载等一系列过程,我们成为Vue 实例的生命周期。
  • Vue部分源码:(可以说明Vue在new Vue的时候做了很多事情)
function Vue (options) {if (process.env.NODE_ENV !== 'production' &&!(this instanceof Vue)) {warn('Vue is a constructor and should be called with the `new` keyword')}this._init(options)
}
Vue.prototype._init = function (options?: Object) {......
}
  • 下边created和mounted会在new Vue()的时候执行:
    <script>const app = new Vue({el: '#app',data: {},methods: {},created: function() {console.log("created");    //控制台打印“create”},mounted: function() {console.log("mounted");    控制台打印“mounted”},})</script>
  • Vue生命周期图(重要★)

11.(了解)定义vue的template

  • 自定义用户代码片段,vscode:文件-首选项-用户片段-html.json,加入以下代码:
"vue": {"prefix": "vue", // 触发的关键字 输入vue按下tab键"body": ["    <div id=\"app\"></div>","    <script>","        const app = new Vue({","           el:'#app',","           data:{},","           methods:{}","        });","    </script>",],"description": "vue template"}

12.(掌握)插值操作-mustache语法

  • {{message}}

 <div id="app"><h2>{{message}}</h2><h2>{{message}},龙猫</h2><!-- mustache语法中,也可以直接写简单的表达式 --><h2>{{firstName +' '+ lastName}}</h2><h2>{{firstName}}{{lastName}}</h2><h2>{{count*2}}</h2></div><script src="./js/vue.js"></script><script>const app = new Vue({el: '#app',data: {message: '你好啊',firstName: 'mao',lastName: 'long',count: 100},methods: {}});</script>

13.(掌握)插值操作-其他指令的使用(v-once、v-html、v-text、pre)

  • v-once 只渲染一次,不会随着数据改变而改变,
 <h2 v-once>{{message}}</h2>
  • v-html按照HTML格式进行解析,并且显示对应的内容
  • v-text作用和Mustache一致,通常情况下,接受一个string类型
  • v-pre用于跳过这个元素和它子元素的编译过程,用于显示原本的Mustache语法
  • v-cloak避免在某些情况下,我们浏览器可能会直接显然出未编译的Mustache标签
 <div id="app"><!-- 显示'<a href="http://www.baidu.com">百度</a>'-->{{url}}<!-- 显示:百度--><div v-html="url"></div><!-- v-text和{{}}几乎一样,不会解析html元素,还不如{{}},因为会覆盖内容--><div v-text="url"></div><!-- v-pre不会解析{{}},原封不动显示,用的不多 --><div v-pre>{{message}}</div><!-- vue解析之前,div有一个熟悉叫v-cloak,解析之后,没了,[v-cloak]{display:none} --><div v-cloak>{{message}}</div></div><script src="./js/vue.js"></script><script>setTimeout(() => {const app = new Vue({el: '#app',data: {message: '你好',url: '<a href="http://www.baidu.com">百度</a>'},methods: {}});}, 1000);</script>

14.(掌握)v-bind的基本使用

  • v-bind用于绑定属性,如a元素的href属性,img元素的src属性
  • v-bind的缩写是冒号:
<div id="app"><img :src="imgUrl" alt=""><img v-bind:src="imgUrl" alt=""><a :href="baiduUrl">百度一下</a>C</div><script src="./js/vue.js"></script><script>const app = new Vue({el: '#app',data: {message: '类名',imgUrl: 'https://cn.vuejs.org/images/logo.png',baiduUrl: 'https://www.baidu.com',},methods: {}});</script>

15.(掌握)v-bind动态绑定class(对象语法)

  • 对象语法的含义是:class后面跟的是一个对象

用法一:直接通过{}绑定一个类

Hello World

用法二:也可以通过判断,传入多个值

Hello World

用法三:和普通的类同时存在,并不冲突 注:如果isActive和isLine都为true,那么会有title/active/line三个类

Hello World

用法四:如果过于复杂,可以放在一个methods或者computed中 注:classes是一个计算属性

Hello World

<head><style>.active {color: red;}.line {font-size: 60px;}</style>
</head>
<body><div id="app"><div :class="{active:isActive,line:isLine}">{{message}}</div><div :class="getClasses()">{{message}}</div></div><script src="./js/vue.js"></script><script>const app = new Vue({el: '#app',data: {message: '类名',isActive: true,isLine: true},methods: {getClasses: function() {return {active: this.isActive,line: this.isLine}}}});</script>
</body>

16.(掌握)v-bind动态绑定class(数组语法)

  • 数组语法的含义是:class后面跟的是一个数组。
  • Hello World

17.作业v-bind和v-for结合

  • 两种方法实现v-for不同行点击效果,第二种好
<body><div id="app"><ul>:class="{active:isActive[index]}"方法:<li v-for="(item,index) in movies" :class="{active:isActive[index]}" @click = "changeColor(index)">{{item}}</li>index==this.num?"active":''方法:<li v-for="(item,index) in movies" :class="getClass(index)" @click = "changeNum(index)">{{item}}</li></ul></div><script src="../js/vue.js"></script><script>var app=new Vue({el:'#app',data:{movies:['龙猫','千与千寻','功夫','天空之城'],//    classes:['c1','c2','c3','c4'],isActive:[true,false,false,false],num:0},methods:{changeColor:function(index){// console.log(index);this.isActive = [false,false,false,false]this.isActive[index] = true;},changeNum:function(index){this.num = index;},getClass:function(index){return index==this.num?"active":''}}});</script>
</body>

18.v-bind动态绑定style(对象语法)

  • key:value,value如果不是一个变量,需要加单引号''
<div id="app"><h2 :style="{color:'red',fontSize:'100px',backgroundColor:color}">{{message}}</h2><h2 :style="getStyles()">{{message}}</h2></div><script src="../js/vue.js"></script><script>var app=new Vue({el:'#app',data:{message:'龙猫',color:'blue'},methods:{getStyles:function(){return {color:'red',fontSize:'100px',backgroundColor:this.color}}}});</script>

19.v-bind动态绑定style(数组语法)

  • (用得很少)

20.(掌握)计算属性computed的基本使用

  • 计算属性一般用在对数据进行某种变换对时候,对数据重新定义一个属性
 <div id="app"><h2>{{firstName +' '+lastName}}</h2><h2>{{firstName}} {{lastName}}</h2><h2>{{getFullName()}}</h2><!-- 计算属性一般用在对数据进行某种变换对时候,对数据重新定义一个属性 --><h2>{{fullName}}</h2></div><script src="../js/vue.js"></script><script>var app=new Vue({el:'#app',data:{firstName:'sen',lastName:'wang'},methods:{getFullName:function(){return this.firstName+' '+this.lastName}},//    因为说计算属性,名字最好只像属性computed:{fullName:function(){return this.firstName+' '+this.lastName}}});</script>

21.(掌握)计算属性的复杂操作

  • computed用于计算属性,一般写名词eg:计算几本书的总价
<div id="app"><h2>{{getSumPrice()}}</h2><h2>{{SumPrice}}</h2></div><script src="../js/vue.js"></script><script>var app=new Vue({el:'#app',data:{books:[{id:1101 ,name:"哈姆雷特" ,price:102},{id:1102 ,name:"计算机原理" ,price:102},{id:1103 ,name:"操作系统" ,price:102},{id:1104 ,name:"web前端" ,price:102},],},methods:{//    有错误,不知道为什么getSumPrice:function(){  let sum = 0for( let i = 0;i<this.books.length;i++){sum += this.books[i].price;}return sum}},computed:{SumPrice:function(){//    for( let i = 0;i<this.books.length;i++){//         this.sumPrice += this.books[i].price;//     }//     return this.sumPrice;// 或者使用es6语法:let sum = 0for(let book of this.books){sum += book.price}return sum;  }}});</script>

22.课堂回顾(略)


Day 02


01.理解计算属性的setter和getter

  • 默认使用get方法,没有用set方法
  • set方法只有在设置属性的时候才会调用,如:app.fullName2 = 'sss'
    <div id="app"><h2>{{fullName}}</h2><h2>get方法:{{fullName2}}</h2></div><script src="../js/vue.js"></script><script>var app=new Vue({el:'#app',data:{firstName:'sen',lastName:'wang',  },methods:{},computed:{fullName:function(){return this.firstName +' '+ this.lastName;},fullName2:{set:function(newValue){console.log('---',newValue);const names = newValue.split(' ');this.firstName = names[0];this.lastName = names[1];},get:function(){return this.firstName +' '+ this.lastName}}}});</script>

02.计算属性computed和methods对比

  • computed只调用一次函数性能高(内部有一个缓存),methods会多次调用函数
 <div id="app"><!-- 1.直接拼接 --><h2>{{firstName}}{{lastName}}</h2><!-- 2.通过定义methods --><h2>{{getFullName()}}</h2><h2>{{getFullName()}}</h2><h2>{{getFullName()}}</h2><h2>{{getFullName()}}</h2><!-- 3.通过定义computed --><h2>{{fullName}}</h2><h2>{{fullName}}</h2><h2>{{fullName}}</h2><h2>{{fullName}}</h2></div><script src="../js/vue.js"></script><script>var app=new Vue({el:'#app',data:{firstName:'sen',lastName:'wang'},methods:{getFullName:function(){console.log('getFullName');//输出(调用)4次return this.firstName +' '+ this.lastName}},computed:{fullName:function(){console.log('fullName');//只输出(调用)1次return this.firstName +' '+ this.lastName}}});</script>

03.(掌握)块级作用域let和var

  • JavaScript 闭包。它使得函数拥有私有变量变成可能。
 <script>// 1.var定义的变量在块级外边也可以访问{var name = "longmao"console.log(name);}console.log(name);if(true){var name2 = 'why'}console.log(name2);
</script>
  • 闭包案例
  • 没有使用闭包之前,单击每个按钮打印点击了第i个按钮会全部打印最后1个i的值
  • 使用闭包之后,相当于函数套函数,打印的是5个带参数的函数,在点击的时候再传递参数
var btns = document.querySelectorAll('button');for(i=0;i<btns.length;i++){// btns[i].onclick = function(){//     console.log('第'+i+'个按钮被点击了');// }//使用闭包可以解决此问题,闭包可以看作打印了5个函数,每个函数的num都是一个参数,点击的时候再传递参数(function(num){btns[i].onclick = function(){console.log('第'+num+'个按钮被点击了');}})(i)}
  • let块级作用域解决冲突
    <button>按钮1</button><button>按钮2</button><button>按钮3</button><script>var btns = document.querySelectorAll('button');for(let i=0;i<btns.length;i++){btns[i].onclick = function(){console.log('第'+i+'个按钮被点击了');}}
// //使用let:
//         {//i = 0
//             btns[i].onclick = function(){
//                 console.log('第'+i+'个按钮被点击了');
//             }
//         }
//         {//i = 1
//             btns[i].onclick = function(){
//                 console.log('第'+i+'个按钮被点击了');
//             }
//         }
//         {//i = 3
//             btns[i].onclick = function(){
//                 console.log('第'+i+'个按钮被点击了');
//             }
//         }
// //使用var i=3
//         {//i = 3
//             btns[i].onclick = function(){
//                 console.log('第'+i+'个按钮被点击了');
//             }
//         }
//         {//i = 3
//             btns[i].onclick = function(){
//                 console.log('第'+i+'个按钮被点击了');
//             }
//         }
//         {//i = 3
//             btns[i].onclick = function(){
//                 console.log('第'+i+'个按钮被点击了');
//             }
//         }</script>

04.三种方案对比

  1. var错误的方式
  2. var+闭包方式
  3. let方式

05.(掌握)const的使用和注意点

  • ES6开发中,优先使用const,只有需要改变某个标识符时才用let
<script>
const name = 'why';
name = 'what';//报错
</script>
  • const obj = { },可以修改obj内部的属性,但是不能修改obj外部的指向:
    <script>const name = 'why';// name = 'what';//报错const obj = {name:'龙猫',age:2,move:function(){console.log(this.name);}};// obj = {}//报错obj.name = '千寻';obj.move();//打印的是“千寻”,因为内部的属性可以修改,但是不能改变obj的指向</script>

06.(掌握)ES6对象字面量增强写法

  • ES5和ES6的区别:
  1.         let name = 'why';let age = 18;let obj1 = {name:name,age:age,eat:function(){console.log("吃1");}}console.log(obj1);obj1.eat();//ES6let obj2 = {name,age,eat(){console.log("吃2");}}console.log(obj2);obj2.eat();

07.空

08.(掌握)v-on的基本使用和语法糖

  • 语法糖v-on:和@等价

09.(掌握)v-on的参数传递问题

  • 方法加()的问题
  1. 如果方法中没有传递参数,可以省略括号(也可以不省略)

    +

  2. 如果方法中有参数传递,必须加括号

    +

  3. 如果方法中有多个参数:

 <div id="app"><!-- 1.事件调用方法没有参数 --><button @click = "btn1Click">按钮1不带参数,正常执行</button><button @click = "btn1Click()">按钮1()不带参数,正常执行</button><!-- 2.事件调用方法有参数 --><button @click = "btn2Click('参数')">按钮2(name)带参数,正常返回</button><button @click = "btn2Click()">按钮2()带括号但是不传递参数,返回undefined</button><button @click = "btn2Click">按钮2不带括号也不传递参数,返回MouseEvent对象</button><!-- 3.传递多个参数 --><button @click = "btn3Click('参数3',$event)">按钮3,方法定义时需要参数和event</button></div><script src="../js/vue.js"></script><script>var app=new Vue({el:'#app',data:{},methods:{btn1Click(){console.log("按钮1");},btn2Click(name){console.log(name);},//默认不写参数的时候,执行的是event对象:// btn2Click(event){//     console.log(event);// }btn3Click(name,event){console.log(name,event);}}});</script>

10.(掌握)v-on修饰符的使用

  1. vue中阻止事件冒泡: 按钮
  2. vue中阻止submit默认行为.prevent,如
  3. vue中键盘按下修饰符@keyup.enter = "keyUp"
  4. vue中只运行一次修饰符.once,如按钮2
<div id="app"><!-- 1..stop修饰符 --><div @click = "divClick"><button @click.stop = "btnClick">按钮</button></div><!-- 2..prevent事件修饰符的使用  --><form action="baidu"><input type="submit" value="提交" @click.prevent = "submitClick"></form><!-- 3.监听键帽的按下 --><input type="text" @keyup.enter = "keyUp"><!-- 4..once修饰符 --><button @click.once = "btn2Click">按钮2</button></div><script src="../js/vue.js"></script> <script>var app=new Vue({el:'#app',data:{},methods:{btnClick(){console.log("btnClick");},divClick(){console.log("divClick");},submitClick(){console.log("submitClick");},keyUp(){console.log("keyUp");},btn2Click(){console.log("btn2Click");}}});</script>

11.(掌握)v-if和v-if-else和v-else的使用

  • 区别如下,不太建议在这写,建议在computed里边写判断
<div id="app"><h2 v-if="score>90">优秀</h2><h2 v-else-if="score>80">良好</h2><h2 v-else-if="score>60">中等</h2><h2 v-else>差</h2><h1>{{resultMessage}}</h1></div><script src="../js/vue.js"></script><script>var app=new Vue({el:'#app',data:{score:88},methods:{},computed:{resultMessage(){let showMessage = '';if(this.score>90){showMessage = "优秀"}else if(this.score>80){showMessage = "良好"}else if(this.score>60){showMessage = "中等"}else{showMessage = "差"}return showMessage;}}});</script>

12.(掌握)v-if登陆切换的小案例

<div id="app"><span v-if="isShow"><label for="username">用户名登录</label><input type="text" placeholder="请输入用户名" id="username"></span><span v-else><label for="email">邮箱登录</label><input type="text" placeholder="请输入邮箱" id="email"></span><button @click="changeLoggin">登录切换</button></div><script src="./js/vue.js"></script><script>const app = new Vue({el: '#app',data: {isShow: true},methods: {changeLoggin() {this.isShow = !this.isShow}}});</script>

13.(理解)登录切换的input复用问题

  • 问题:点击切换的时候,input的内容没有清空

    • 原理:div--虚拟dom(放内存里)--显示内容
    • 出于性能考虑,因为没有改变label和input元素标签,会继续复用虚拟dom的label和input元素标签
  • 解决:各加一个key属性,
    • key = "username"
    • key = "email"
        <span v-if="isShow"><label for="username">用户名登录</label><input type="text" placeholder="请输入用户名" id="username" key="username"></span><span v-else><label for="email">邮箱登录</label><input type="text" placeholder="请输入邮箱" id="email" key = "email"></span><button @click="changeLoggin">登录切换</button>

14.(掌握)v-show的使用和v-if的区别

  • v-show:false相当于加了一个行内样式display:none属性
  • v-if:false相当于删除dom
    <div id="app"><!-- v-if为false时,相当于删除dom,适合使用频率低的时候 --><h2 v-if="isShow" id="if">{{message}}</h2><!-- v-show为false时,相当于display:none,适合使用频率高的时候 --><h2 v-show="isShow" id="show">{{message}}</h2></div><script src="./js/vue.js"></script><script>const app = new Vue({el: '#app',data: {message: "hello",isShow: true},methods: {}});</script>

15.(掌握)v-for遍历数组和对象

  • 遍历数组
    <div id="app"><ul><li v-for="(item,index) in names">{{index+1}},{{item}}</li></ul></div><script src="./js/vue.js"></script><script>const app = new Vue({el: '#app',data: {names: ['why', 'wangsen', 'james', 'curry']},methods: {}});</script>
  • 遍历对象
    <div id="app"><!-- 1.笨方法 --><ul><li>{{obj.name}}</li><li>{{obj.age}}</li><li>{{obj.height}}</li></ul><!-- 2.遍历方法,只获取value --><ul><li v-for="item in obj">{{item}}</li></ul><!-- 3.获取(value,key) --><ul><li v-for="(item,key) in obj">{{key}}:{{item}}</li></ul><!-- 4.获取(value,key,index)index用的很少 --><ul><li v-for="(item,key,index) in obj">{{key}}:{{item}}--{{index}}</li></ul></div><script src="./js/vue.js"></script><script>const app = new Vue({el: '#app',data: {obj: {name: 'wangsen',age: 18,height: 1.88}},methods: {}});</script>

16.(理解)v-for绑定和非绑定key的区别

  • 数组插入app.letters.splice(2,0,'F') ,第二个字母边插入F
  • 正常情况是虚拟dom里插入F,然后渲染。但是实际不是,实际是把E改成F,把D改成C,E改成D,最后加一个E,性能比较低,这叫diff算法
  • 所以官方推荐我们使用v-for时,给对应元素加:key属性,这样diff算法就可以正确识别此节点,找到正确的位置插入
  • :key="item"不用index是因为插入之后,index会变,不是一一对应,性能不好
    <div id="app"><ul><!-- :key="item"不用index是因为插入之后,index会变,不是一一对应,性能不好--><li v-for="(item,index) in letters" :key="item">{{index}},{{item}}</li></ul></div><script src="./js/vue.js"></script><script>const app = new Vue({el: '#app',data: {letters: ['A', 'B', 'C', 'D', 'E']},methods: {}});</script>

17.(掌握)数组中哪些是响应式的

数组方法 是否响应式 作用

this.letter.push('sss')

响应式

数组后边添加元素,可以做到响应式

this.letters.pop()

响应式

删除数组最后一个

this.letters.shift()

响应式

删除数组中的第一个

this.letters.unshift('aaa', 'bbb')

响应式

在数组前边添加元素,可以传多个参数是因为是可变参数...str

this.letter.sort()

响应式

排序,响应式

this.letters.reverse()

响应式 数组反转

this.letters.splice(2, 1, 'm  ')

响应式

可以做增删改,从第二个开始,删除1个,增加‘m’

this.letters[0] = 'bbbb'

不能做到响应式,可以this.letters.splice(0, 1, 'bbbb');替代

Vue.set(this.letters, 0, 'bbbb')

响应式 vue的方法实现元素替换

18.(掌握)作业的回顾和实现

  • 四行一列的数据,点击谁,谁变红
  • 重点:currentIndex的引入(此类问题都是这么解决),就是获取当前点击的index的数字
    <div id="app"><ul><li v-for="(item,index) in movies" @click="changeClass(index)" :class="{active:currentIndex==index}">{{item}}</li><!-- <li v-for="(item,index) in movies" @click="changeClass(index)" :class="{active:currentIndex==0}">{{item}}</li><li v-for="(item,index) in movies" @click="changeClass(index)" :class="{active:currentIndex==1}">{{item}}</li><li v-for="(item,index) in movies" @click="changeClass(index)" :class="{active:currentIndex==2}">{{item}}</li><li v-for="(item,index) in movies" @click="changeClass(index)" :class="{active:currentIndex==3}">{{item}}</li> --></ul></div><script src="./js/vue.js"></script><script>const app = new Vue({el: '#app',data: {currentIndex: 0,movies: ['海王', '海贼王', '加勒比海盗', '海尔兄弟']},methods: {changeClass(index) {this.currentIndex = index;}}});</script>

19.(掌握)购物车案例-界面搭建

  • v-for把书籍遍历
        <table><thead><tr><th></th><th>书籍名称</th><th>出版日期</th><th>价格</th><th>购买数量</th><th>操作</th></tr></thead><tbody><tr v-for="(item,index) in bookList"><td>{{item.id}}</td><td>{{item.name}}</td><td>{{item.date}}</td><td><span>{{getFinallPrice(item.price)}}</span><td><button @click="subCount(index)">-</button><span>{{item.count}}</span><button @click="addCount(index)">+</button></td><td><button @click="remove(index)">移除</button></td></tr></tbody></table><h2>总价格:{{sumPrice}}</h2>

20.(掌握)购物车案例-过滤器filter的使用

  • 没有使用过滤器和使用过滤器都能达到目的:
<!--没有使用过滤器-->
<span>{{getFinallPrice(item.price)}}</span>
<script>
...methods: {getFinallPrice(price) {return '¥' + price.toFixed(2)}},
</script><!--使用过滤器-->
<span>{{item.price | showPrice}}</span><script>
...methods: {},filters: {showPrice(price) {return '¥' + price.toFixed(2)}},
</script>

21.(掌握)购物车案例-改变购买数量

  • :disabled="item.count==1"剩下1个点时候,减少按钮不能再点击(变灰)
<th><button @click = "sub(index)" :disabled="item.count==1">-        </button><span>{{item.count}}</span><button @click = "add(index)">+</button>
</th>
...
methods:{sub(index){this.books[index].count--      },add(index){this.books[index].count++},
}

22.(掌握)购物车案例-移除按钮-最终价格

  • 移除全部书之后,购物车变成“购物车为空”,利用v-if和v-else
  • 计算总价使用计算属性:
    两种方法 DOM中区别 调用
    computed

    总价为{{sumPrice}}

    会自动调用sumPrice方法
    methods

    总价为{{sumPrice()}}

    也会自动调用sumPrice方法,但是不太合适
    totalPrice() {//计算总价的方法1:// let totalprice = 0;// for (item of this.bookList) {//     totalprice += item.price * item.count;// }// return totalprice//计算总价的方法2(高级函数):return this.bookList.reduce(function(preValue, book) {return preValue + book.price * book.count}, 0)}
<div v-if="books.length!=0"><table>books</table>
</div>
<div v-else>购物车为空</div>

Day 03


01.(掌握)JavaScript高阶函数的使用

  • 计算总价的三种方法(of 最好):
sumPrice(){//1.普通的for循环// let sumprice = 0;// for(let i=0;i<this.books.length;i++){//     sumprice += this.books[i].price * this.books[i].count;// }// return sumprice// 2. in循环// let sumprice = 0;// for(let i in this.books){//     sumprice += this.books[i].price * this.books[i].count;// }// return sumprice// 3.of循环let sumprice = 0;for(let item of this.books){sumprice += item.price * item.count;}return sumprice}
编程范式 命令式编程 声明式编程
编程范式

面向对象编程

(第一公民:对象)

函数式编程

(第一公民:函数)

  • 高阶函数:函数所需要的参数也是函数
  • filter / map / reduce高级方法(数组):
    1. filter的使用,用于过滤数值,不改变数值

nums = [12 , 333 , 34 , 55 , 133 ]

let new3Nums = nums.filter(function(n) {

return n < 100

})

console.log(new3Nums)    //打印[12 , 34 , 55 ]

2.map的使用,一般用于数值操作,不过滤数值

let new4Nums = new3Nums.map(function(n) {

return n * 2

})

console.log(new4Nums);    //打印[24 , 68 , 110 ]

3.reduce应用,用于数组求和:

let total2 = new4Nums.reduce(function(total, num) {

return total + num;

})

console.log(total2);    //打印24+68+110的和

4.命令式和高级函数对比代码:

        const nums = [10, 20, 44, 66, 888, 123, 55, 75, 111];
//1.取出所有小于100的数字let newNums = [];for (let n of nums) {if (n < 100) {newNums.push(n)}}console.log(newNums);
//2.将所有小于100的数字进行转化:全部*2let new2Nums = [];for (let n of newNums) {new2Nums.push(n * 2);}console.log(new2Nums);
//3.将所有num2Nums数字相加,得到最终结果let total = 0for (let n of new2Nums) {total += n;}console.log(total);
//4.filter,根据条件筛选,不能改变值let new3Nums = nums.filter(function(n) {return n < 100})console.log(new3Nums);
//5.map,不做筛选,改变值let new4Nums = new3Nums.map(function(n) {return n * 2})console.log(new4Nums);
// 6.reducelet total2 = new4Nums.reduce(function(total, num) {return total + num;})console.log(total2);
//7.一行代码搞定,函数式编程let total3 = nums.filter(function(n) {return n < 100}).map(function(n) {return n * 2}).reduce(function(total, num) {return total + num;})console.log(total3);
//8.一行代码搞定——箭头函数let total4 = nums.filter(n => n < 100).map(n => n * 2).reduce((total, num) => total + num);console.log(total3);

02.(掌握)v-model的使用和原理

  • v-model指令来实现表单元素和数据的双向绑定
  • v-bind指令是单向绑定,只能从数据传到表单,表单的值改变不能改变message的值
1.双向绑定,可以接收和改变message:<input type="text" v-model="message"><h2>message:{{message}}</h2>
2.单向绑定,只能接收不能改变message:<input type="text" :value="message">
3.人为单向绑定,只改变不接收,2+3合起来就是v-model<input type="text" v-on:input="valueChange">
4.手动双向绑定:<input type="text" :value="message" @input="message=$event.target.value"></div><script src="./js/vue.js"></script><script>const app = new Vue({el: '#app',data: {message: '龙猫'},methods: {valueChange(event) {this.message = event.target.value;}}});</script>

03.(掌握)v-model结合radio类型使用

  • 二选一的时候和value有关
  • 单选多时候是boolean
        <label for="male"><input type="radio" id="male"  value="男" v-model="sex">男</label><label for="female"><input type="radio" id="female"  value="女" v-model="sex">女</label><h2>你选择的性别是:{{sex}}</h2><h1>单选框:</h1><label for="agree"><input type="checkbox" id="agree" v-model="isAgree">同意</label><h2>你选择的是:{{isAgree}}</h2><button :disabled="!isAgree">下一步</button>
......data:{sex:'男',isAgree:false},

04.(掌握)v-model结合checkbox类型

  • 多选多时候绑定的是数组
        <h1>多选框:</h1><input type="checkbox" value="篮球" v-model="hobbies">篮球<input type="checkbox" value="钢琴" v-model="hobbies">钢琴<input type="checkbox" value="跳舞" v-model="hobbies">跳舞<h2>你的爱好是:{{hobbies}}</h2>...var app=new Vue({el:'#app',data:{hobbies:[],},});

05.(掌握)v-model结合select类型使用

  • 多选的时候加multiple
    <div id="app"><h2>选择一个:</h2><select name="abc" id="" v-model="fruit"><option value="苹果" >苹果</option><option value="香蕉" >香蕉</option><option value="梨" >梨</option><option value="榴莲" >榴莲</option></select><h2>{{fruit}}</h2><h2>选择多个:</h2><select name="abc" id="" v-model="fruits" multiple><option value="苹果" >苹果</option><option value="香蕉" >香蕉</option><option value="梨" >梨</option><option value="榴莲" >榴莲</option></select><h2>{{fruits}}</h2></div><script src="../js/vue.js"></script><script>var app=new Vue({el:'#app',data:{fruit:'榴莲',fruits:[]},});</script>

06.(掌握)input中的值的绑定

  • v-for实现多选
        <h1>v-for:</h1><label v-for="item in originHobbies" :for="item"><input type="checkbox" :value="item" v-model="hobbies">{{item}}</label><h2>{{hobbies}}</h2>var app=new Vue({el:'#app',data:{hobbies:[],originHobbies:["篮球","钢琴","跳舞","瑜伽","游泳"],},});

07.(掌握)v-model修饰符的使用

  1. .lazy回车之后才会改变message值
  2. .number让输入的值由字符串改为number类型
  3. trim去除两端多余空格
 <div id="app"><h1>1.修饰符lazy</h1><input type="text" v-model.lazy="message"><h2>{{message}}</h2><h1>2.修饰符number</h1><input type="number" v-model.number="age"><h2>{{typeof age}},{{age}}</h2><h1>3.trim去除空格</h1><input type="text" v-model.trim="name"><h2>{{name}}</h2></div><script src="../js/vue.js"></script><script>var app=new Vue({el:'#app',data:{message:'',age:18,name:''},methods:{}});</script>

08.(掌握)组件化的使用和实现步骤

09. (掌握)组件化的基本使用过程

  1. 创建组件构造器对象
  2. 注册组件
  3. 使用组件
    <div id="app"><h2>我是内容</h2><p>我是内容1111</p><p>我是内容2222</p><h2>我是内容</h2><p>我是内容1111</p><p>我是内容2222</p>
<!-- 3.使用组件 --><my-cpn></my-cpn><my-cpn></my-cpn></div><script src="../js/vue.js"></script><script>
//1.创建组件构造器对象const cpnC = Vue.extend({template:`<div><h2>我是内容</h2><p>我是内容3333</p><p>我是内容4444</p></div>`});
//2.注册组件Vue.component('my-cpn',cpnC);var app=new Vue({el:'#app',data:{},methods:{}});</script>

10.(掌握)全局组件和局部组件

  • Vue CLI3.x 构建Vue项目的
  • 使用组件必须在app元素内

  • 全局组件和局部组件
  • 全局组件:Vue.component('my-cpn',cpnC); app1和app2都可以使用
  • 局部组件:components:{ my_cpn:cpnC }, /只能在对应的app下面使用,my_cpn使用组件的标签名, 是在vue实例中创建的,开发中用局部组件比较多。
  • 注意:组件名不能大写
    <div id="app"><!-- <my-cpn></my-cpn> --><my_cpn></my_cpn></div><div id="app2"><!-- <my-cpn></my-cpn> -->局部组件不能在这里使用:<!-- <my_cpn></my_cpn> --></div><script src="../js/vue.js"></script><script>//1.全局组件const cpnC = Vue.extend({template:`<div><div>我是标题</div><p>我是内容</p></div>`})//全局组件,可以在多个vue的实例下面使用 //Vue.component('my-cpn',cpnC);var app=new Vue({el:'#app',data:{},components:{//局部组件,只能在对应的app下面使用,my_cpn使用组件的标签名my_cpn:cpnC},methods:{}});var app2=new Vue({el:'#app2',data:{},methods:{}});</script>

11.(掌握)父组件和子组件的区分

  • 父组件也可以套子组件(套娃):Vue.extend({... conponents:{cpn1:cpnC1}})
  • new Vue({});也可以看成是最顶层的组件(root),里边也可以有template属性
    <div id="app"><cpn2></cpn2>
<!-- 下边这个会报错,因为要么全局注册,要么组件中注册过局部的 --><cpn1></cpn1></div><script src="../js/vue.js"></script><script>const cpnC1 = Vue.extend({template:`<div><h2>我说标题1</h2><p>我说内容1</p> </div>`});const cpnC2 = Vue.extend({template:`<div><h2>我说标题2</h2><p>我说内容2</p> <cpn1></cpn1></div>`,components:{cpn1:cpnC1}});var app=new Vue({el:'#app',data:{},components:{cpn2:cpnC2},methods:{}});</script>

12.(掌握)注册组件的语法糖写法

  • 语法糖省去了调用Vue.extend()带步骤,可以直接使用一个对象代替

<div id="app"><cpnc1></cpnc1><cpnc2></cpnc2></div><script src="../js/vue.js"></script><script>//1.创建组件的构造器// const cpn1 = Vue.extend()//2.注册组件(语法糖):Vue.component('cpnc1',{template:`<div><h2>我是标题1</h2><p>我是内容1</p></div>`})var app=new Vue({el:'#app',data:{},components:{cpnc2:{template:`<div><h2>我是标题2</h2><p>我是内容2</p></div>`}},methods:{}});</script>

13.(掌握)组件模板抽离的写法

  • 模板分离的第一种写法:
  • 模板分离的第二种写法:    ,第二个比较好,用得多
<div id="app"><cpn1></cpn1><cpn2></cpn2></div><!-- 1.模板分离的写法 --><script type="text/x-template" id="cpnC1"><div><h2>模板分离1</h2><p>我是内容1</p></div></script>
<!--2.模板分离的第二种写法 --><template id="cpnC2"><div><h2>模板分离2</h2><p>我是内容2</p></div></template><script src="../js/vue.js"></script><script>Vue.component('cpn1',{template:'#cpnC1'})Vue.component('cpn2',{template:'#cpnC2'})var app=new Vue({el:'#app',data:{},methods:{}});</script>

14.(理解)为什么组件data必须是函数

  • 组件内部不能访问vue实例中的内容的:

    {{title}}

    ......data:{title:"我是标题"}

  • 如果想访问,必须加data(){return {}}: Vue.component('cpn1',{
                template:'#cpnC1',
                data(){
                    return {
                        title:"我是标题",
                        con:"我是内容"
                    }
                }
            })
    <div id="app"><cpn1></cpn1></div><template id="cpnC1"><div><!-- 下边title不能访问实例数据 --><h2>{{title}}</h2><p>{{con}}</p></div></template><script src="../js/vue.js"></script><script>Vue.component('cpn1',{template:'#cpnC1',data(){return {title:"我是标题",con:"我是内容"}}})var app=new Vue({el:'#app',data:{
//以下这种写法错误//title:"我是标题"},methods:{}});</script>
  • let obj1 = abc();和let obj2 = abc();并不是一个对象,指向的地址也不一样,因此,data(){return {count:0}}每次返回的count(局部变量)是不同对象的count,互不冲突,如果用data():{count:obj},就会冲突:

    <div id="app"><!-- 组件实例对象 --><cpn1></cpn1><cpn1></cpn1><cpn1></cpn1></div><template id="cpnC1"><div><button @click="sub">-</button><span>{{count}}</span><button @click="add">+</button></div></template><script src="../js/vue.js"></script><script>//1.创建组件Vue.component('cpn1',{template:'#cpnC1',data(){//每次调用的时候,return一个新的对象,这样避免的用同一个count导致的冲突//注:这里return的对象是局部变量,每次是不一样的,如果外边定义个obj穿过来,就会导致冲突了(使用同一个count)return {count:0}},methods:{sub(){this.count--},add(){this.count++}}})var app=new Vue({el:'#app',data:{},});</script>

15.(掌握)父子组件通信-父传子

  • 父传子:通过props向子组件传递数据(properties属性)
  • 子传父:自定义emit事件
  • 理解:属性向下传,方法向上传
  • 说明:new Vue({})相当于根组件

  1. 父传子 (props的值有多种类型:对象、数据、字符串、布尔、数值等等)
    <div id="app"><cpn :cmovies="movies" :cmessage="message"></cpn></div><template id="cpnC1"><div><ul><li v-for="item in cmovies">{{item}}</li></ul><p>{{cmessage}}</p></div></template><script src="../js/vue.js"></script><script>const cpn = {template:'#cpnC1',// props:['cmovies','cmessage'],//开发中数组的写法比较少//props不止是数组,还可以是对象、字符串、布尔、数组点等,如:props:{//1.类型限制// cmovies:Array,// cmessage:String//2.提供一些默认值cmovies:{type:Array,default(){  //类型是对象或者数组时,默认值必须是一个函数return []}},cmessage:{type:String,default:'aaa',required:true   //使用组件的时候,必须传cmessage属性}},data(){return {}},methods:{}}var app=new Vue({el:'#app',data:{movies:['龙猫','千与千寻','天空之城'],message:'你好'},components:{// cpn:cpncpn //增强写法},});</script>

16.(掌握)父子组件通信-props驼峰标识

  • props里边要用驼峰命名(cInfo),外边使用组件的时候,要用-号(c-info)
  • 知识点补充:js大小写敏感,html大小写不敏感
  • 父组件传递数据的过程:1,父组件data中准备数据,2,子组件的构造器添加props,包括需要用到的变量,在template中使用这些变量,3,在vue实例中把这两项绑定起来
    <div id="app"><cpn :c-info="info" :child-my-message="childmymessage"></cpn><!-- 下面这个写只输出默认值{} --><!-- <cpn></cpn> --></div><template id="cpn"><div><h2>{{cInfo.name}}</h2><h2>{{cInfo.age}}</h2><h2>{{cInfo.height}}</h2><h2>{{childMyMessage}}</h2></div></template><script src="../js/vue.js"></script><script>const cpn = {template:'#cpn',props:{cInfo:{type:Object,default(){return {}}},childMyMessage:{type:String} }}var app=new Vue({el:'#app',data:{info:{name:"龙猫",age:2,height:2.88},childmymessage:"aaaa",},components:{cpn},methods:{}});</script>

17.(掌握)父子组件通信-子传父(自定义事件)

  • 使用场景:1,购物网站列表中选择手机,会向父级发消息说点击了谁,然后父级再回转手机的数据;
  • 传递过程:1,子组件中通过$emit()来触发事件,2,父组件中v-on来监听子组件事件

  • 注:父组件中的方法不要写参数,默认在子组件模版中已经定义了,不能写cpnClick(item),只能写cpnClick

 <!-- 父组件模板 --><div id="app"><!-- 不能写cpnClick(item) 相当于之前的@click="btnClick"默认会传递event事件,这里默认传item --><cpn1 @item-click="cpnClick"></cpn1></div><!-- 子组件模板 --><template id="cpn"><div><button v-for="item in categories" @click="btnClick(item)">{{item.name}}</button></div></template><script src="../js/vue.js"></script><script>//1.子组件const cpn1 = {template:'#cpn',data(){return {categories:[{id:'aaa',name:'热门推荐'},{id:'bbb',name:'手机数码'},{id:'ccc',name:'家用家电'},{id:'ddd',name:'电脑办公'},]}},methods:{btnClick(item){// 自定义事件item-click,相当于之前的reset-map//传递过程:1,子组件中通过$emit()来触发事件,2,父组件中v-on来监听子组件事件this.$emit('item-click',item)}}}//2.父组件var app=new Vue({el:'#app',data:{},components:{cpn1},methods:{cpnClick(item){console.log(item);}}});</script>
  • 计数器小案例,把子组件中的count传递给父组件total:
    <div id="app"><cpn @cpn-sub="changeTotal" @cpn-add="changeTotal"></cpn><h2>{{total}}</h2></div><template id="cpn"><div><button @click="sub">-</button><button @click="add">+</button></div></template><script src="../js/vue.js"></script><script>const cpn = {template:'#cpn',data(){return {count:0}},methods:{sub(){this.count--;this.$emit('cpn-sub',this.count)},add(){this.count++;this.$emit('cpn-add',this.count)}}}var app=new Vue({el:'#app',data:{total:0},components:{cpn},methods:{changeTotal(count){this.total = count}}});</script>

18.(了解)项目展示

  • template和JavaScript代码相互分离

19.(了解)知识回顾


04day


01.(掌握)父子组件通信-结合双向绑定案例

  • 子组件使用v-model案例
  • v-model相当于v-bind:value和@input="$event.target.value"的结合,也就是set方法
    <div id="app"><cpn :number1="num1" :number2="num2" @num1-change="changeNum1"@num2-change="changeNum2"></cpn></div><template id="cpn"><div><h2>props:{{number1}}</h2><h2>data:{{dnumber1}}</h2><!-- <input type="text" v-model="dnumber1"> --><input type="text" :value="dnumber1" @input ="num1Input"><h2>props:{{number2}}</h2><h2>data:{{dnumber2}}</h2><!-- <input type="text" v-model="dnumber2"> --><input type="text" :value="dnumber2" @input ="num2Input"></div></template><script src="../js/vue.js"></script><script>var app=new Vue({el:'#app',data:{num1:1,num2:0},components:{cpn:{template:'#cpn',props:{number1:{type:Number},number2:{type:Number},},data(){return {dnumber1:this.number1,dnumber2:this.number2}},methods:{num1Input(){//1.input中的value复制到dnumber1中this.dnumber1 = event.target.value;//2.为了让父组件可以修改值,发出一个事件this.$emit('num1-change',this.dnumber1);//3.让number2和dnumber2的值是1的100倍this.dnumber2 = this.dnumber1 * 100;this.$emit('num2-change',this.dnumber2)},num2Input(){this.dnumber2 = event.target.value;this.$emit('num2-change',this.dnumber2);//3.让number2和dnumber2的值是1的100倍this.dnumber1 = this.dnumber2 / 100;this.$emit('num1-change',this.dnumber1)},}},},methods:{changeNum1(value){this.num1 = parseInt(value);},changeNum2(value){this.num2 = parseInt(value);}}});</script>

02.(掌握)上边代码的图示:

03.(了解)结合双向绑定案例-watch实现

  • watch可以监听某一个属性的改变
  • watch是实时监听属性变化,computed是计算属性,计算完后有一个缓存。而methods监听触发事件的。
  • watch是监听变化的,不变化不触发
    <div id="app"><cpn :number1="num1" :number2="num2" @num1-change="changeNum1"@num2-change="changeNum2"></cpn></div><template id="cpn"><div><h2>props:{{number1}}</h2><h2>data:{{dnumber1}}</h2><!-- <input type="text" v-model="dnumber1"> --><input type="text" v-model="dnumber1"><h2>props:{{number2}}</h2><h2>data:{{dnumber2}}</h2><!-- <input type="text" v-model="dnumber2"> --><input type="text" v-model="dnumber2"></div></template><script src="../js/vue.js"></script><script>var app=new Vue({el:'#app',data:{num1:1,num2:0},components:{cpn:{template:'#cpn',props:{number1:Number,number2:Number,},data(){return {dnumber1:this.number1,dnumber2:this.number2}},watch:{dnumber1(newValue){this.dnumber2 = newValue * 100;this.$emit('num1-change',newValue)},dnumber2(newValue){this.dnumber1 = newValue / 100;this.$emit('num2-change',newValue)},},},},methods:{changeNum1(value){this.num1 = parseInt(value);},changeNum2(value){this.num2 = parseInt(value);}}});</script>

04.(掌握)父组件访问子组件-$children-$refs

  • 父组件访问子组件两种方式
  • 注意:refs是渲染结束后才能拿到,不能在初始化的时候访问
第一种(用得少) 第二种(用的非常多)
$children $refs       (refs:reference引用的意思)
结果是个数组,下标志拿数据方式不太好,因为子组件数量可能会变化,下标的索引值会变 结果是个对象,可以给每个组件添加一个ref属性设置唯一性
    <div id="app"><cpn ref="aaa"></cpn><cpn ref="bbb"></cpn><cpn ref="ccc"></cpn><button @click="btnClick">按钮</button></div><template id="cpn"><div>我是子组件</div></template><script src="../js/vue.js"></script><script>var app=new Vue({el:'#app',data:{},methods:{btnClick(){// 一、$children结果是个数组,用得很少//1,取子组件的方法,下标志拿数据方式不太好,因为子组件数量可能会变化this.$children[0].showMessage();//0代表第一个子组件// //2,取子组件的数据console.log(this.$children[0].name); // //3,或者循环遍历for(let item of this.$children){item.showMessage();console.log(item.name);    }//二、$refs结果是个对象,用的非常多this.$refs.aaa.showMessage();    console.log(this.$refs.aaa.name);    }},components:{cpn:{template:'#cpn',data(){return {name:"我是子组件的内容"}},methods:{showMessage(){console.log('message');}}}}});</script>

05.(了解)子访问父-parent-root

  • this.$parent和this.$root用得也非常少
    <div id="app"><cpn></cpn></div><template id="cpn"><div><h2>我是子组件</h2><button @click="btnClick">按钮</button></div></template><script src="../js/vue.js"></script><script>var app=new Vue({el:'#app',data:{message:'父组件message'},components:{cpn:{template:'#cpn',methods:{btnClick(){//1,this.$parent返回的不是组件(VueComponent),而是实例(Vue),用的非常少console.log(this.$parent.name);//2,this.$root可以访问父,也可以访问父亲父父亲,返回实例对象console.log(this.$root);}}}},methods:{}});</script>

06.(掌握)slot插槽的基本使用

  • 插槽就是预留的空间,一般抽取共性,保留插槽
  • 使用案例:

  • 使用过程:template里加入,也可以设置默认值按钮
    <div id="app"><cpn><button>按钮</button></cpn><cpn><span>span标签</span></cpn><cpn></cpn><cpn></cpn></div><template id="cpn"><div><!-- 这种定义的组件不具有扩展性,如仅对第一个<cpn></cpn>组件的<p>后加一个span或者button标签--><h2>我是组件标题</h2><p>我是组件内容</p><!-- 下边插槽内加<button>按钮</button>可以设置插槽默认值 --><slot><button>按钮</button></slot></div></template><script src="../js/vue.js"></script><script>var app=new Vue({el:'#app',data:{},components:{cpn:{template:'#cpn',}},methods:{}});</script>

07.(掌握)具名插槽的使用

  • 当有多个slot,想改变某一个值的时候,如京东导航栏,模板设置name:中间,父组件标题:
    <div id="app"><!-- 1.不替换 --><cpn></cpn><!-- 2.只会把没有名字的替换掉 --><cpn><span>标题</span></cpn><!-- 3.只会替换center的slot --><cpn><span slot="center">标题</span></cpn></div><template id="cpn"><div> <slot name="left"><span>左边</span></slot><slot name="center"><span>中间</span></slot><slot name="right"><span>右边</span></slot><slot><span>右边</span></slot></div></template><script src="../js/vue.js"></script><script>var app=new Vue({el:'#app',data:{},components:{cpn:{template:'#cpn',}},methods:{}});</script>

08.(理解)编译作用域的概念

  • 不关心组件,只关心在那个app里,只会使用vue实例里边的isShow

    <div id="app"><cpn v-show="isShow"></cpn></div><template id="cpn"><div><h2>我是标题</h2><p>我是内容</p></div></template><script src="../js/vue.js"></script><script>var app=new Vue({el:'#app',data:{isShow:true    //使用的是这里的isShow},components:{cpn:{template:'#cpn',data(){return {isShow:false}}}},methods:{}});</script>

09.(掌握)作用域插槽的使用

  • 需求:在渲染之前,把组件的数据传给vue实例(渲染之后一般用this.$refs.name)
  • 即,父组件对子组件的展示方式不满意,想以另外一种方式展示
  • 总结:父组件替换插槽的标签,但是内容由子组件来提供
    <div id="app"><!-- 1.不改变template,直接显示 --><cpn></cpn><!-- 2.不想用列表的方式,想用-连接字符串 --><cpn><template slot-scope="slot"><!-- <span v-for="item in slot.data">{{item}} - </span> --><span>{{slot.data.join('-')}}</span></template></cpn></div><template id="cpn"><div><slot :data="pLanguages"><ul><li v-for="item in pLanguages">{{item}}</li></ul></slot></div></template><script src="../js/vue.js"></script><script>var app=new Vue({el:'#app',data:{},components:{cpn:{template:'#cpn',data(){return {pLanguages:['Javascript','c++','Java','Python','go','swift','c#']}}}},methods:{}});</script>

10.(了解)前端代码复杂带来的问题

  • 如小明在a.js文件中定义var flag = true;小红在b.js定义var flag = false;当小明在c.js使用if(flag){}时可能会传小红的flag
  • 解决方法匿名函数,即闭包。闭包的核心理念是用函数的变量作用域控制来完成javascript所缺失的块作用域功能:
  • 闭包的缺点导致的代码的复用性不高,如下边的sum函数在别的js文件中访问不到,因此闭包也不行
(function(){var flag = true;function sum(num1,num2){return num1+num2}
})()

11.(理解)前端模块化雏形和CommonJS

  • 只能用模块化解决(如下a.js),就可以在c.js使用if(moduleA.flag){},下边这种就是模块化思想,但是已经不用了
  • 常见的模块化规范:CommonJS,AMD,CMD,ES6的Modules
var moduleA = (function(){var obj = {};var name = '小明';var age = 18;function sum(num1,num2){return num1 + num2}var flag = true;// if(flag){//     console.log(sum(10,20));// }obj.name = name;obj.age = age;obj.flag = flag;obj.sum = sum;obj.myFunction = function(value){console.log(value)}return obj
})()
  • CommonJS了解
//a.js导出
module.exports = {name:ws,flag:true,sum(a,b){return a+b}
}//b.js导入,导入名字要和导出的名字一样
let {name, sum, flag} = require('./a.js');
//上边等同于下边
let mod = require('./a.js');
let name = mod.name;
let flag = mod.flag;
let sum = mod.sum;

12.(掌握)ES6模块化的导入和导出

  • 可以使用type="module"把js变成块级作用域,解决变量冲突问题:
  • 但是这样带来了新的问题,其他模块想使用该块内的变量,访问不到:
//index.html
//    <script src="./aaa.js" type="module"></script>
//    <script src="./bbb.js" type="module"></script>
//    <script src="./ccc.js" type="module"></script>//aaa.js//小明
var name = 'xiaoming';
var age = 18;
var flag = true;
function sum(a , b){return a+b
}
if(flag){console.log(sum(11,2));
}//bbb.js//小红
var name = 'xiaohong';
var age = 19;
var flag = false;//ccc.js 报错,flag未定义
if(flag){console.log('flag');
}
  • 解决方案:模块导出(3种方法)
  1. 方法1,先定义变量、函数或class,再导出:export { flag,sum,Person}

  2. 方法2,直接导出:export var num1 = 100001;   export function sum(a,b){return a+b};  export class Person{run(){console.log("在奔跑")}}

  3. 方法3,export default name;  import myName from "./aaa.js",用于导入者自己可以修改名字,但是export default只能在一个js中使用一次

  4. 前两种导入方法一样:import {flag , sum,num1 , Person} from "./aaa.js"或import * as obj from "./aaa.js"  然后obj.flag可以取值

//index.html//<script src="./aaa.js" type="module"></script>//<script src="./bbb.js" type="module"></script>//<script src="./ccc.js" type="module"></script>//aaa.js
var name = 'xiaoming';
var age = 18;
var flag = true;
function sum(a , b){return a+b
}
if(flag){console.log(sum(11,2));
}
//1.导出方式一:
export{flag,sum
}
//2.导出方式二:
export var num1 = 100001;
export var height = 1.88;
export class Person{run(){console.log("在奔跑");}
}
//3.导出方式三:
var address = '北京市';
export default address;//ccc.js
import {flag , sum} from "./aaa.js"
if(flag){console.log('flag');console.log(sum(111,222));
}
import {num1 , height ,Person} from "./aaa.js"
console.log(num1);
console.log(height);
let ws = new Person();
ws.run();
import myAdd from "./aaa.js"
console.log(myAdd);
import * as obj from "./aaa.js"
console.log(obj.height);

13.(理解)webpack的介绍和安装

  • webpack就是一个模块打包工具

  • webpack打包现在用的比较多,而gulp用的比较少了,grunt更没人用了
  • 什么时候用gulp和webpack

  • webpack和node、npm关系:

  • 注意:Mac安装webpack要先获取权限,使用sudo -s然后输入计算机密码,最后npm install webpack@3.6.0 -g

14.(掌握)webpack的基本使用过程

  • 使用目的代码打包到dist文件夹中,方法一的过程(方法二是配置webpack.config.js,见15):
  1. 全局安装webpack(npm install webpack@3.6.0 -g),终端定位到项目的根目录中
  2. webpack ./src/main.js ./dist/bundle.js 意思是把main.js打包到dist文件夹下的bundle.js文件中,至于main.js里边的依赖会由webpack自动处理
  3. index.html中引用bundle.js,,执行index.html
  4. 代码:
//index.html
//<script src="./dist/bundle.js"></script>//main.js
//1.common.js导入
let {sum ,mul} = require('./mathUtils.js');
console.log(sum(11,3));
console.log(mul(22,10));
//2.ES6导入
import {name , age , height} from './info';
console.log(name);
console.log(age);
console.log(height);//mathUtils.js
function sum(num1,num2){return num1 + num2
}
function mul(num1,num2){return num1 * num2
}
//1.common.js导出
module.exports = {sum,mul
}//info.js
//2.ES6导出
export const name = 'xiaoming';
export const age = 18;
export const height = 1.88;

15.(掌握)webpack.config.js和package.json的配置

  • 代码打包的方法二:
  1. (第一层映射)新建webpack.config.js文件(如下),输入打包的参数(如入口、出口);2.运行命令:webpack
  2. (第二层映射)执行npm init 命令,在package.js文件加"build":"webpack"    //本句加完之后,能用npm run build替代webpack命令
//webpack.config.js文件
const path = require('path');//'path'是node的系统模块
module.exports = {entry:'./src/main.js',output:{path:path.resolve(__dirname,'dist'),filename:'bundle.js'}
}
  • 注意:const path = require('path') ,括号内的path是node的系统模块,__dirname是node上下文自带的全局变量
  • 运行webpack一般需要依赖node环境的项目,都会有package.json文件(项目的信息,如下),该文件的配置命令:npm init
//package.js文件
{"name": "meetwebpack","version": "1.0.0","description": "","main": "index.js","scripts": {"test": "echo \"Error: no test specified\" && exit 1","build":"webpack"    //本句加完之后,能用npm run build替代webpack命令},"author": "","license": "ISC"
}
  • 刚刚的webpack是全局安装的(npm install webpack@3.6.0 -g),但是开发的时候每个项目都要有自己的本地的webpack(npm install webpack@3.6.0 --save-dev),因为二者版本可能不一样

——只要是在终端敲webpack,用的都是全局的,想使用本地的必须./node_modules/.bin/webpack

——所以定义"build":"webpack" 的好处是执行npm run build时,优先找本地的webpack

16.(掌握)webpack中使用css文件的配置(loader)

  • loader干什么的?:因为webpack除了要打包js以外,还要对css、图片、ES6、Vue等进行打包,这时候webpack就不支持了,需要对webpack扩展loader就可以了

    • loader使用过程:1.安装loader:npm install --save-dev css-loader@2.0.2   2.webpack.config.js配置module.exports={}  3.安装css-loader(可以去webpack官网看安装命令和配置说明):npm install style-loader --save-dev
    • css-loader只负责加载,不负责解析,需要再安装style-loade(样式添加到dom中)

const path = require('path');
module.exports = {entry: './src/main.js',output: {path: path.resolve(__dirname, 'dist'),filename: 'bundle.js',publicPath: '../dist/' //涉及到url的东西,都会再前边拼接dist/},module: {rules: [{test: /\.css$/i,use: ["style-loader", "css-loader"],}, {test: /\.less$/i,loader: [// compiles Less to CSS"style-loader","css-loader","less-loader",],}, {test: /\.(png|jpg|gif)$/i,use: [{loader: 'url-loader',options: {//当加载的图片小于limit时,会将图片编译成base64位字符串形式//当加载的图片大于limit时,需要使用file-loader模块进行加载limit: 8192,},}, ],}],},
}

04day


01.(掌握)webpack-less文件的打包less-loader

  • 1.预处理:写*.less文件,引入到main.js(目的是打包less格式的样式文件)
  • 2, npm install --save-dev less-loader@4.1.0 less@3.9.0
  • 3,配置webpack.config.js(详见03-16)
  • 4.npm run build

02.(掌握)webpack图片文件的打包url-loader

  • 1.预处理:css加背景图,引入到main.js
  • 2.npm install --save-dev url-loader@1.1.2 (图片小于limit尺寸)或者npm install file-loader@3.0.1 --save-dev(图片大于limit)
  • 3,配置webpack.config.js(详见03-16),output中添加publicPath: '../dist/' ,涉及到url的东西,都会再前边拼接dist/
  • 4.npm run build

03.(掌握)webpack ES6转ES5的babel-loader

  • 需求:由于打包后的文件还是ES6,并没有转成ES5,有些浏览器并不能运行,所以用babel-loader
  • 1.npm install --save-dev babel-loader@7 babel-core babel-preset-es2015 ; 2.配置webpack.config.js:
{test: /\.m?js$/,exclude: /(node_modules|bower_components)/,use: {loader: 'babel-loader',options: {presets: ['es2015']}}}

04.(掌握)webpack-使用vue的配置过程

  • import {name,age} from './js/info.js'有路径,而import Vue from 'vue',没写路径,就从node_modules library root里边拿;
  • npm install vue --save 不需要加-dev因为加dev是开发时依赖,而vue时整个项目就要依赖;
  • 项目里直接使用vue的过程:
1.npm install vue --save
2.webpack.config.js配置:
resolve:{//alias别名alias:{'vue$':'vue/dist/vue.esm.js' //这个指定的有compiler,默认用的是vue.runtime.js}}
3.npm install vue-loader@13.0.0 vue-template-compiler@2.5.21 --save-dev
4.开始使用new Vue({})
4,npm run build

05.(掌握)创建Vue时template和el的关系

  • 实际开发时index.html里只写 里边不写内容;
  • 而如main.js中的new Vue({el..template})如果同时存在el和template,会自动用template内容替换

06.(掌握)Vue的终极使用方法

  • 第一次抽离,index.html只保留 ,在main.js中写组件:
import Vue from 'vue';
// import { Cpn }  from './vue/app.js'
const Cpn = {template:`<div><h2>{{message}}</h2><button @click="btnClick">按钮</button><h2>{{name}}</h2></div>`,data(){return{message:'hello world',name:'coderwhy'}},methods:{btnClick(){console.log("btnClick");}}
};
  • 第二次抽离,const Cpn对象全部抽到app.js中。下边这个Vue是一个根组件,运行只会template会替换el,new Vue({ el:'#app'})之前的组件都是再 里使用,由于现在index.html不让写东西里,就写到这里用,new Vue本身也是一个根组件,只要是组件都有template属性。
//app.js
import Vue from 'vue';import { Cpn }  from './vue/app.js'
//下边这个Vue是一个根组件,运行只会template会替换el
new Vue({el:'#app',template:'<Cpn/>',   components:{Cpn}
})
  • 第三次抽离,app.js内容全部抽到App.vue中,main.js导入App.js模块实现template-script-style三者相分离:
//App.vue
<template><div><h2 class="title">{{message}}</h2><button @click="btnClick">按钮</button><h2>{{name}}</h2></div>
</template>
<script>
export default {name:Cpn,data(){return{message:'hello world',name:'coderwhy'}},methods:{btnClick(){console.log("btnClick");}}
}
</script><style scoped>
.title{color: green;
}
</style>
  • import Cpn from './Cpn.vue' 的.vue想省略的话,需要需改webpack.config.js:resolve:{extensions:['.js' , '.css' , '.vue']}

07.(掌握)webpack-横幅Plugin的使用-版权声明

  • plugin是插件的意思,通常是用于对某个现有的架构进行扩展。 webpack中的插件,就是对webpack现有功能的各种扩展,比如打包优化,文件压缩等等。
  • loader和plugin区别 loader主要用于转换某些类型的模块,它是一个转换器。 plugin是插件,它是对webpack本身的扩展,是一个扩展器。
  • plugin的使用过程:
  • 步骤一:通过npm安装需要使用的plugins(某些webpack已经内置的插件不需要安装)
  • 步骤二:在webpack.config.js中的plugins中配置插件。
  • 添加版权:const webpack = require('webpack');                   module.exports = {plugins:[new webpack.BannerPlugin('该版权归龙猫所有!')]}

08.(掌握)webpack-HtmlWebpackPlugin的使用

  • HTML打包目的是为了让index.html打包到dist文件夹中,过程:

1.安装 npm install html-webpack-plugin --save-dev 
2. 配置webpack.config.js:

const HtmlWebpackPlugin = require('html-webpack-plugin');
new HtmlWebpackPlugin({template:'index.html'}),加了参数后,为了让原index.html的

引进进来,webpack.config.js:

const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {entry: './src/main.js',output: {path: path.resolve(__dirname, 'dist'),filename: 'bundle.js',// publicPath: '../dist/' //涉及到url的东西,都会再前边拼接dist/},module: {rules: [{test: /\.css$/i,use: ["style-loader", "css-loader"],},{test: /\.less$/i,loader: [// compiles Less to CSS"style-loader","css-loader","less-loader",],}, {test: /\.(png|jpg|gif)$/i,use: [{loader: 'url-loader',options: {//当加载的图片小于limit时,会将图片编译成base64位字符串形式//当加载的图片大于limit时,需要使用file-loader模块进行加载limit: 8192,},}, ],},{test: /\.js$/,// exclude: 排除// include: 包含exclude: /(node_modules|bower_components)/,use: {loader: 'babel-loader',options: {presets: ['es2015']}}},{test: /\.vue$/,use: ['vue-loader']}],},resolve: {// alias: 别名extensions: ['.js', '.css', '.vue'],alias: {'vue$': 'vue/dist/vue.esm.js'}},plugins: [new webpack.BannerPlugin('版权最终归龙猫所有'),new HtmlWebpackPlugin({template: 'index.html' //为了让原index.html的<div id="app"><div>引进进来})]
}

09.(掌握)webpack-UglifyjsWebpackPlugin的使用(压缩js文件)

  1. npm install uglifyjs-webpack-plugin@1.1.1 --save-dev
  2. const UglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin')
  3. plugins: [  new UglifyjsWebpackPlugin()  ]

10.(掌握)webpack-dev-server搭建本地服务器(npm run dev)

过程:

1.npm install --save-dev webpack-dev-server@2.9.3

2.配置webpack.config.js:

devServer:{

contentBase:'./dist',

inline:true,

}

3.配置package.js的script:"dev":"webpack-dev-server",或者script:"dev":"webpack-dev-server --open"默认打开

4.运行npm run dev

11.(掌握)webpack配置文件的分离

  • 需求:开发时和发布时依赖的配置文件不一样,后边脚手架用法哦了,提前了解
  • 分离过程:
  • 1.把webpack.config.js分离成base.config.js、prod.config.js、base.config.js
  • 2.npm install webpack-merge@4.1.5 --save-dev
  • 3.package.json配置:"build": "webpack --config ./build/prod.config.js" , "dev": "webpack-dev-server --open --config ./build/dev.config.js"

发布时base.config.js+prod.config.js  => npm run build

开发时base.config.js+dev.config.js  => npm run dev

//prod.config.js
const UglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin')
const webpackMerge = require('webpack-merge')
const baseConfig = require('./base.config')module.exports = webpackMerge(baseConfig,{plugins:[new UglifyjsWebpackPlugin()]
})
//dev.config.js
const webpackMerge = require('webpack-merge')
const baseConfig = require('./base.config')module.exports = webpackMerge(baseConfig,{devServer:{contentBase:'./dist',inline:true,}
})

coderwhy老师vue.js b站视频教程笔记——第一部分相关推荐

  1. coderwhy老师vue.js b站视频教程笔记——第四部分

    从项目开始 07.(掌握)项目开发-项目创建和github托管 1.项目目录列表有config文件夹是脚手架2,没有的话是脚手架3 2.使用github 2.1 通过拷贝的方式提交代码到github- ...

  2. [译] 使用 Web3 和 Vue.js 来创建你的第一个以太坊 dAPP(第二部分)

    原文地址:Create your first Ethereum dAPP with Web3 and Vue.JS (Part 2) 原文作者:Alt Street 译文出自:掘金翻译计划 本文永久链 ...

  3. 外贸视频教程[外贸人zencart自助建站视频教程]:第一课

    最近研究外贸视频教程,稍微总结一下,以后继续补充: [外贸人zencart自助建站视频教程]:第一课 概况浏览: http://user.qzone.qq.com/1251233090/blog/13 ...

  4. Vue.js的章节记录笔记(详细)

    笔记 Vue.js的概念 下面是MVC和MVVM的关系图解 vue.js的组件化思想是什么? 注册组件的基本步骤 父组件和子组件 注册组件语法糖 模板的分离写法 组件可以访问Vue实例数据吗 为什么组 ...

  5. 学习vue.js的自我梳理笔记

    基本语法格式: <script> new Vue({ el: '#app', data: { url: 'http://www.runoob.com' } }) </script&g ...

  6. Vue.js实战第十章笔记

    10.1前端工程化与webpack Virtual Dom并不是真正意义上的DOM,而是一个轻量级的JavaScript对象,在状态发生变化时,Virtual Dom会进行D 通常,前端自动化(半自动 ...

  7. Vue.js入门(学习笔记)

    说在前头: 本人为大三在读学生,书写文章的目的是为了对自己掌握的知识和技术进行一定的记录,同时乐于与大家一起分享,因本人资历尚浅,发布的文章难免存在一些错漏之处,还请阅读此文章的大牛们见谅与斧正.若在 ...

  8. 《Vue.js实战》读书笔记

    嗯,加油啦!!都是书里的东西,整理了一下,以后复习的时候看. 电子档资源见评论 摘些最近看书的句子: 迪安却不一样,他为了面包和性爱在社会上使劲打拼. 我不知道自己究竟是谁了,我远离家乡,旅途劳顿,疲 ...

  9. Vue.js实战之系统学习第一节

    为什么叫系统学习呢?因为我以前接触过Vue.js,但是没学过它的原理,只是简单的使用了,使用的时候就觉得很好用,没有其他的什么感觉,但当我进入职场后,学习了很多的前端技术后,才发现这个技术的友好,被它 ...

最新文章

  1. javascript(js)的小数点乘法除法问题
  2. 如何做好应急响应工作?常见应急响应流程
  3. System Center 2012与vCenter Operations 产品功能对比
  4. Win10重装系统后更改用户文件夹名称的方法
  5. python3精要(35)-模块(1)-import
  6. ESP32连接亚马逊你不得不知道的坑
  7. Promise第二篇:你需要记着的API
  8. ZeroClipboard的时代或许已经过去了
  9. java 继承 子类 实例化_关于Java继承中父类和子类构造函数的问题
  10. 大神开发的模板框架 包括常见的功能
  11. display:none与visibility:hidden的区别 ,还有html5的新属性hidden
  12. linux夸分区建立软链接,Linux硬链接和软链接
  13. java map clone,map.putall()和map.clone()方法有什么区别?
  14. 自动驾驶仿真(一)—— 基于CarSim与Simulink的ABS系统仿真
  15. linux环境编程apue和unp,《APUE》和《UNP》文件的编译和使用(转载)
  16. 【转帖】龙芯3A3000处理器深度评测:和Intel、AMD差距巨大
  17. C# DLL HRESULT:0x8007000B
  18. ROCKCHIP UART开发指南
  19. 国家图书馆认证中国长峰制定的《婴幼儿血管瘤临床路径》
  20. 美团优选总显示服务器403,最新提示!美团优选商家端登录入口

热门文章

  1. flexpaper文档
  2. 小程序中 input输入框上面定位的元素真机测试点击事件不生效
  3. 服务器mysql 修改数据库密码怎么修改,服务器mysql修改数据库密码
  4. 使用python做tf-idf算法实践
  5. 海思开机Logo的使用
  6. Linux基础——”shell脚本编程“ 你知道自动轰炸脚本怎么来的吗?
  7. 北漂程序员,年收入200万却想辞职,幸福感为0却放不下家庭
  8. 微软 Windows 11 正式发布!不仅完美运行 Android 应用,还迎来超多重磅功能
  9. 文科生也能搞定的深度学习漫画(下)
  10. 前端入门知识点之html标签