MVC 主要是后端的分层开发思想;把 一个完整的后端项目,分红了三个部分:javascript
1. 注意:Vue中,不推荐程序员手动操做DOM元素;因此,在Vue项目中,没有极其变态的需求,通常不要引入 Jquery;
2. Vue代码解析执行的步骤:
1. 当 VM 实例对象,被 建立完成以后,会当即解析 el 指定区域中的全部代码;
2. 当 VM 在解析 el 区域中全部代码的时候,会把 data 中的数据,按需,填充到 页面指定的区域;
3. 注意:每当 vm 实例对象,监听到 data 中数据发生了变化,就会当即 从新解析 执行 el 区域内,全部的代码;
复制代码
<!-- 1.导入vue的包 -->
<!-- 只要导入了vue的包,在window全局会挂载Vue成员(构造函数) --> <script src="./lib/vue-2.5.16.js"></script> </head>
<body>
<!--2. 放一个id为app的div,未来new 出来的vue实例会控制这个div内部的代码 --> <!-- 注意:不能vm实例对象直接控制body或者是html--> <div id="app"> <h3>{{msg}}</h3> </div> <script> // 3new 一个Vue,建立Vue的实例对象 // new出来的vm实例对象就是mvvm中的 vm const vm=new Vue({ // 指定new 出来的vm实例要控制页面上的哪一个区域 el:'#app',//这个vm中指定的区域就是mvvm中view data:{//指定被控制的区域,要用到的数据 msg:'Hello Vue.js' }//这个data指向对象就是mvvm 中的model }); // function Person(obj){ // this.name=obj.name; // this.age=obj.age; // } // const p1=new Person({name:'zs',age:20}); </script> </body>
复制代码
定义:Vue中,经过一些特殊的用法,扩展了HTML的能力
复制代码
<p>{{msg}}</p>
复制代码
注意:指令是框架中提出的概念,扩展了html的能力,指令若是想要生效就必须被vm实例对象所解析
复制代码
<div id="app">
<h3>{{msg}}</h3>
<h3>{{1+1}}</h3>
<h3>{{boo ? '条件为真':'条件为假'}}</h3>
<h3>{{msg.length}}</h3>
<!--注意插值表达式只能在内容区域,不能在属性节点里面-->
<h3>{{arr}}</h3>
<!--不能写循环等语句-->
</div>
<script>
const vm=new Vue({
el:'#app',
data: {
msg:'Hello Vue.js',
boo:false,
arr:[1,2,3]
},
});
</script>
复制代码
var vm = new Vue({
delimiters:['$','#'],//把插值表达中的双花括号换成是指定的,可是通常不推荐
el: '#app',
data: {
city: '北京',
people: 2000
}
})
复制代码
5.对于自增和自减运算会出现异常,因此这里暂时不推荐在插值表达中使用自增自减元素。css
[v-cloak]{
display: none;
}
复制代码
1.基本使用 在元素的属性节点上,添加v-text 命令,例如:html
<p v-text="msg"></p>
复制代码
2.v-text中也可使用简单的语句 3.v-text与{{}}的区别前端
4.应用场景(v-text)vue
1.基本使用 在元素的属性节点上,添加v-text 命令,例如:java
<!-- 总结: vue 中的指令只有插值表达式是用在内容节点上的, 其余的全部指令都是用在属性节点的 -->
<p v-text="msg"></p>
复制代码
2.应用场景 当服务器返回的数据中,包含的html的标签,此时,这些标签只能在v-html来渲染node
添加在元素节点身上的属性均可以经过v-bind进行绑定(id width src)等
复制代码
1.基本使用react
<div id="app">
<!-- v-bind:指令表示属性绑定, 能够在v-bind中写一些简单的表达式 从此在开发中很是经常使用 v-bind:指令能够简写为英文的:表明的是属性绑定 -->
<button :title="titleStr">按钮</button>
<img :src="boo ? img:img1" alt="">
<!-- <img v-bind:src="img1" alt=""> -->
</div>
<script> // 当vm实例被建立完毕后会当即解析执行el区域内全部vue的指令 // 并且只要data数据中发生了变化,就会当即从新解析数据 const vm=new Vue({ el:'#app', data:{ titleStr:'这是title属性值', boo:false, img:'https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=2391791031,3623366227&fm=26&gp=0.jpg' ,img1:'https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=486958716,243120904&fm=26&gp=0.jpg' } }) </script>
复制代码
2.应用场景webpack
<input type="button" value="按钮" v-on:click="事件处理函数名" />
复制代码
<input type="button" value="按钮" v-on:click="show(123)" />
复制代码
关于参数问题:
1. 有传递使用传递的参数
2. 没有声明(),第一个形参就是事件对象object MouseEvent
3. 有声明(),尚未传递实参,形参就是undefined
methods: {
// 成员方法
exp(id){
console.log('商品被删除了'+id);
}
// 不传递实参的状况下是undefined
// 不加括号[object MouseEvent]
},
复制代码
<input type="button" value="按钮" @click="事件处理函数名" />
复制代码
1.基本使用:ios
<input type="text" v-model="msg"/>
复制代码
2.和v-bind的区别
4.v-model简易版原理整理 v-model的原理就给input输入框中定义oninput事件,在该事件中把用户输入的信息都给随时得到到,并对data成员进行赋值
data成员变化了,页面上用到的地方就从新渲染,达成简易双向绑定的效果 代码以下:
<div id="app">
<p>{{city}}</p>
<!-- 这里的$event就表明的是event -->
<input type="text" @input="city=$event.target.value" :value="city">
<input type="text" @input="feel" :value="city">
</div>
<script src="./vue.js"></script>
<script>
var vm=new Vue({
el:'#app',
data:{
city:'北京'
},
methods: {
feel(evt){
// console.log(evt);
// console.log(evt) // InputEvent对象
// evt.target:表明触发当前事件的html元素dom对象,具体是input框对象
// evt.target.value: 随时感知输入框输入的信息
// 把随时输入的信息赋予给city,这样city变化,因为“从新渲染”,页面上用到的地方就更新了
// 就达成v-model双向绑定的效果了
this.city=evt.target.value;
}
},
})
</script>
复制代码
5.应用场景: 简易计算器的实现:
<body>
<div id="app">
<!-- 第一个运算的数值 -->
<input type="text" v-model="n1">
<select v-model="opt">
<option value="+">+</option><br>
<option value="-">-</option><br>
<option value="*">*</option><br>
<option value="/">/</option><br>
</select>
<!-- 第二个元素的数值 -->
<input type="text" v-model="n2">
<!-- 注意这里不要写错 -->
<button @click="calc">=</button>
<!-- 运算的结果 -->
<input type="text" readonly :value="result">
</div>
<script> const vm=new Vue({ el:'#app', data:{ n1:0, n2:0, opt:'+', result:0 }, methods: { calc(){ switch(this.opt){ case '+': this.result= parseFloat(this.n1)+parseFloat(this.n2); break; case '-': this.result= parseFloat(this.n1)-parseFloat(this.n2); break; case '*': this.result= parseFloat(this.n1)*parseFloat(this.n2); break; case '/': this.result= parseFloat(this.n1)/parseFloat(this.n2); break; } } }, }) </script>
</body>
复制代码
根据业务须要,事件在执行过程当中须要对Vue实例的data数据进行操做,经过this关键字实现,
this表明Vue实例对象,而且针对data或methods成员均可以直接进行调用
1.类名数组
<p :class="['thin', 'red', 'big']">哈哈哈</p>
复制代码
2.类名数组中使用三元表达式,按需为元素添加某些类名
<button @click="getInfo()" >获取数据</button>
<script>
var vm = new Vue({
el:'#app',
data:{
address:'铁岭'
},
methods:{
getInfo:function(){
// 经过 this关键字 得到 data区域的数据信息
console.log(this.address+'是一个大城市');
}
}
})
</script>
复制代码
<p :class="['thin', flag ? 'red' : '']">哈哈哈</p>
复制代码
3.应用场景
<div id="app" :class="[flag ? 'light':'dark']">
<button @click="flag=!flag">切换</button>
<h1>{{msg}}大渣好,我系咕天乐,我系渣渣辉,贪挽难约,介系一个你没有挽过的船新版本,挤需体验3番钟,里就会干我同样,挨上节款游戏</h1>
<img :src="flag ? img1:img2" alt="">
</div>
<script>
const vm=new Vue({
el:'#app',
data:{
//false是黑夜,true是白天
flag:false,
img1:'./images/6.jpg',
img2:'./images/段段.jpg'
}
})
</script>
复制代码
style属性也比较特殊,其能够给标签设置许多css样式,在vue中能够作以下应用
- 对象语法
<div :style="{color: 'red', 'font-size': '20px', fontWeight:'bold' }"></div>
- 数组语法
<div :style="[{color: 'red'}, {'font-size': '20px', fontWeight:'bold' }]"></div>
复制代码
在一个数组元素中能够绑定多个或一个样式成员 有的样式属性名称是经过"-"中横线链接的,这在javascript的命名规则中不容许的,例如font-size、font-weight,在处理时有两种方式
以上对象或数组绑定class语法均渲染为:
<div style="color:red; font-size:20px; font-weight:bold"></div>
复制代码
经过 数组 或 对象 对 class/style 进行绑定的好处是,属性值能够嵌入编程内容,实现精细化控制
1.基本用法:
<li v-for="(item,i) in list1">{{item}}---索引{{i}}</li>
复制代码
<li v-for="(item,i) in list2">{{item.id}}---{{item.name}}---索引值{{i}}</li>
复制代码
2.:key的用法
<li v-for="item in list2" :key="item.id">{{item.id}}---{{item.name}}---索引值{{i}}</li>
复制代码
注意:从此只要用到了id值,就必定要为循环的每一项,添加:key属性绑定,并且key的值最好绑定到id值上,key的值必定要惟一,单独的使用索引值也是不能够的,由于这个key值是用来标识数据惟一性的,经过key绑定的数据项和数据状态(好比复选框的选中伪选中关系)之间的关系
复制代码
<div id="app">
<button @click="flag=!flag">Toggle</button>{{flag}}
<!-- v-if是经过动态建立或者移除元素实现动态切换 -->
<h3 v-if="flag">奔跑的五花肉</h3>
<hr>
<!-- v-show是经过控制元素的display:none样式实现切换 -->
<h3 v-show="flag">2432432</h3>
</div>
复制代码
通常来讲,v-if 有更高的切换消耗 而 v-show 有更高的初始渲染消耗。
所以,若是须要频繁切换 v-show 较好,若是在运行时条件不大可能改变 v-if 较好。
复制代码
.prevent 阻止默认行为(使用最频繁)
<a href="http://www.baidu.com" @click.prevent="show">百度</a>
复制代码
.once 只触发1次(几乎不经常使用)
<button @click.once="btnHandler">按钮</button>
复制代码
.stop阻止冒泡
<button @click.stop="btnHandler">按钮</button>
复制代码
.self只有在当前元素上触发事件的时候,才会调用处理函数
<div class="inner" @click.self="innerHandler"></div>
复制代码
按键修饰符是配合文本框的使用的 .enter
<input type="text" v-model="password" @keyup.enter="login"><br>
复制代码
.tab
<input type="text" v-model="password" @keyup.tab="login"><br>
复制代码
.esc
<input type="text" v-model="password" @keyup.esc="login"><br>
复制代码
"2018-01-25T02:10:02.945Z" => 2018-01-25
复制代码
概念:过滤器的本质就是一些函数,可被用做一些常见的文本格式化
<td :title="item.ctime |dateFormate">{{item.ctime | dateFormate}}</td>
复制代码
1.使用全局过滤器的语法
<span>{{ dt | 过滤器的名称 }}</span>
|的做用就是调用一个过滤器
复制代码
2.定义全局过滤器的语法
注意:全局过滤器必须定义在new Vue()以前
复制代码
3.使用过滤器的注意事项
<div id="app">
<!-- 在插值表达式中可使用|管道符来调用指定的过滤器 -->
<!-- 若是调用过滤器了,则在这个内容区域显示的内容是过滤器方法最终返回的处理结果 -->
<!-- 过滤器只是对原有的数据作了一层包装,并无修改原来的值 -->
<h3>{{dt | dateFormate}}</h3>
<p>{{dt}}</p>
</div>
<script>
// 经过Vue.filter定义一个全局过滤器
// 注意,调用过滤器的时候,管道符前面的值,必须经过function的第一个参数接收
// Vue.filter('过滤器的名称',function(originVal){//过滤器的处理函数
// })
Vue.filter('dateFormate',function(originVal){
//最终必定要返回一个处理结果
// return originVal+'-------'
const dt=new Date(originVal);
const y=dt.getFullYear();
const m=(dt.getMonth()+1+'').padStart(2,'0');
const d= (dt.getDate()+'').padStart(2,'0');
const hh= (dt.getHours()+'').padStart(2,'0');
const mm=(dt.getMinutes()+'').padStart(2,'0');
const ss= (dt.getSeconds()+'').padStart(2,'0');
const dtstr=`${y}-${m}-${d} ${hh}:${mm}:${ss}`;
return dtstr;
});
const vm=new Vue({
el:'#app',
data:{
dt:'2018-01-25T02:10:02.945Z'
},
methods: {
},
})
</script>
复制代码
const vm=new Vue({
el:'#app',
data:{
dt:'2018-01-25T02:10:02.945Z'
},
methods: {
},
// 注意是跟methods同级
// 注意:私有的过滤器带s,全局过滤器不带过滤器
// 私有过滤器的名称:function (){//私有过滤器的处理函数}
// 过滤器是按照就近原则进行调用的,先调用私有的,若是私有过滤器先看私有过滤器,没有再看全局过滤器
filters:{
// es3写法
// dateFormate:function(originVal){
// return originVal+'-----'
// }
// es6写法
dateFormate(originVal){
return originVal+'-----'
}
}
})
复制代码
过滤器是按照就近原则进行调用的,先调用私有的,若是私有过滤器先看私有过滤器,没有再看全局过滤器
复制代码
有的时候,过滤器主体业务逻辑不变化的状况下,可能结果的形式根据业务要求有所调整,为了加强灵活度,能够经过传递参数实现。
语法:Vue.$mount("选择器 - 指定要控制的区域")
const vm=new Vue({
data:{
msg:'Hello'
}
});
//mount是挂载的意思,表示 手动指定当前的vm实例要控制的区域
vm.$mount('#app');
复制代码
语法:template:'<h6>{{msg}}</h6>'
const vm=new Vue({
el:'#app',
data:{
msg:'Hello'
},
methods: {},
filters:{},
// 指定当前vm要渲染的模版
// 结论:若是同时指定了el和template,那么template会把el区域替换掉
template:'<h6>{{msg}}</h6>'
})
复制代码
概念 : 实例的生命周期,就是一个阶段,从建立到运行,再到销毁的阶段;
在实例的生命周期中,在特定阶段执行的一些特定的事件,这些特定的事件叫作生命周期函数
<script>
// 经过这个属性,全局设置 请求的 根路径
axios.defaults.baseURL = 'http://www.liulongbin.top:3005'
// 未来项目中都这么搞
Vue.prototype.$http = axios
// 建立 Vue 实例,获得 ViewModel
var vm = new Vue({
el: '#app',
data: {},
methods: {
async getInfo() {
const { data: res } = await this.$http.get('/api/get', { params: { name: 'zs', age: 22 } })
console.log(res)
},
async postInfo() {
const { data: res } = await this.$http.post('/api/post', { name: 'zs', age: 22 })
console.log(res)
}
}
});
</script>
复制代码
注意:axios这个库能够在任意的请求中使用,他们发送get和post请求时的参数是不相同的,get请求参数是params而那个post请求,请求参数是data,可是这里太过麻烦,就用对象结构赋值的方式将代码进行解构
复制代码
在Vue中,还可使用 vue-resource 发起数据请求
注意:Vue中的动画,都是简单的动画过渡,并不会有CSS3那么炫酷
复制代码
1.每一个动画都是由两部分组成的:
- 入场动画:从不可见(flag = false) -> 可见(flag = true)
- 出场动画:可见(flag = true) -> 不可见(flag = false)
复制代码
动画图示:
总结:带active的都是时间段的效果,
带to的都是完成以后的状态,
什么也不带的都是开始时的状态
也就是说动画都是从哪来,从哪去
复制代码
<style> /* 定义元素入场之间和离场以后的位置 */ /* 注意:他在入场以前并非标准里的位置 */ .v-enter, .v-leave-to { transform: translateX(150px); opacity: 0; } /* 定义元素,入场阶段,和离场阶段的过渡效果 */ .v-enter-active, .v-leave-active { transition: all 0.8s; } /* 动画完成以后,默认的位置就是标准流中的效果 */ /* 定义元素在标准流中的效果, 这个标准流的效果就是入场完成以后,移入离场开始以前,元素的效果*/ h3 { transform: translateX(50px); opacity: 0.5; } /* 经过类名,能够设置页面上的多组动画效果 */ .test-enter,.test-leave-to{ opacity: 0; transform: translateY(200px); } .test-enter-active, .test-leave-active{ transition: all 0.8s; } </style>
复制代码
此时transition身上的name属性也要改为对应的属性值
<div id="app">
<button @click="flag=!flag">Toggle</button>
<!-- 1.使用vue框架提供的transition标签,把须要添加过渡的效果包裹起来 -->
<transition name="">
<h3 v-if="flag">函数哈哈胡莎莎</h3>
</transition>
<hr>
<button @click="flag2=!flag2">Toggle</button>
<transition name="test">
<h6 v-if="flag2">这是第二个元素</h6>
</transition>
</div>
复制代码
注意:v-if和v-show在前面讲过是控制元素的显示和隐藏,具体的操做能够再回顾一下上面的笔记.
复制代码
<div id="app">
<button @click="flag=!flag">Toggle</button>
<!-- 指定入场的类名 -->
<transition enter-active-class="bounceInDown" leave-active-class="bounceOutDown">
<h3 v-if="flag" class="animated"> 哇哈哈哈哈哈哈</h3>
</transition>
</div>
复制代码
<!-- transition-group这个标签要放在ul里面,而且这个标签会自动的渲染为span -->
<!-- 可是这里也能够强制的将这个标签渲染为ul,这时,外面的ul属性也不须要设置了 -->
<transition-group tag="ul">
<li v-for="item in list" :key="item.id">
{{item.id}}---{{item.name}}
</li>
</transition-group>
复制代码
组件还有一个特殊之处。不只能够进入和离开动画,还能够改变定位。要使用这个新功能只需了解新增的 v-move 特性,它会在元素的改变定位的过程当中应用。
<style>
/* 为即将被删除的元素,添加样式,让他脱离标准流 */
.v-leave-active{
position: absolute;
width: 100%;
}
/* 经过.v-move这个类,可让后续的元素,经过过渡,渐渐的顶上去 */
/* 若是不加这个类的话,下面的元素会一下就顶上去,也就没有了过渡的效果 */
.v-move{
transition: all 0.8s;
}
</style>
复制代码
因为下面的笔记,在配置的时候可能会遇到ES6中导入导出的语法,因此这里提早在笔记中记录一下。
在webpack中一切皆模块,这里主要是ES6中模块化的导入和导出。
在webpack中,每一个js文件都须要独立的模块,每一个模块都有独立的做用域,其余模块默认没法直接访问当前模块中定义的成员。
1.默认导入
默认导入的语法可使用任何合法的名称来进行接收
import 接收名称 from '模块名称'
复制代码
2.默认导出语法:
export default {
a:a
}
复制代码
webpack 是前端的一个工具,这个工具,能够从NPM官网上下载到本地使用;
{
"name": "code2",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev":"webpack"
},
复制代码
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "webpack-dev-server"
},
复制代码
<script src="/main.js"></script>
复制代码
// 导入 html-webpack-plugin,从而帮咱们自动把 打包好的 main.js 注入到 index.html 页面中
// 同时,html-webpack-plugin 能够把 磁盘上的 index.html 页面,复制一份并托管到 内存中;
const HtmlPlugin = require('html-webpack-plugin')
const htmlPlugin = new HtmlPlugin({
// 传递一个配置对象
template: './src/index.html', // 指定路径,表示 要根据哪一个物理磁盘上的页面,生成内存中的页面
filename: 'index.html' // 指定,内存中生成的页面的名称
})
复制代码
// webpack 这个构建工具,是基于 Node.js 开发出来的一个前端工具
module.exports = {
mode: 'development', // 当前处于开发模式
plugins: [htmlPlugin] // 插件数组
}
复制代码
因为webpack只能打包js文件,因此对于非js文件就须要单独进行处理
module: { // 全部 非.js 结尾的第三方文件类型,均可以在 module 节点中进行配置
rules: [ // rules 是匹配规则,若是 webpack 在打包项目的时候,发现,某些 文件的后缀名是 非 .js 结尾的
// webpack 默认处理不了,此时,webpack 查找 配置文件中的 module -> rules 规则数组;
{ test: /\.css$/, use: ['style-loader', 'css-loader'] }
]
}
复制代码
注意:因为使用非js文件打包,都须要对他进行loader的出来,可是这里css-loader也有他本身的调用顺序,这里这个loader的调用时逆向的,先调用css-loader,而后再调用style-loader
复制代码
{ test: /\.less$/, use: ['style-loader', 'css-loader', 'less-loader'] }
复制代码
注意:只要是样式表,在他的loader配置中都须要加上style-loader和css-loader这两个选项。
复制代码
{ test: /\.jpg|png|gif|bmp$/, use: 'url-loader' }
复制代码
{ test: /\.eot|woff|woff2|ttf|svg$/, use: 'url-loader' }
复制代码
默认状况下,若是导入的模块是路径,webpack会优先去node_modules目录下,查找指定的路径是否存在
注意:这里打包字体文件和loader和打包处理图片的loader都是url-loader
复制代码
1.因为webpack默认只能打包处理一部分高级的js的语法,若是某些js语法,过于高级,则webpack也是处理不了的,此时只能借助于babel这个插件,来打包处理高级的js语法 2.运行两套命令,去安装相关的 loader:
- 运行 npm i babel-core babel-loader babel-plugin-transform-runtime -D
- 运行 npm i babel-preset-env babel-preset-stage-0 -D
复制代码
// 注意:在配置 babel-loader 的时候,必定要添加 exclude 排除项,把 node_modules 目录排除
// 这样,只让 babel-loader 转换 程序员 本身手写的 JS 代码;
// 好处:1. 可以提升编译的转换效率; 2. 可以防止没必要要的报错!
{ test: /\.js$/, use: 'babel-loader', exclude: /node_modules/ }
复制代码
{
"presets": ["env", "stage-0"],
"plugins": ["transform-runtime"]
}
复制代码
import Vue from 'vue'
复制代码
<!-- 未来,这个 div 就是 Vue实例 要控制的区域 -->
<div id="app"></div>
复制代码
const vm = new Vue({
el: '#app', // 要控制的区域
data: {
msg: 'ok' // 要渲染的数据
}
})
复制代码
- 把 import Vue from 'vue' 改写为 import Vue from 'vue/dist/vue.js'
复制代码
1.定义组件的语法
Vue.component('组件的名称', { 组件的配置对象 });
在组件的配置对象中:可使用 template 属性指定当前组件要渲染的模板结构;
Vue.component('my-test',{
template:`<div>这是我定义的第一个Vue组件</div>`
});
注意:这里的组件名称最好都写成是小写的,而且中间最好用-链接一下
复制代码
2.使用组件的语法(全局组件)
把 组件的名称, 以标签的形式,引入到页面上就行; 注意:
从更抽象的角度来讲,每一个组件,就至关因而一个自定义的元素;
组件中的DOM结构,有且只能有惟一的根元素(Root Element)来进行包裹!
Vue.component('my-test',{
template:`<div> <div>这是我定义的第一个Vue组件</div> <div>这是我定义的第一个Vue组件</div> </div>`
});
复制代码
3.使用组件的语法(私有组件)
注意:定义私有组件,只能在定义区域内使用,超出定制区域内使用无效,会报错误
const vm = new Vue({
el: '#app',
data: {
msg: 'Hello World!'
},
components: {
//使用compoents属性定义的组件,叫作是私有组件
// '组件名称':{/组件的配置对象/}
'my-test2': {
template: `<div>这是私有组件</div>`
}
}
})
复制代码
Vue.component('my-test', {
template: `<div> <div>这是我定义的第一个Vue组件{{d1}}</div> <div>这是我定义的第一个Vue组件</div> </div>`,
// 注意Vue规定,组件中的data必须是function函数,并且必须return一个对象
data(){
// return 当前实例对象
return {
d1:'111'
}
}
});
复制代码
区分vm实例中定义data数据
//在vm实例中,data既能够是对象也能够方法,可是在组件中只能是方法
const vm = new Vue({
el: '#app',
// data: {
// msg: 'Hello World!'
// },
data() {
return {
msg: 'Hello World!'
}
},
components: {
//使用compoents属性定义的组件,叫作是私有组件
// '组件名称':{/组件的配置对象/}
'my-test2': {
template: `<div>这是私有组件</div>`
}
}
})
复制代码
Vue.component('my-test', {
template: `<div> <div @click="show">这是我定义的第一个Vue组件{{d1}}</div> <div>这是我定义的第一个Vue组件</div> </div>`,
// 注意Vue规定,组件中的data必须是function函数,并且必须return一个对象
data(){
// return 当前实例对象
return {
d1:'111'
}
},
//组件中也能够有本身的私有方法
methods: {
show(){
console.log('调用了自定义组件中的show方法')
}
},
//组件中也能有本身的私有过滤器
filters:{
testFilter(originval){
return originval+'~~~'
}
} ,
// 组件也能够有本身的声明周期函数
created() {
console.log('调用了created函数')
; },
复制代码
组件中的 data 必须是一个 function 并 return 一个 字面量对象;在 Vue 实例中,实例的 data 既能够是 对象,能够是 方法;
组件中,直接经过 template 属性来指定组件的UI结构;在 Vue 实例中,经过 el 属性来指定实例控制的区域;可是实例也可使用 template;
组件和实例,都有本身的生命周期函数,私有的过滤器,methods 处理函数;
主要是内存中存储的地址不同,具体操做能够看下图的指示:
为何要把组件,单独的定义到 .vue 文件中?
每一个 .vue 文件,都是一个 vue 组件(叫作 单文件组件),它由三部分组成:
<template>
<div>
<!--注意单文件中的template节点只能有惟一的父元素进行包裹 -->
<h3>这是使用.vue文件定义单文件组件---{{msg}}</h3>
</div>
</template>
<script>
// 行为中固定写法
// 当前组件中私有的data数据
export default {
data(){
return {
msg:'hello .vue文件'
}
},
methods:{},
filters:{},
created(){}
}
</script>
<style >
h3{
color: red;
}
</style>
复制代码
// 导入单文件组件
import Home from './components/HOME.vue';
//把单文件组件,以Vue.compondent注册为全局组件
Vue.component('my-home',Home);
复制代码
从上述代码中能够看出,当前导入的是.vue文件,不是以js为后缀名的文件,同时也不是咱们以前处理的文件类型,因此这里在浏览器运行就会报出一个没有loader的错误.
{ test: /\.vue$/, use: 'vue-loader' }
复制代码
// 导入插件
const VueLoaderPlugin = require('vue-loader/lib/plugin')
// new 一个插件的实例对象
const vuePlugin = new VueLoaderPlugin()
// 把 new 出来的插件实例对象,挂载到 `plugins` 节点中:
plugins: [...其它插件, vuePlugin]
复制代码
全局注册 .vue 文件:
// 导入单文件组件
import Home from './components/HOME.vue';
//把单文件组件,以Vue.compondent注册为全局组件
Vue.component('my-home',Home);
const vm=new Vue({
el:'#app',
data:{
}
})
复制代码
2.私有注册 .vue 文件:
//导入son组件
import Son from './Son.vue';
// 行为中固定写法
// 当前组件中私有的data数据
export default {
data(){
return {
msg:'hello .vue文件'
}
},
// 在.vue文件中,能够经过components属性,将另一个.vue组件,定义为本身的私有组件
components:{
'my-son':Son,
}
}
复制代码
因为咱们指望在组件中的样式只在当前组件中生效,可是咱们经过运行能够发现,子组件在父组件中使用,他也被父组件的样式影响,这个是由于默认状况下,组件中定义的样式是全局组件,因此可使用下面的这种方法:
<style scoped>
/* 咱们指望在组件中的样式只在当前组件中生效 */
/* 因此从此,咱们都须要给组件的style添加scoped,防止样式冲突 */
h3 {
color: red;
}
</style>>
复制代码
若是咱们但愿使用标签嵌套的方式,也就是less的文件样式,就须要添加一个lang="less"属性,
<style lang="less" scoped>
/* 咱们指望在组件中的样式只在当前组件中生效 */
/* 因此从此,咱们都须要给组件的style添加scoped,防止样式冲突 */
.home-box {
border: 1px solid #000;
h3 {
color: red;
}
}
</style>>
复制代码
1.在父组件中,以标签形式使用子组件的时候,能够经过属性绑定,为子组件传递数据:
<my-son :pmsg1="parentMsg" :pinfo="parentInfo"></my-son>
复制代码
2.在子组件中,若是向用父组件传递过来的数据,必须先定义 props 数组来接收:
<script>
export default {
data(){
return {}
},
methods: {},
// property 属性
// 注意:父组件传递到子组件中的数据,必须通过 props 的接收,才能使用;
// 经过 props 接收的数据,直接能够在页面上使用;注意:不接受,不能使用外界传递过来的数据
props: ['pmsg1', 'pinfo']
}
</script>
复制代码
3.接收完的props数据,能够直接在子组件的 template 区域中使用:
<template>
<div>
<h3>这是子组件 --- {{pmsg1}} --- {{pinfo}}</h3>
</div>
</template>
复制代码
具体操做能够看下图:
注意:父组件传递给子组件的成员数据props都是可读数据,不要为他们从新赋值,
可是data数据都是当前属性的私有数据,并且data中的数据都是可读可写的
因为props中的数据都是只读的,因此若是想为props数据从新复制,能够把数据转存到data中,从而实现从新赋值
复制代码
因为上述进行值的传递和转存的时候,都是简单的数据类型的值,因此若是变成是引用数据类型的值,就会出现值会同时修改的状况,因此这里须要进行深拷贝操做,这里进行深拷贝操做的是利用一个包lodash:
import _ from 'lodash';
export default {
data(){
// 对于转存修改属性只是简单数据类型能够转,对于复杂数据类型还须要另外进行操做
return {
infoFromParent:this.pinfo,
msgFromParent:_.cloneDeep(this.pmsg)
}
},
// 子组件须要使用props按钮,接收外界传递过来的数据
props:['pmsg','pinfo']
}
复制代码
经过_cloneDeep(传递一个对象),这样就能够实现深拷贝,而且返回的是一个全新的对象,修改他的值,不会影响其余的值.
<my-son @func="show"></my-son>
复制代码
其中,为 子组件传递的 方法名称为 func, 具体的方法引用,为 父组件中的 show 方法 2. 子组件中,能够直接经过 this.$emit('func') 来调用父组件传递过来的方法;
子向父传值,要使用 事件绑定机制@;
父向子传递一个方法的引用
子组件中,可使用 this.$emit() 来调用父组件传递过来的方法
在使用this.$emit()调用 父组件中方法的时候,能够从第二个位置开始传递参数;把子组件中的数据,经过实参,传递到父组件的方法做用域中;
methods: {
// 点击子组件中的按钮,触发按钮的点击事件
btnHandle(){
// 在子组件中经过this.$emit()方法,触发父组件,为子组件绑定func事件
this.$emit('func' +this.msg)
}
},
复制代码
注意:兄弟组件之间,实现传值,用到的技术,是 EventBus
import Vue from 'vue'
export default new Vue()
复制代码
import bus from './bus.js'
复制代码
created(){
// 定义事件
bus.$on('ooo', (data)=>{
console.log(data)
})
}
复制代码
import bus from './bus.js'
复制代码
import bus from './bus.js'
export default {
data(){
return {
msg: 'abcd'
}
},
methods: {
sendMsg(){
// 触发 绑定的 事件,并向外传递参数
bus.$emit('ooo', this.msg)
}
}
}
复制代码
1.把要获取的DOM元素,添加 ref 属性,建立一个DOM对象的引用,指定的值,就是引用的名称:
//经过ref获取的DOM元素的引用就是一个元素的DOM对象
<p ref="myElement11">这是父组件</p>
复制代码
console.log(this.$refs.myElement11)
复制代码
console.log(this.$refs.myElement11)
复制代码
3.也可使用 ref 为组件添加引用;可使用 this.$refs.组件应用名称, 拿到组件的引用,从而调用组件上的方法 和 获取组件data上的 数据;
若是在 vm 实例中既指定了 el 又指定了 render 函数,则会把 el 所指的的区域,替换为 render 函数中所提供的组件;
既然 render 函数会替换到 el 区域内的全部代码,也会让 template 属性失效;所以,在删减版的 vue 包中,new 出来的 Vue 实例对象,不容许 挂载 data 属性和 template 属性!
const vm = new Vue({
el: '#app',
// createElements 形参是一个方法,专门用于渲染一个组件,并替换掉 el 区域
/* render: function(createElements){ return createElements(App) }, */
// 这是 render 的终极格式
// 被render渲染的组件,叫作 根组件
// 什么是根组件:【不论浏览器中的页面如何切换,根组件永远都在页面上显示】
render: h => h(App)
})
// 注意:只要在 vm 实例中,指定了 render 函数来渲染组件,那么,el 区域,就会被 render 中渲染的组件替换掉;
复制代码
<template>
<div>
<h1>App 根组件</h1>
<button @click="comName='my-home'">Home</button>
<button @click="comName='my-movie'">Movie</button>
<!-- 能够经过 component 的is属性,动态指定要渲染的组件 -->
<component :is="comName"></component>
</div>
</template>
<script>
import Home from './coms/Home.vue'
import Movie from './coms/Movie.vue'
export default {
data() {
return {
// 默认是展现home属性的
comName: 'my-home'
}
},
components: {
'my-home': Home,
'my-movie': Movie
}
}
</script>
复制代码
使用 component 标签的:is属性来切换组件
总结:单页面应用程序中,实现组件切换的根本技术点,就是 监听 window.onhashchange 事件;
什么是路由:路由 就是 对应关系;
// 导入路由模块
import VueRouter from 'vue-router'
// 注册路由模块(把路由模块安装到Vue上)
Vue.use(VueRouter)
复制代码
<!-- router-link 就是 第一步,建立 路由的 hash 连接的 -->
<!-- to 属性,表示 点击此连接,要跳转到哪一个 hash 地址, 注意:to 属性中,你们不须要以 # 开头 -->
<router-link to="/home">首页</router-link>
<router-link to="/movie">电影</router-link>
<router-link to="/about">关于</router-link>
复制代码
3.建立并在 index.js 中导入路由相关的组件:
import Home from './components/Home.vue'
import Movie from './components/Movie.vue'
import About from './components/About.vue'
复制代码
4.建立路由规则
// 建立路由规则(对应关系)
const router = new VueRouter({ // 配置对象中,要提供 hash 地址 到 组件之间的 对应关系
routes: [ // 这个 routes 就是 路由 规则 的数组,里面要放不少的对应关系
// { path: 'hash地址', component: 配置对象 }
{ path: '/home', component: Home },
{ path: '/movie', component: Movie },
{ path: '/about', component: About }
]
})
// 建立的 router 对象,千万要记得,挂载到 vm 实例上
const vm = new Vue({
el: '#app',
render: c => c(App),
router // 把 建立的路由对象,必定要挂载到 VM 实例上,不然路由不会生效
})
复制代码
5.在页面上放路由容器
<!-- 这是路由的容器,未来,经过路由规则,匹配到的组件,都会被展现到这个 容器中 也就是切换的内容会在下面的这个区域进行显示 -->
<router-view></router-view>
或者是直接写成是单闭合标签
<router-view />
复制代码
<style lang="less" scoped> .router-link-active { color: red; font-weight: bold; } </style>
复制代码
// 3. 建立路由实例对象
const router = new VueRouter({
routes: [
// 路由? 就是对应关系
// 前端路由? hash => 组件 之间的对应关系
// vue 中路由的格式 { path, component }
// path 路由hash地址中,路径必须以 / 开头,并且必须是小写,并且不能带空格
{ path: '/home', component: Home },
{ path: '/movie', component: Movie },
{ path: '/about', component: About },
{ path: '/me', component: Me }
],
linkActiveClass: 'my-active' // 若是你们作项目时候, 用到的 UI 组件库中,提供了默认的高亮效果
})
//在页面上的显示类名以下:
.my-active {
color: #007ACC;
font-weight: 700;
}
复制代码
const router = new VueRouter({
routes: [
// 路由? 就是对应关系
// 前端路由? hash => 组件 之间的对应关系
// vue 中路由的格式 { path, component }
// path 路由hash地址中,路径必须以 / 开头,并且必须是小写,并且不能带空格
// 在路由规则中,经过 redirect 属性,指向一个新地址,就可以实现路由的重定向
{ path: '/', redirect: '/home' },
{ path: '/home', component: Home },
{ path: '/movie', component: Movie },
// 在某个路由规则中,如何嵌套子路由规则? path 和 component 平级,还有个 children 属性
// children 属性 是一个数组, 做用,就是来嵌套子路由规则的
{
path: '/about',
component: About,
redirect: '/about/tab1',
children: [
{ path: '/about/tab1', component: Tab1 },
{ path: '/about/tab2', component: Tab2 }
]
},
{ path: '/me', component: Me }
],
linkActiveClass: 'my-active' // 若是你们作项目时候, 用到的 UI 组件库中,提供了默认的高亮效果
})
复制代码
经过属性绑定实现路由传参,也就是在路由规则的参数项以前加冒号实现路由传参
<!-- 当router-link的to地址,要动态进行拼接的时候,那么,必定要把 to 设置成属性绑定的形式 -->
<router-link v-for="item in mlist" :key="item.id" :to="`/mdetail/${item.id}/${item.name}`" tag="li">{{item.name}}</router-link>
复制代码
可是仍是可能会出现参数不固定的状况
const router = new VueRouter({
routes: [
{ path: '/', component: MovieList },
// 把路由规则中, 参数项位置,前面加上 : 表示这是一个参数项
// props: true 表示,为当前路由规则,开启 props 传参
{ path: '/mdetail/:id1/:name2', component: MovieDetail, props: true }
]
})
复制代码
{ path: '/movie/:type/:id', component: movie, props: true }
复制代码
const movie = {
template: '<h3>电影组件 --- {{type}} --- {{id}}</h3>', // 使用参数
props: ['type', 'id'] // 接收参数
}
复制代码
什么是命名路由: 就是为路由规则,添加了一个 name ;
<!-- 使用 命名路由实现跳转 -->
<router-link v-for="item in mlist" :key="item.id" :to="{name: 'moviedetail', params: {id1: item.id, name2:item.name}}" tag="li">{{item.name}}</router-link>
复制代码
以前所学的router-link是标签跳转;
除了使用router-link是标签跳转以外,还可使用Javascript来实现路由的跳转;
//跳转到指定的路由规则中
//能够前进和后退
//能够前进
//能够后退
path 是要匹配的hash值, component 要展现的组件 redirect 要重定向的路由 props 开启props传参 name 命名路由 children 嵌套子路由
// 参数1:是要去的那个页面路由相关的参数
// 参数2:从哪一个页面即将离开
// 参数3:next 是一个函数,就至关于 Node 里面 express 中的 next 函数
// 注意: 这里的 router 就是 new VueRouter 获得的 路由对象
router.beforeEach((to, from, next) => { /* 导航守卫 处理逻辑 */ })
复制代码
案例核心代码:
// 经过 路由导航守卫, 控制有权限页面的访问, 只有登陆之后,才容许访问高级的页面
router.beforeEach((to, from, next) => {
// to.path 表示咱们下一刻要访问哪一个地址
// console.log(to)
// from.path 表示咱们上一刻,所访问的是哪一个地址
// console.log(from)
// next() 直接调用,表示放行
// next()
// 若是 要访问的地址,是 /login, 证实用户要去登陆, 没有必要拦截,直接放行
if (to.path === '/login') return next()
// 若是用户访问的不是 登陆页面,则 先尝试从sessionStorage中获取 token 令牌字符串
const tokenStr = window.sessionStorage.getItem('token')
// 若是没有 token 令牌,则 强制用户跳转到登陆页
if (!tokenStr) return next('/login')
// 若是有令牌,则直接放行
next()
})
复制代码
token是一个令牌,是服务器端发送过来的客户端必须经过登陆,才能获取这个令牌,
watch 监听的特色:监听到某个数据的变化后,侧重于作某件事情;
案例:登陆 密码 的长度检测
密码长度小于8位,字体为红色;大于等于8位,字体为黑色;
export default {
data() {
return {
uname: '',
upwd: ''
}
},
// watch 是监听 data 中数据的变化, 侧重于作某件事件
watch: {
upwd(newVal, oldVal) {
if (newVal.length < 8) {
this.$refs.pwdDOM.style.color = 'red'
} else {
this.$refs.pwdDOM.style.color = ''
}
}
}
}
复制代码
计算属性特色:同时监听多个数据的变化后,侧重于获得一个新的值;
export default {
data() {
return {
firstname: '',
lastname: ''
}
},
// 计算属性
computed: {
// 定义一个计算属性,叫作 fullName
// 注意: 全部的计算属性,在定义的时候, 都要被定义为 function,
// 可是,在页面上使用计算属性的时候, 是直接看成普通的 变量 来使用的,而不是看成方法去调用的!!!
// 特色:只要计算属性的 function 中,依赖的 任何一个数据发生了变化,都会对这个计算属性,从新求值
fullName: function() {
return this.firstname + '-' + this.lastname
}
}
}
复制代码
应用
若是页面须要访问一个数据,这个数据比较复杂,是须要经过其余data通过复杂步骤制做出来的,那么就能够经过“计算属性”简化得到该数据
补充:Vue自己支持模板中使用复杂表达式表现业务数据,可是这会使得模板内容过于杂乱,若是确有需求,能够经过computed计算属性实现
与methods方法的区别:
computed计算属性自己有“缓存”,在关联的data没有变化的状况下,后续会使用缓存结果,节省资源
methods方法没有缓存,每次访问 方法体 都须要加载执行,耗费资源
复制代码
为何要使用 vue-cli 建立项目:
省略文件扩展名:
resolve: {
// resolve 节点下的 extensions 数组中,能够配置,哪些扩展名能够被省略
extensions: ['.js', '.vue', '.json']
}
复制代码
修改完配置之后,从新运行 npm run dev 查看效果;
配置 @ 指向 src 目录:
resolve: {
alias: {
'@': path.join(__dirname, './src') // 让 @ 符号,指向了 项目根目录中的 src
}
}
复制代码
// Vue.directive('全局指令名称', { /*指令的配置对象*/ })
// 注意:自定义指令名称以前,不须要手动添加 v- 前缀
Vue.directive('red', {
// 只要指令被解析指令了,就会优先调用指令中的 bind 方法
bind(el) {
// 只要bind被指向了,那么el,就是它所绑定到的 UI 元素
// el 是原生DOM对象,也正是由于他是原生的DOM对象,因此他才能够经过style.color的方式修改样式
el.style.color = 'red'
}
})
复制代码
概念:只有指令所属的组件中,才能够被正常调用的指令,叫作私有自定义指令;
// 私有自定义指令的定义节点
directives: {
// 指令名称: { /配置对象/ }
blue: {
bind(el) {
el.style.color = 'blue'
}
}
}
复制代码
Vue.directive('focus', {
// bind 表示指令第一次被解析执行时候调用,此时,这个 DOM 元素,尚未被append到父节点中;
// 此时只是在内存中存储着,因此还你没有渲染到页面上
bind(el) {
// el.focus()
// console.log(el.parentNode),null
},
// inserted 会在元素被插入到父节点以后,执行,此时已经渲染到页面之上了
inserted(el) {
// 定义 文本框得到焦点的指令,只能经过 inserted 来实现
// 由于 bind方法 和 inserted方法 的执行时机不同
el.focus()
}
})
// 总结:若是只是单纯的为元素设置样式,尽可能写到 bind 中
// 若是要设置JS行为,好比文本框获取焦点,这种行为,尽可能写到 inserted 中
复制代码
Vue.directive('color', {
// 经过 形参中的 binding 来接收指令传递过来的数据
// 全部经过=传过来的值都是在binding中存储着
// 传递过来的参数,是 binding.value 属性
bind(el, binding) {
// console.log(binding.value)
el.style.color = binding.value
}
})
复制代码
定义:定义子组件的时候,在子组件内部刨了一个坑,父组件想办法往坑里填内容;
Son.vue子组件代码:
<template>
<div>
<h4>这是子组件</h4>
<p>哈哈哈</p>
<!-- 没有name属性的插槽,称为是匿名插槽 -->
<slot></slot>
<!-- 注意:在同一个组件中,只容许定义一次插槽 -->
<!-- <slot></slot> -->
<p>heiehei</p>
</div>
</template>
复制代码
APP.vue主组件代码展现:
<template>
<div>
<h1>这是父组件</h1>
<hr>
<!-- 在子组件的内部放置内容 -->
<!-- 默认状况下载组件内容中,定义的信息都会被显示到匿名插槽中 -->
<my-son>
<img src="./images/土拨鼠啊.gif" alt="">
<img src="./images/老王.png" alt="">
<h3>6666</h3>
</my-son>
</div>
</template>
复制代码
<template>
<div>
<h1>这是子组件</h1>
<p>啊,五环</p>
<!-- 匿名插槽 -->
<slot></slot>
<p>你比四环多一环</p>
<!-- 具名插槽 -->
<slot name="s2"></slot>
<p>啊,五环</p>
<slot name="s3"></slot>
<p>你比七环少两环</p>
</div>
</template>
复制代码
<template>
<div>
<h1>这是父组件</h1>
<hr />
<my-son>
<!-- 默认状况下指定的元素会被插入到匿名插槽中 -->
<img src="../03默认插槽/images/一脸懵逼表情包.jpg" alt />
<img slot="s2" src="../03默认插槽/images/土拨鼠啊.gif" alt />
<img src="../03默认插槽/images/老王.png" alt />
<img slot="s3" src="../03默认插槽/images/擅用百度.jpg" alt="">
</my-son>
</div>
</template>
复制代码
<template>
<div>
<h4>这是子组件</h4>
<slot smsg="hello Vue" sinfo="你好"></slot>
<p>
~~~~~~~~~~~~~~
</p>
<slot name="s2" :umsg="m1" :uinfo="m2">
</slot>
</div>
</template>
<script>
export default {
data(){
return {
m1:'abcd',
m2:'123456'
}
}
}
</script>
复制代码
<template>
<div>
<h1>这是父组件</h1>
<hr>
<my-son>
<h6 slot-scope="scope">{{scope}}</h6>
<!-- <h3 slot="s2" slot-scope="scope">{{scope}}</h3>
<h3 slot="s2" slot-scope="scope">{{scope}}</h3> -->
<!-- 若是要接收做用域插槽中的数据,并且渲染为多个标签,
则必须在多个标签以外,包裹一个父元素,进行接收插槽中的数据
-->
<!-- 注意 template只起到包裹元素的做用,不会被渲染为任何标签-->
<template slot="s2" slot-scope="scope">
<h3>{{scope.uinfo}}</h3>
<h3>{{scope.umsg}}</h3>
</template>
</my-son>
</div>
</template>
复制代码
待更新....
1.element-ui 是 饿了么 前端团队,开源出来的一套 Vue 组件库;
2.完整引入 Element-UI 组件:
1. 运行 yarn add element-ui -S 安装组件库
2. 在 index.js 中,导入 element-ui 的包、配套样式表、而且安装到Vue上:
复制代码
// 导入 element-ui 这个包
import ElementUI from 'element-ui'
// 导入 配套的样式表
import 'element-ui/lib/theme-chalk/index.css'
// 把 element-ui 安装到 Vue 上
Vue.use(ElementUI)
复制代码
3.按需导入和配置 Element-UI :
{
"presets": ["@babel/preset-env"],
"plugins": ["@babel/plugin-transform-runtime", "@babel/plugin-proposal-class-properties",
+ [
+ "component",
+ {
+ "libraryName": "element-ui",
+ "styleLibraryName": "theme-chalk"
+ }
]]
}
复制代码
$ npm install -g vue-cli // 全局安装脚手架工具
$ vue init webpack my-project // 初始化项目
$ cd my-project // 切换到项目根目录中
$ npm install // 安装依赖包
$ npm run dev // 一键运行项目
复制代码
// 使用 ESLint 规则
"prettier.eslintIntegration": false,
// 每行文字个数超出此限制将会被迫换行
"prettier.printWidth": 100,
// 使用单引号替换双引号
"prettier.singleQuote": true,
// 格式化文件时候,不在每行结尾添加分号
"prettier.semi": false,
// 设置 .vue 文件中,HTML代码的格式化插件
"vetur.format.defaultFormatter.html": "prettier"
复制代码