一、对VUE的理解
1.1 什么是vue
1、VUE使用了基于HTML的模板语法
也就是说.vue文件中我们可以同时使用html的相关语句,也可以使用vue的语法与生命周期函数
2、VUE允许我们声明式的将DOM绑定至底层VUE实例的数据(见3的MVVM模式),VUE结合响应系统,当我们数据改变时,VUE智能地计算出重新渲染组件的最小代价并应用到DOM操作上,使DOM操作次数减少。
【“数据驱动”】:VUE底层通过一些特殊的HTML语法,将DOM和数据通过VUE实例绑定起来。一旦你创建了绑定,DOM将和数据保持同步,每当变更了数据,DOM也会相应地更新。
当一个 Vue 实例被创建时,它将 data 对象中的所有的 property 加入到 Vue 的响应式系统中。当这些 property 的值发生改变时,视图将会产生“响应”,即匹配更新为新的值。
3、MVVM模式(Model-View-ViewModel)
Vue.js是一个JavaScript MVVM库,它是以数据驱动和组件化的思想构建的。
ViewModel是如何和View以及Model进行交互的👇
使用Vue的过程就是定义MVVM各个组成部分的过程:
- 定义View
Vue.js有多种数据绑定的语法,最基础的形式是文本插值,使用一对大括号语法,在运行时{{ name }}会被数据对象的name属性替换
- 定义Model
- 创建一个Vue实例或”ViewModel”,它用于连接View和Model。ViewModel是Vue.js的核心,它是一个Vue实例。Vue实例是作用于某一个HTML元素上的,如指定了id=xxx的某个元素。
el属性指向View,el: ‘#app’表示该Vue实例将挂载到<div id="app">...</div>这个元素
创建了ViewModel后,如何达成双向绑定?
首先,我们将上图中的DOM Listeners和Data Bindings看作两个工具,它们是实现双向绑定的关键。
① 从View侧看,ViewModel中的DOM Listeners工具会帮我们监测页面上DOM元素的变化,如果有变化,则更改Model中的数据;
data:{
mheight: 325,
},
create(){
...
},
mounted() {
//要保证足够的加载时间,如这里是200,否则获取的永远是table加载前的height!!
setTimeout(() => {
let div1 = document.querySelector('.box-card1').offsetHeight
let div2 = document.querySelector('.box-card2').offsetHeight
this.mheight = Math.min(div1, div2);
}, 1000)
}
② 从Model侧看,当我们更新Model中的数据时,Data Bindings工具会帮我们更新页面中的DOM元素。
可参考上面data()中的property
③ MVVM模式本身实现了双向绑定,在Vue.js中可以使用v-model指令在表单元素上创建双向数据绑定。
<!--这是View-->
<div id="app">
<p>{{ message }}</p>
<input type="text" v-model="message"/>
</div>
<script>
new Vue({
el: '#app',
data: {
message:'hello'
}
})
</script>
👆将message绑定到文本框,当更改文本框的值时,<p>{{ message }}</p> 中的内容也会被更新。
反过来,如果改变data中message的值,文本框的值也会被更新,可以控制台进行尝试
1.2 vue为什么便捷
本人在写代码过程中最直观感受到的三点如下:
① vue采用组件化模式,使代码复用很便捷
在“企业检索”处,我复用了Header.vue,而不用拷贝Header.vue里的代码
② 操作效率高
vue采用声明式编码,让编码人员无需直接操作DOM,提高开发效率
对比命令式编码,首先要getElementById,然后再把处理完的字符串通过list.innerHTML更新上去
而vue可以采用v-for来便利,并且通过{{ }}来更新数据,不用自己手动操作DOM
③ 可以方便的更新数据
一旦data中的数据发生改变,那么模板中用到该数据的地方也会自动更新。
二、VUE的生命周期
2.1 vue的生命周期是什么
vue每个组件都是独立的,每个组件都有一个属于它的生命周期,从一个组件创建、数据初始化、挂载、更新、销毁,这就是一个组件所谓的生命周期。
- 开始创建
- 初始化数据
- 编译模板
- 挂载DOM
- 渲染-更新-渲染
- 卸载
可以参考上面两张图~
2.2 vue生命周期的在项目中的执行顺序
1、data( ){
return{
}
}
2、beforeCreate
在实例初始化之后,数据观测和事件配置之前被调用,此时组件的选项对象还未创建,el 和 data 并未初始化,因此无法访问methods, data, computed等上的方法和数据。
3、created
实例已经创建完成之后被调用,在这一步,实例已完成以下配置:数据观测、属性和方法的运算,watch/event事件回调,完成了data 数据的初始化,el没有。 然而,挂在阶段还没有开始, $el属性目前不可见,这是一个常用的生命周期,因为你可以调用methods中的方法,改变data中的数据,并且修改可以通过vue的响应式绑定体现在页面上,获取computed中的计算属性等等
4、beforeMount
挂载开始之前被调用,相关的render函数首次被调用(虚拟DOM),实例已完成以下的配置: 编译模板,把data里面的数据和模板生成html,完成了el和data 初始化,注意此时还没有挂在html到页面上。
5、mounted
挂载完成,也就是模板中的HTML渲染到HTML页面中,此时一般可以做一些ajax操作,mounted只会执行一次
6、beforeDestroy
在实例销毁之前调用,实例仍然完全可用。
- 这一步还可以用this来获取实例,
- 一般在这一步做一些重置的操作,比如清除掉组件中的定时器 和 监听的dom事件
7、destroyed
在实例销毁之后调用,调用后,所以的事件监听器会被移出,所有的子实例也会被销毁,该钩子在服务器端渲染期间不被调用
一般我常用是就是created和mounted
created:(此时页面未渲染)
created() {
this.getData();
this.$scrollTo();
}
methods: {
async getData() {
let {data} = await this.$get(
"http://121.46.19.xx:xxxx/xx/xxx/" + this.stockCode
)
this.companyInfo = data.companyInfo
this.contact = data.contact
}
我一般会在created里调用获取数据的方法,因为在该生命周期可以调用methods中的方法,来改变data中的数据,并且修改可以通过vue的响应式绑定体现在页面上。此时页面还没有加载出来,我就已经向后端接口发送请求了。
mounted:(此时页面渲染完毕)
mounted() {
//要保证足够的加载时间,如这里是200,否则获取的永远是table加载前的height!!
setTimeout(() => {
let div1 = document.querySelector('.box-card1').offsetHeight
let div2 = document.querySelector('.box-card2').offsetHeight
this.mheight = Math.min(div1, div2);
}, 1000)
},
在这里我获得页面上未经过调整的表格的高度,来对data中的mheight进行更改,数据更改后新高度的表格立刻反映在页面上。
三、VUE项目目录详解
- node_modules:存放npm命令下载的开发环境和生产环境的依赖包。
- public:public目录存放的是一些公用文件,比如初始创建时,public目录中有两个文件,一个是图标,一个是通用的错误页面:看index.html文件可以判断出,这是用于当浏览器不支持JavaScript脚本时的提示页面。
- src下assets:存放项目中需要用到的资源文件,css、js、images等。
- src下components:存放通用的组件。
- src下router.js:vue-router vue路由的配置文件。
- src下store:存放 vuex 为vue专门开发的状态管理器。
- src下views:view是视图的意思,顾名思义,这里是存放视图文件的地方。当然,一般在开发中,我们为了方便管理文件,还会在这个目录中创建更多的文件夹来进行管理。比如把项目的模块划分到目录中来管理。
- src下app.vue:使用标签<route-view></router-view>渲染整个工程的.vue组件。
我个人将它理解为该项目的根VUE实例,
- src下main.js:main.js文件的作用是创建vue实例。初始项目中,引入了vue、app、store、router,当然我们也可以在此引入更多的东西或做一些全局的处理工作。
这里的东西的作用域是全局,所以引入css要慎重,可能会有样式冲突
- package.json:用于 node_modules资源和启动、打包项目的 npm 命令管理。
四、VUE最基本的语法
4.1 v-text
4.2 v-html
设置标签的innerHTML,如果是html格式会被解析出来
<p>Using v-html directive: <span v-html="rawHtml"></span></p>
4.3 v-bind(缩写是:xx="xxxx")
① 设置class或某个style是什么
<a class="date" style="float:right;">
<i class="far fa-calendar-alt"
v-bind:class="ClassObj(scope.row.analysis_year)"
style="margin-right: 5px;"></i>
<span>
{{scope.row.analysis_year}}
</span>
</a>
method:{
ClassObj(year){
var ClassName='';
if(year==='2020'){
ClassName='redColor'
}
if(year==='2019'){
ClassName='blueColor'
}
if(year==='2018'){
ClassName='purpleColor'
}
if(year==='2017'){
ClassName='yellowColor'
}
if(year==='2016'){
ClassName='greenColor'
}
return ClassName;
}
}
<style>
.redColor{
color:#f1b0b7;
}
.blueColor{
color:#0d95e8;
}
.purpleColor{
color:#ffccff;
}
.yellowColor{
color:#ffffcc
}
.greenColor{
color:#C1FFC1
}
</style>
② 设置元素的属性
<button v-bind:disabled="isButtonDisabled">Button</button>
<a v-bind:href="url">...</a>
如果 isButtonDisabled 的值是 null、undefined 或 false,则 disabled attribute 不会被包含在渲染出来的 <button> 元素中。
4.4 v-on(缩写是@xx="xxxx")
为元素绑定事件,如键盘事件,鼠标事件等
<button class="btn1 btn-primary border-0 position-relative"
v-bind:disabled="dis"
type="button"
@click="trans" //为click绑定方法
id="searchclick">
Search
</button>
4.5 v-if
适用于切换频率较低的场景
特点:不展示的DOM元素直接被移除
<div v-if=isnull>
<div class="accordion-item">
<h5 style="font-style: normal; text-align: center">
暂无该企业的研究报告
</h5>
</div>
</div>
4.6 v-show
适用于切换频率较高的场景
特点:不展示的DOM元素未被移除,仅仅是使用样式隐藏掉(display:none
4.7 v-for(列表渲染)
根据数据生成列表结果
语法:v-for="(item,index) in xxx" :key="yyy"
4.8 v-model(双向绑定)
双向数据绑定
五、VUE的常用属性
5.1 计算属性computed
要用的属性不存在,要通过已有的属性计算得来
如我下面的hasNoData属性是通过已有的returnlist属性计算得来的
<!-- 实时检索下拉菜单 -->
<div class="search-content " ref="search" v-show="input" style="background:white">
<ul>
<li class="search-item " v-for="item in returnlist" :key="item.id" @click="transFromRealtime(item)">
<p style="color: #000000">
{{ item.company_name }}
</p>
</li>
<li class="search-item nodata" v-show="hasNoData">
<p style="color: #000000">没有找到匹配数据</p>
</li>
</ul>
</div>
<script>
export default {
data() {
return {
input: "",
list: data,
returnlist: [],
dis: true,
}
computed: {
hasNoData() {
return !this.returnlist.length
},
},
</script>
5.2 侦听属性watch
当你有一些数据需要随着其它数据变动而变动时可以使用watch。
当被监视的属性变化时,回调函数自动调用,进行相关操作
<el-input class="input1"
placeholder="请输入要检索的企业名"
v-model="input"
clearable
@clear="setValueNull"
@keyup.enter.native="trans"
>
</el-input>
<button class="btn1 btn-primary border-0 position-relative"
v-bind:disabled="dis"
type="button"
@click="trans"
id="searchclick">
Search
</button>
<script>
export default {
data() {
return {
input: "",
list: data,
returnlist: [],
dis: true,
},
methods: {
// 发送检索请求
trans() {
if (this.input === '') {
this.dis = true;
} else {
setTimeout(() => {
this.$router.push("/retrieval" + "?query=" + this.input);
}, 200);
}
},
watch: {
input() {
if (this.input !== '') {
this.dis = false;
}
}
computed和watch之间的区别:
- computed能完成的功能,watch都可以完成
- watch能完成的功能,computed不一定能完成(例如:watch可以进行异步操作)
六、组件基础
6.1 组件复用
6.2 通过Prop向子组件传递数据
<Banner :title='this.title' :show_value='this.value' ></Banner>
<div class="col-lg-8">
<h1 class="page-title">{{ title }}</h1>
<div class="show">
{{'检索词 :'}} {{show_value}}
</div>
</div>
<script>
export default {
name: "Banner",
props:['title','show_value'],
}
</script>
6.3 监听子组件事件
外部组件要获得子组件的某个属性
比如这里我的information.vue组件想获得里面MoreNews.vue组件的新闻总数,以显示在右处。
Information.vue
<!--现在这里是外部,而新闻条数是MoreResearch组件里的数据,需要从组件里获得-->
<a v-if="radio1==='新闻动态'">共{{this.newsNumber}}条</a>
<MoreNews :stockCode="stockCode" @listenToChildren="newsNumberRecords">
</MoreNews>
methods:{
//外部组件感知事件被触发后,调用listenToChildren事件的处理函数
newsNumberRecords (data) {
// data 就是刚刚从子组件传过来的值,这个处理函数把值存下后,就是上图右侧显示的数据了
this.newsNumber = data;
}
}
MoreNews.vue
子组件可以通过调用内建的 $emit 方法并传入事件名称来触发一个事件 ,如果像抛出一个特定的值,则使用$emit的第二个参数来提供这个值
下面MoreNews.vue子组件通过$emit方法触发listenToChildren事件,并传入参数totalRecords
watch:{
//注意名字要和下面要传输的东西相同
totalRecords(){
//通过$emit方法触发listenToChildren事件,并传入参数totalRecords
//将数据从MoreNews组件传到上级组件Information
this.$emit('listenToChildren',this.totalRecords);
}
}
如何使用外部库、路由跳转、如何上线,我下次分享在讲~o(* ̄▽ ̄*)ブ