Vue总结
vue引入与导出
引入一个js文件,如果js文件中有 export default xxx 的内容
就这样引入: import 名称 from '路径'
如果js文件中没有 export default xxx 内容
需要这样引入: import '路径' (此时window增加一个全局变量 initGeetest)
只有在index.html和main.js引入才是全局引入
vue第一天
vue
Vue是一个优秀的前端框架
开发者按照Vue的规范进行开发
Vue能做什么?
1. 和DOM解耦 与DOM关系不多
2. 适应当前SPA的项目开发 single page application 单一页面应用
3.掌握Vue的开发语法 相当于掌握了新的开发模式,可以适应目前绝大多数的技术环境
特点:
1. 数据驱动视图 可以让我们只关注数据
2. MVVM 双向绑定
3. 通过指令增强了html功能 新特性
4. 组件化 复用代码
实例选项-el
- 作用:当前Vue实例所管理的html视图
- 值:通常是id选择器(或者是一个 HTMLElement 实例)
- 不要让el所管理的视图是html或者body!
实例选项-data
- Vue 实例的数据对象,是响应式数据(数据驱动视图) 数据变化 => 视图变化
- 可以通过 vm.$data 访问原始数据对象
- Vue 实例也代理了 data 对象上所有的属性,因此访问 vm.a 等于 vm.$data.a
- 视图中绑定的数据必须显式的初始化到 data 中 ,显示到视图中的数据在data中必须定义
- 数据对象的更新方式 直接 采用 实例.属性 = 值 vm.name = "张三"
实例选项-methods
- methods是一个对象
- 可以直接通过 VM 实例访问这些方法,或者在指令表达式中使用。
- 方法中的 this 自动绑定为 Vue 实例。
- methods中所有的方法 同样也被代理到了 Vue实例对象上,都可通过this访问, vm.fn()
- 注意,不应该使用箭头函数来定义 method 函数 (例如 plus: () => this.a++)。理由是箭头函数绑定了父级作用域的上下文,所以 this 将不会按照期望指向 Vue 实例,this.a 将是 undefined
插值表达式(重要)
作用:会将绑定的数据实时的显示出来:
形式: 通过 {{ 插值表达式 }}包裹的形式
通过任何方式修改所绑定的数据,所显示的数据都会被实时替换(响应式数据)
a , a = 10 , a == 10 , a > 10, a + b + c
"1" + "2" + "3", a.length.split(''), a > 0 ? "成功" : "失败"
注意:不能写 var a = 10; 分支语句 循环语句,不可以带有JS关键字
例:
<p>{{ count === 1 }}</p> #返回Boolean类型
<!-- count 为data中的数据 -->
<p>{{ count === 1 ? "成立" : "不成立" }}</p>
<p>{{ fn() }}</p> #调用方法
指令(重要)
- 指令 (Directives) 是带有 v- 前缀的特殊特性。
- 指令特性的值预期是单个 JavaScript 表达式(v-for 是例外情况,稍后我们再讨论)。
- 指令的职责是,当表达式的值改变时,将其产生的连带影响,响应式地作用于 DOM。
指令位置: 起始标签
插值表达式: 更新标签中局部的内容
v-text 更新整个标签中的内容
v-html 更新标签中的内容/标签,可以渲染内容中的HTML标签(少用,容易造成危险)
v-if 和 v-show v-show本质是通过修改标签的display值
v-if="isShow" isShow: false
场景: 需要根据条件决定 元素是否显示 使用以上指令
使用: v-if 和 v-show 后面的表达式返回的布尔值 来决定 该元素显示隐藏
注意 : v-if 是直接决定元素 的 添加 或者删除 而 v-show 只是根据样式来决定 显示隐藏v-on绑定事件:
<input type="text" @change="fn()"> #fn()默认参数为$event,methods内的函数默认第一个参数也是event
v-on:事件名.修饰符="方法名" ,v-on:可以用@代替
注意 方法名 中 可以采用$event的方式传形参 也可以直接写事件名 默认第一个参数为event事件参数
传递$event的时候,$必须加,如果不写,methods中的函数默认第一个参数为event事件参数
例:fn(count,$event)
修饰符(可不写)
.once - 只触发一次回调。
.prevent - 调用 event.preventDefault()。获取当前input中输入的值:
#event事件中target指的是触发该事件的元素 是DOM对象
console.log(event.target.value);
@change:鼠标失去焦点输出
@input:value值变化就输出
遍历数组和对象v-for
注意 v-for写的位置 应该是重复的标签上 不是其父级元素上 需要注意
item in items // item为当前遍历属性数组项的值
(item,[index]) in items //item为当前遍历属性数组项的值 index为数组的索引
v-for 指令需要使用 item in items 或者 item of items 形式的特殊语法,in/of 一样
items 是源数据数组 /对象 <p v-for="item in list">{{item}}</p>
对象:
item in items // item为当前遍历属性对象的值
(item,[ key], [index]) in items //item为当前遍历属性对象的值 key为当前属性名的值 index为当前索引的值
vue第二天
v-for-key
- 场景:列表数据变动会导致 视图列表重新更新 为了 提升性能 方便更新 需要提供 一个属性 key
- 使用: 通常是给列表数据中的唯一值 也可以用索引值
语法:
<li v-for="(item,index) in list" :key="index">
v-if和v-for优先级
<p v-if="index>1" v-for="(item,index) in list"></p>
v-for 的优先级大于v-if ,所有v-if才能使用v-for的index变量
如果遇到 v-if判断数组变量 需要在循环体外再建立一个判断 v-if
<div v-if="list.length >4">
<li v-if="index>2" v-for="(item,index) in list" :key="index">
{{ item }}
</li>
</div>
v-bind
- 作用:绑定标签上的任何属性
- 场景: 当标签上的属性是变量/动态/需要改变的
<p v-bind:id="ID"></p> // ID为数据对象中的变量值
<p :id="ID"></p> // 简写
v-bind-绑定class-对象语法
绑定class对象语法 :class="{ class名称: 布尔值 }"
<p :class="{left:showClass}">内容</p>
showClass:true
如果showClass的值为true,则加上left类,若为false,则不加
<p v-bind:class="name"></p>
name: "test" 加上test类
绑定class和原生class会进行合并
v-bind-绑定class-数组语法
绑定class数组语法 :class="[class变量1,class变量2..]" #绑定class和原生class会进行合并
<p :class="[activeClass,selectClass]" class="default">内容</p>
v-bind-绑定style-对象语法
<p :style="{fontSize:fontSize,color:color,fontWeight:fontWeight}">Hello world</p>
复合标签必须采用小驼峰命名
当属性名和 值的变量名一致是 可以简写 为 color:color => color
<p :style="{fontSize,color,fontWeight}">Hello world</p>
data: {fontSize: "48px", color: "red",fontWeight: "bold"} #data数据如下
v-bind-绑定style-数组语法
语法: :style="[对象1,对象2...]"
对象可以是多个属性的 集合 同样里面的css属性需要遵从小驼峰命名的规则
例:
<p v-bind:style="[obj1,obj2]" style="color:blue">Hello world</p>
data: {
obj1: {fontSize: "48px",color: "red", backgroundColor: "black"},
obj2: { backgroundColor: "yellow" }
}
原有内联CSS会先执行,后加CSS如有重复会覆盖内联样式
v-model-基础用法
作用: 表单元素的绑定
特点: 双向数据绑定
数据发生变化可以更新到界面
通过界面可以更改数据
v-model 会忽略所有表单元素的 value、checked、selected 特性的初始值而总是将 Vue 实例的数据作为数据来源。应该在 data选项中声明初始值。
<input type="text" v-model="name" />
<p v-text="name"></p>
语法糖原理
<input type="text" @input="changeInput" :value="name" />
changeInput(){this.name = event.target.value;}
通过v-on指令和 v-bind指令 组合实现v-model效果
利用input事件,获取value实时变化的值,用v-bind绑定value的初始值与data数据一致
v-model绑定其它表单
当表单type属性为Checkbox的时候,获取的是当前表单value值
当表单type属性为Checkbox的时候,未选中默认为false,选中为true
v-cloak
解决页面初次渲染时 页面模板闪屏现象
<div v-cloak id="app"> #可以一次性 将v-cloak引用在实例视图上 避免多次写入标签
[v-cloak] { display: none; }
v-once
- 作用: 使得所在元素只渲染一次
- 场景:静态化数据
<p>{{ name }}</p>
<p v-once>{{ name }}</p> #数据不再变化
<input type="text" v-model="name" />
全局过滤器
1. 在创建 Vue 实例之前定义全局过滤器Vue.filter()
2. Vue.filter('该过滤器的名字',(要过滤的数据)=>{return 对数据的处理结果});
3. 在视图中通过{{数据 | 过滤器的名字}}或者v-bind使用过滤器
<p>{{ name | toUpper }}</p> #应用过滤器
1 注册过滤器
Vue.filter("toUpper", function(value) {
// 2 实现过滤逻辑
return value.charAt(0).toUpperCase() + value.substr(1);
});
局部过滤器
filters: {
// 和全局过滤器区别只是注册位置不同 应用范围不同
toUpper(value) {
return value.charAt(0).toUpperCase() + value.substr(1);
} }
filters比全局多了个s,写在Vue实例中,只有当前实例可以调用 ,和全局过滤器区别只是注册位置不同 应用范围不同
第一个参数永远是value,第二个参数可以是索引
过滤器可定义多个,也可一起使用
<p>{{ text | toUpper(2) | reverse }}</p> // 语法 多个过滤器用 | 分割
使用过滤器完成日期 格式处理
1 . 引入 第三方格式化日期插件 moment.min.js
2 . 定义格式化日期过滤器
3 . 实现其格式化功能
4 . 使用过滤
format(value, format) {
return moment(value).format(format);
} // 过滤器代码
<td>{{item.date|format("YYYY-MM-DD hh:mm:ss")}}</td>
vue第三天
ref 操作 DOM
- 作用: 通过ref特性可以获取元素的dom对象
- 使用: 给元素定义 ref属性, 然后通过$refs.名称 来获取dom对象
<input type="text" ref="myInput" /> // 定义ref
focus() {
this.$refs.myInput.focus();
} // 获取dom对象 聚焦 methods中定义方法
自定义指令-全局自定义指令
- 使用场景:需要对普通 DOM 元素进行操作,这时候就会用到自定义指令
- 分类:全局注册和局部注册
1. 在创建 Vue 实例之前定义全局自定义指令Vue.directive()
2. Vue.directive('指令的名称',{ inserted: (使用指令的DOM对象) => { 具体的DOM操作 } } );
3. 在视图中通过"v-自定义指令名"去使用指令 v-focus
// 定义指令
// 自定义指令是不需要加v-前缀的
// 第二个参数为一个对象 对象中要实现 inserted的方法
// inserted中的参数为当前指令所在元素的dom对象
Vue.directive("focus", {
inserted(dom) {
dom.focus();
}
});
局部自定义命令写在vm实例中
computed
- 场景:当表达式过于复杂的情况下 可以采用计算属性 对于任何复杂逻辑都可以采用计算属性
- 使用: 在Vue实例选项中 定义 computed:{ 计算属性名: 带返回值的函数 }
- 说明: 计算属性的值 依赖 数据对象中的值 数据对象发生改变 => 计算属性发生改变=> 视图改变
- methods 和 计算属性的区别
- methods 每次都会执行
- 计算属性 会每次比较更新前后的值 如果前后一致 则不会引起视图变化
- methods每次都会执行 性能较计算属性较差
计算属性中一定是同步操作,如果有异步操作,则该业务逻辑就会失败
{{newList}} //调用计算属性
computed: {
newList(){
var arr= this.list.filter(function(value,index){
return value>5;
})
return arr;
}} // 定义计算属性
axios
- 本地引入axios文件
在npm 中引入axios文件
axios.get(url).then((res) => {
// 请求成功 会来到这 res响应体
}).catch((err) => {
// 请求失败 会来到这 处理err对象
})
表格案例
获取数据:
mounted() {
// 渲染完成事件
axios.get("http://localhost:3000/brands").then(result => {
this.list = result.data;});}
删除数据:
delItem(id) {
if (confirm("确定删除此条记录")) {
axios
.delete("http://localhost:3000/brands/" + id)
.then(result => {
this.getList(); // 重新调用拉取数据}); } }
添加数据:
addItem() { // 添加商品
axios.post("http://localhost:3000/brands", {
name: this.name,
date: new Date()
})
.then(result => {
if (result.status == 201) {
this.getList(); // 请求数据
this.name = ""; // 清楚文本框内容}});
watch(监听属性)
watch:{ //watch也是vm实例的一个对象
city:function(oldName,newName){
var arr = this.list.map(function(i){
i.name = newName;
return i;
});
this.list = arr;} }
vue第四天
组件
组件特点: 组件是一个特殊的 Vue实例
和实例相似之处: data/methods/computed/watch 等一应俱全
注意:data和Vue实例的区别为 组件中data为一个函数 没有el选项
data选项是一个函数的时候,每个实例可以维护一份被返回对象的独立的拷贝,这样各个实例中的data不会相互影响,是独立的。
template 代表其页面结构 (有且只要一个根元素)
每个组件都是独立的 运行作用域 数据 逻辑没有任何关联
<content-a></content-a> / //使用组件
Vue.component("content-a", { // // 组件名称 abc abcD adc-d 推荐 abc-d的模式 而且全小写
template: `<div>
{{count}}
</div>`,
data() {
return {
count: 1
};
}});
// 组件能够实现数据独立 因为在data中return 了一个新的对象
// 组件中 data必须是一个函数 而且必须返回一个对象(重点)
// 这是组件和Vue实例的最大区别
局部组件
局部组件写在vm实例对象内部,components:{},需要加个s
components:{ "content-a": { template: ``}}
使用组件中的实例不要忘记加this
component嵌套
var comA = {template: `<div>我是子组件</div>`}; //先定义子组件
var parentA = { //再定义父组件
template: `<div>
我是父组件
<com-a></com-a> //调用子组件
</div>`,
components: {'com-a': comA } //组件同样拥有注册局部组件选项
};
components: { 'parent-a":parentA} //根组件再调用父组件
组件传值
父组件→子组件
- props作用: 接收父组件传递的数据
- props就是父组件给子组件标签上定义的属性
- props是组件的选项 定义接收属性
props的值可以是字符串数组 props:["绑定的属性"] , 来源于外部的(组件的外部)
父组件传递给子组件的数据是只读的,即只可以用,不可以改
1.<child :title="name" :age="age"> //调用子组件时,给子组件标签用v-bind绑定属性
data() {return { name: "张三",age: 18};- props: ["title", "age"] // 父组件传递后,子组件要用props接收传递属性
3.{{ title }}{{age}}
//子组件接收完属性就可以进行调用属性,不是属性值
- props: ["title", "age"] // 父组件传递后,子组件要用props接收传递属性
子组件→父组件
通过在子组件中触发$emit事件,然后在父组件中监视此事件 进行追踪
methods: {
selectCity() {
// this当前实例 this.属性名直接可以获取props属性值 所以props不能和data属性重名 也不能和方法重名
//console.log(this.city);
// $emit是当前实例的方法 (自定义事件名称(可随意定义),params...)
this.$emit("changecity", this.city); //抛出一个事件
}
子组件通过抛出事件,父组件定义事件接收 @changecity="change",事件名与$emit中一致,change(city)可以拿到实参
SPA
- 传统模式 每个页面及其内容都需要从服务器一次次请求 如果网络差, 体验则会感觉很慢
- spa模式, 第一次加载 会将所有的资源都请求到页面 模块之间切换不会再请求服务器
优点:
用户体验好,因为前段操作几乎感受不到网络的延迟
完全组件化开发 ,由于只有一个页面,所以原来属于一个个页面的工作被归类为一个个组件.
缺点
- 首屏加载慢->按需加载 不刷新页面 之请求js模块
- 不利于SEO->服务端渲染(node->自己写路由->express-art-template+res.render())
- 开发难度高(框架) 相对于传统模式,有一些学习成本和应用成本
- vue适合开发SPA , SPA不利于SEO
SPA-实现原理
前端自由切换模块
刷新页面模块依然还在当前视图- 可以通过页面地址的锚链接来实现
- hash(锚链接)位于链接地址 #之后
- hash值的改变不会触发页面刷新
- hash值是url地址的一部分,会存储在页面地址上 我们可以获取到
- 可以通过事件监听hash值得改变
- 拿到了hash值,就可以根据不同的hash值进行不同的模块切换
location 可以拿到hash
路由
体验:
<!-- router-link 最终会被渲染成a标签,to指定路由的跳转地址 -->
<router-link to='/bj'>北京</router-link> //设置导航内容
<!-- 路由匹配到的组件将渲染在这里 -->
<!-- 设置容器 -->
<router-view></router-view> // 设置容器
<script src="./vue-router.js"></script> ///引入vue-router.js
var router = new VueRouter({ //实例化一个vue-router
routes:[{ //编写页面路由 配置路由表
path:'/bj',
component:{
template: `<div>北京</div>`
}}]
router:router //将router挂载到Vue实例上
点击link标签,跳转到相应路径路由,将对应模板 显示到view上,其它模板被销毁
vue第五天
vue-router-动态路由
- 点击列表页 跳转到详情页时,跳转的链接需要携带参数,会导致页面path不同
当页面path不同却需要对应同一个组件时,需要用到动态路由这一概念,可以通过路由传参来实现
this.$route 获取当前路由对象 并通过params获取定义的参数id
path:"/team/:teamname", //定义动态路由
component:{
template:<div>我是{{$route.params.teamname}}队粉丝</div>
}
//{{$route.params.teamname}}{{$route.params.postname}} ,两个参数需要拿两次
勇士 //传入实参路由规则 匹配路径 $route.params
/user/:username /user/evan { username: 'evan' }
/user/:username/post/:post_id /user/evan/post/123 { username: 'evan', post_id: '123' }
vue-router-to属性赋值
<!-- <router-link to="/sport">体育</router-link> -->
<!-- 变量 -->
<!-- <router-link :to="path">体育</router-link> -->
<!-- 根据对象name跳转 -->
<!-- <router-link :to="{name:'abcdefg'}">体育</router-link> -->
<!-- 根据对象path跳转 -->
<!-- <router-link :to="{path:'/sport'}">体育</router-link> -->
<!-- 带参数的跳转 -->
<router-link :to="{name:'abcdefg',params:{a:1}}">体育</router-link>
注意:如果提供了 path,params 会被忽略,上述例子中的name并不属于这种情,你可以提供路由的 name 并手写完整的参数params:**
vue-router-重定向
当希望某个页面被强制中转时 可采用redirect 进行路由重定向设置
path: "/sport",
redirect: "/news", // 强制跳转新闻页
vue-router-编程式导航
- 跳转不同的组件 不仅仅可以用router-link 还可以采用代码行为
- (Vue实例)this.$router 可以拿到当前路由对象的实例
- 注意 前面小节获取数据用到的是 $route,这里用到的是$router
- 路由对象的实例方法 有 push replace, go()
- push 方法 相当于往历史记录里推了一条记录 如果点击返回 会回到上一次的地址
- replace方法 想相当于替换了当前的记录 历史记录并没有多 但是地址会变
- go(数字) 代表希望是前进还是回退,当数字大于0 时 就是前进 n(数字)次,小于0时,就是后退n(数字)次
可以通过vue实例 获取当前的路由实例 $router
goPage() {
// 跳转到新闻页面
this.$router.push({
path: "/news"});}
vue-router-routerlink-tag-激活样式
当前路由在导航中是拥有激活class样式的,设置激活class样式即可
<a href="#/news" class="router-link-exact-active router-link-active">新闻</a>
vue-router-嵌套路由
- 如果存在组件嵌套,就需要提供多个视图容器
- 同时,router-link和router-view 都可以添加类名、设定样式
注意,以 / 开头的嵌套路径会被当作根路径。 这让你充分的使用嵌套组件而无须设置嵌套的路径。
{
path:'/music',
children:{
path:'/pop' }} //此时该条路由 就是 /pop
// 如果想使用 /music/pop 可以这样
{
path:'/music',
children:{
path:'/music/pop' }} //此时该条路由 就是 /music/pop
// 或者
{
path:'/music',
children:{
path:'pop' }} //此时该条路由 就是 /music/pop
二级路由需要写在一级路由的组件中,包括视图
{
path:"/hx",
//二级路由要写在组件中
component:{
template:<div> 我是化学 <router-link to="/hx/h2">语文</router-link> <router-link to="/hx/o2">数学</router-link> <router-link to="/hx/h2o">外语</router-link> <router-view></router-view> </div>
},
children:[{
path:"/hx/h2",
component:{
template:<div>语文</div>
}},
{
path:"/hx/o2",
component:{
template:<div>数学</div>
}},
{
path:"/hx/h2o",
component:{
template:<div>外语</div>
}
}]
},
CSS 过渡和动画 中自动应用 class
- 基本用法就是给我们需要动画的标签外面嵌套transition标签 ,并且设置name属性(就是class)
Vue 提供了 transition 的封装组件,在下列元素更新,移除,新增 情形中,可以给任何元素和组件添加进入/离开过渡
<button @click="show=!show">显示/隐藏