前端学习开发之【Vue】-中

语法

1.表单输入绑定

表单输入需要进行双向数据绑定,所以使用v-model

  • 文本:<input type="text" v-model="user" />收集value值;type=password、text、number。
  • 多行文本:<textarea v-model="text"></textarea>不接受插值语法;
  • 单选框:<input type="radio" name="sex" v-model="userInfo.sex" value="male"> 单选框需要标识name,否则不会排他,手机value值;
  • 多选框:<input type="checkbox" v-model="userInfo.hobby" value="study"> :没有配置value属性,那么收集的是checked属性(勾选 or 未勾选,是布尔值);若配置了value属性:
    ①v-model的初始值是非数组,那么收集的就是checked(勾选 or 未勾选,是布尔值)
    ②v-model的初始值是数组,那么收集的就是value组成的数组
  • 下拉框:<select v-model="userInfo.city"> <option value="">请选择校区</option> <option value="beijing">北京</option> <option value="shanghai">上海</option> <option value="shenzhen">深圳</option> <option value="wuhan">成都</option> </select>
    文本类型的 和 元素会绑定 value property 并侦听 input 事件;
    和 会绑定 checked property 并侦听 change 事件;
    会绑定 value property 并侦听 change 事件

v-model 会忽略任何表单元素上初始的 value、checked 或 selected attribute,应该在 JavaScript 中使用data 选项来声明该初始值。

v-model的三个修饰符:

  • lazy:失去焦点后再收集数据,默认在input事件后收集数据,加lazy后在change事件后收集数据。
  • number:输入字符串转为有效的数字
  • trim:默认自动去除用户输入内容中两端的空格

过滤器

定义:对要显示的数据进行特定格式化后再显示(适用于一些简单逻辑的处理)
注册过滤器:
Vue.filter(name, callback)全局过滤器
new Vue {filters: {}} 局部过滤器

使用过滤器:{ { xxx | 过滤器名}}v-bind:属性 = "xxx | 过滤器名"

  • 过滤器可以接收额外参数,多个过滤器也可以串联
  • 并没有改变原本的数据,而是产生新的对应的数据

2. 一些内置指令

在这里插入图片描述

  • v-text:v-text会替换掉节点中的内容,<div v-text="str"></div>
  • v-html:向指定节点中渲染包含html结构的内容 ,会替换掉节点中所有的内容,<div v-html="str"></div>
  • v-cloak:本质是一个特殊属性,Vue实例创建完毕并接管容器后,会删掉v-cloak属性;所以可以在加载vue慢的时候使用v-cloak属性接管节点,设置该属性不可见,解决{ {xx}}问题;
  • v-once:所在节点在初次动态渲染后,就视为静态内容了,以后数据的改变不会引起v-once所在结构的更新,可以用于优化性能;
  • v-pre:跳过v-pre所在节点的编译过程,可利用它跳过:没有使用指令语法、没有使用插值语法的节点,会加快编译

自定义指令

  1. 局部指令:
new Vue({
    
    															
  directives:{
    
     
    指令名:配置对象 
  }   
})

new Vue({
    
    															
  directives:{
    
     
    指令名:回调函数 
  }   
})
  1. 全局指令
Vue.directive(指令名, 配置对象)
或
Vue.directive(指令名, 回调函数)


Vue.directive('fbind', {
    
    
    // 指令与元素成功绑定时(一上来)
    bind(element, binding) {
    
    	// element就是DOM元素,binding就是要绑定的
      element.value = binding.value
    },
    // 指令所在元素被插入页面时
    inserted(element, binding) {
    
    
      element.focus()
    },
    // 指令所在的模板被重新解析时
    update(element, binding) {
    
    
      element.value = binding.value
    }
})

在这里插入图片描述

扫描二维码关注公众号,回复: 15149087 查看本文章

3.Vue生命周期

  • 生命周期又名生命周期回调函数、生命周期函数、生命周期钩子
  • 是Vue在关键时刻帮我们调用的一些特殊名称的函数
  • 生命周期函数的名字不可更改,但函数的具体内容是程序员根据需求编写的
  • 生命周期函数中的 this 指向是vm或组件实例对象

Vue 完成模板的解析并把初始的真实 DOM 元素放入页面后(挂载完毕)调用 mounted;
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
数据代理与数据监测:创建前、创建完毕;
虚拟DOM:将要挂载与挂载完毕;
model->view:将要更新与更新完毕;
所有:将要销毁和销毁完毕。

4.组件基础

组件是用来实现局部功能的代码和资源的集合。
组件允许我们将 UI 划分为独立的、可重用的部分,并且可以对每个部分进行单独的思考。在实际应用中,组件常常被组织成层层嵌套的树状结构:
在这里插入图片描述
优点:复用编码,简化项目编码,提高运行效率。

非单文件组件:一个文件中包含有 n 个组件
单文件组件:一个文件中只包含有 1 个组件,后缀.vue

使用非单文件组件:(不推荐)

创建

const 组件名 = Vue.extend({
    
    options})
  • 配置项中el不要写,因为最终所有的组件都要经过一个vm的管理,由vm中的el才决定服务哪个容器
  • data必须写成函数,避免组件被复用时,数据存在引用关系

注册

//局部注册
new Vue({
    
    
el:'',
data:{
    
    },
components:{
    
    组件名:组件}
})
//全局注册
Vue.component('组件名',组件)

在这里插入图片描述
脚手架里才能处理自闭合标签。如果你是直接在 DOM 中书写模板 (例如原生 元素的内容),模板的编译需要遵从浏览器中 HTML 的解析行为,必须显式使用闭合标签。
在这里插入图片描述
VueComponent

  • school 组件本质是一个名为VueComponent的构造函数,且不是程序员定义的,而是 Vue.extend() 生成的
  • 我们只需要写 或 ,Vue 解析时会帮我们创建 school 组件的实例对象,即Vue帮我们执行的new VueComponent(options)
  • 每次调用Vue.extend,返回的都是一个全新的VueComponent,即不同组件是不同的对象
  • 组件配置中data函数、methods中的函数、watch中的函数、computed中的函数 它们的 this 均是 VueComponent实例对象
  • new Vue(options)配置中:data函数、methods中的函数、watch中的函数、computed中的函数 它们的 this 均是 Vue实例对象
  • VueComponent的实例对象,以后简称vc(组件实例对象)Vue的实例对象,以后简称vm
  • VueComponent.prototype.proto === Vue.prototype,让组件实例对象vc可以访问到 Vue原型上的属性、方法

单文件组件

  • 命名采用驼峰命名法;
  • template中必须有且只有一个根元素;
  1. 创建一个vue文件:template标签(结构),script标签(交互),style标签(样式),注意要export default暴露,要写name。
<template>
  <button @click="count++">You clicked me {
    
    {
    
     count }} times.</button>
</template>
<script>
export default {
    
    
  name:'组件名',
  data() {
    
    
    return {
    
    
      count: 0
    }
  }
}
</script>
  1. 使用:引入组件,注册,然后使用标签;
<script>
import ButtonCounter from './ButtonCounter.vue'

export default {
    
    
  components: {
    
    
    ButtonCounter
  }
}
</script>

<template>
  <h1>Here is a child component!</h1>
  <ButtonCounter />使用
</template>

介绍一下vue项目总体结构

  1. 准备好自己设计的单文件组件vue文件;
  2. 创建APP.vue文件,调用组件;
  3. 然后创建main.js,调用App.vue
  4. 创建index.html,引入main.js。

如果main.js中不想写任何东西,可以按照如下编写:

new Vue({
    
    
    template:`<App></App>`,
    el:'#root',
    components:{
    
    App}
})

5.Vue CLI脚手架

在这里插入图片描述
render函数(渲染函数):用js语言来构建DOM,因为vue是虚拟DOM,所以在拿到template模板时也要转译成VNode的函数,而用render函数构建DOM,vue就免去了转译的过程。当引入残缺的vue时,用render。render 函数 跟 template 一样都是创建 html 模板的,但是有些场景中用 template 实现起来代码冗长繁琐而且有大量重复,这时候就可以用 render 函数。

new Vue({
    
    
  el:'#app',
  // render函数功能:将App组件放入容器中
  // 简写形式
  render: h => h(App),
  // 完整形式
  // render(createElement){
    
    
  //   return createElement(App)
  // }
})

6.组件深入

ref属性

  • ref被用来给元素或子组件注册引用信息(id的替代者)应用在html标签上获取的是真实DOM元素,应用在组件标签上获取的是组件实例对象vc
  • 使用方式
    a:打标识:<h1 ref="xxx"></h1><School ref="xxx"></School>
    b:获取:this.$refs.xxx

props配置项

  • 让组件接收外部传过来的数据;
  • props优先级高于data
  • 传递数据<Demo name="xxx" :age="18"/>这里age前加:,通过v-bind使得里面的18是数字
  • 接收数据
    第一种方式(只接收)props:[‘name’, ‘age’]
    第二种方式(限制类型)props:{name:String, age:Number}
    第三种方式(限制类型、限制必要性、指定默认值)
props: {
    
    
    name: {
    
    
        type: String,	 // 类型
        required: true,// 必要性
        default: 'cess'// 默认值
    }
}

注:props是只读的,Vue底层会监测你对props的修改,如果进行了修改,就会发出警告,若业务需求确实需要修改,那么请复制props的内容到data中,然后去修改data中的数据。

mixin
功能:可以把多个组件共用的配置提取成一个混入对象。
数据和方法冲突时,组件优先;生命周期钩子全要。混入对象的钩子将在组件自身钩子之前调用。
定义:

const mixin = {
    
    
    data() {
    
    ....},
    methods: {
    
    ....}
    ....
}

使用:

  • 全局混入Vue.mixin(xxx)
  • 局部混入mixins:['xxx']

7.插件

功能:用于增强Vue
本质:包含install方法的一个对象,install的第一个参数是Vue,第二个以后的参数是插件使用者传递的数据。
可以在其中写些全局操作。
定义插件:

export default {
    
    
  install(Vue,x,y,z){
    
    }
}

使用插件:Vue.use(插件名,数据)

8.scoped样式

作用:让样式在局部生效,防止冲突
写法:<style scoped>

9.浏览器的本地存储

WebStorage(js 本地存储)
存储内容大小一般支持 5MB 左右(不同浏览器可能还不一样)
浏览器端通过Window.sessionStorage和Window.localStorage属性来实现本地存储机制
相关API
xxxStorage.setItem(‘key’, ‘value’)该方法接受一个键和值作为参数,会把键值对添加到存储中,如果键名存在,则更新其对应的值
xxxStorage.getItem(‘key’)该方法接受一个键名作为参数,返回键名对应的值
xxxStorage.removeItem(‘key’)该方法接受一个键名作为参数,并把该键名从存储中删除
xxxStorage.clear()该方法会清空存储中的所有数据

备注

  • SessionStorage存储的内容会随着浏览器窗口关闭而消失
  • LocalStorage存储的内容,需要手动清除才会消失
  • xxxStorage.getItem(xxx)如果 xxx 对应的 value 获取不到,那么getItem()的返回值是null
  • JSON.parse(null)的结果依然是null

10.组件间交互

子组件想给父组件传数据,那么就要在父组件中给子组件绑定自定义事件(事件的回调在A中)。

  1. 绑定自定义事件
  • 第一种方式,在父组件中<Demo @事件名="方法"/><Demo v-on:事件名="方法"/>
  • 第二种方式,在父组件中的mouted中this.$refs.demo.$on('事件名',方法)
  1. 传输数据:props
  2. 触发自定义事件this.$emit('事件名',数据)
  3. 解绑自定义事件this.$off('事件名')

父组件:

<!--传一个函数类型的props数据-->
<School :getSchoolName="getSchoolName"/>

  <!-- 通过父组件给子组件绑定一个自定义事件实现子给父传递数据(第一种写法,使用@或v-on) -->
  <Student @demo="m1"/> 

    <!-- 通过父组件给子组件绑定一个自定义事件实现子给父传递数据(第二种写法,使用ref) -->
    <Student ref="student" @click.native="show"/> 
<script>
  import Student from './components/Student'
  import School from './components/School'

  export default {
      
      
    name:'App',
    components:{
      
      School,Student},
    data() {
      
      
      return {
      
      
        msg:'你好啊!',
        studentName:''
      }
    },
    methods: {
      
      
      getSchoolName(name){
      
      
        console.log('App收到了学校名:',name)
      },
      m1(){
      
      
        console.log('demo事件被触发了!')
      },
      show(){
      
      
        alert(123)
      }
    },
    mounted() {
      
      
      this.$refs.student.$on('demo',this.m1) // 绑定自定义事件
      // this.$refs.student.$once('demo',this.m1) // 绑定自定义事件(一次性)
    },
  }
</script>

子组件:

<h2>当前求和为:{
    
    {
    
    number}}</h2>
<button @click="add">点我number++</button>
<button @click="unbind">解绑自定义事件</button>
<button @click="death">销毁当前Student组件的实例(vc)</button>
<script>
	export default {
    
    
		name:'Student',
		data() {
    
    
			return {
    
    
				name:'张三',
				sex:'男',
				number:0
			}
		},
		methods: {
    
    
			add(){
    
    
			//父组件中的自定义事件名与数据
	 	this.$emit('atguigu',this.name,666,888,900)
				// this.$emit('demo')
				// this.$emit('click')
			},
			unbind(){
    
    
        // 解绑
				this.$off('atguigu') //解绑一个自定义事件
				// this.$off(['atguigu','demo']) //解绑多个自定义事件
				// this.$off() //解绑所有的自定义事件
			},
			death(){
    
    
        // 销毁了当前Student组件的实例,销毁后所有Student实例的自定义事件全都不奏效
				this.$destroy()
			}
		},
	}
</script>

11.全局事件总线

一种可以在任意组件间通信的方式,本质上就是一个对象,它必须满足以下条件:

  • 所有的组件对象都必须能看见他
  • 这个对象必须能够使用$on $emit $off方法去绑定、触发和解绑事件

使用步骤:

  1. 定义全局事件总线在main.js
new Vue({
    
    
   	...
   	beforeCreate() {
    
    
   		Vue.prototype.$bus = this // 安装全局事件总线,$bus 就是当前应用的 vm
   	},
    ...
})
  1. 使用事件总线
    a:接收数据:A组件想接收数据,则在A组件中给$bus绑定自定义事件,事件的回调留在A组件自身
export default {
    
    
    methods(){
    
    
        demo(data){
    
    ...}
    }
    ...
    mounted() {
    
    
        this.$bus.$on('xxx',this.demo)
    }
}

b:提供数据:this.$bus.$emit('xxx',data)

  1. 在beforeDestroy钩子中,用$off()去解绑当前组件所用到的事件

12.$nextTick

这是一个生命周期钩子
this.$nextTick(回调函数)在下一次DOM更新结束后执行其指定的回调
什么时候用:当改变数据后,要基于更新后的新DOM进行某些操作时,要在nextTick所指定的回调函数中执行

this.$nextTick(function () {
    
    
        this.$refs.inputTitle.focus();
      });

13.过渡与动画

待补充

14.配置代理

解决跨域问题

  1. cors
  2. jsonp
  3. 配置代理服务器:本身与代理服务器端口号相同,代理服务器与服务器交互不存在跨域问题因为请求方式不同。

如何配置代理服务器

配置文件vue.config.js:
方法一

module.exports = {
    
    
  devServer:{
    
    
    proxy:"http://localhost:5000"
  }
}

说明

  • 优点:配置简单,请求资源时直接发给前端(8080)即可
  • 缺点:不能配置多个代理,不能灵活的控制请求是否走代理
  • 工作方式:若按照上述配置代理,当请求了前端不存在的资源时,才会将请求会转发给服务器 (优先匹配前端资源)

方法二

module.exports = {
    
    
    pages: {
    
    
        index: {
    
    
            entry: 'src/main.js',
        },
    },
    lintOnSave:false,
    //开启代理服务器(方式二)
	devServer: {
    
    
        proxy: {
    
    
            '/api1': {
    
    //请求前缀          
                target: 'http://localhost:5000',
                pathRewrite:{
    
    '^/api1':''},//重写,把api1去掉
                // ws: true, //用于支持websocket,默认为true
                // changeOrigin: true //用于控制请求头中的host值,默认值为true
            },
            '/api2': {
    
    
                target: 'http://localhost:5001',
                pathRewrite:{
    
    '^/api2':''},
            }
        }
    }
}

15.插槽

插槽:让父组件可以向子组件指定位置插入html结构,也是一种组件间通信的方式,
适用于 父组件 ===> 子组件
分类:默认插槽、具名插槽、作用域插槽

默认插槽

父组件:

<Category title="美食" >
<!-- 自己写结构,插进去-->
			<img src="https://s3.ax1x.com/2021/01/16/srJlq0.jpg" alt="">
		</Category>

子组件:

<div class="category">
		<h3>{
   
   { title }}分类</h3>
		<!-- 定义一个插槽(挖个坑,等着组件的使用者进行填充) -->
		<slot>我是一些默认值,当使用者没有传递具体结构时,我会出现</slot>
	</div>

具名插槽

父组件:

<Category title="美食" >
			<img slot="conter" src="https://s3.ax1x.com/2021/01/16/srJlq0.jpg" alt="">
			<a slot="footer" href="http://www.atguigu.com">更多美食</a>
		</Category>

子组件:

<div class="category">
		<h3>{
   
   {title}}分类</h3>
		<!-- 定义一个插槽(挖个坑,等着组件的使用者进行填充) -->
		<slot name="center">我是一些默认值,当使用者没有传递具体结构时,我会出现1</slot>
		<slot name="footer">我是一些默认值,当使用者没有传递具体结构时,我会出现2</slot>
	</div>
</template>

作用域插槽:数据由子组件决定,结构由父组件决定。

父组件:

<Category title="游戏">
			<template scope="atguigu">
				<ul>
					<li v-for="(g,index) in atguigu.games" :key="index">{
    
    {
    
    g}}</li>
				</ul>
			</template>
		</Category>

子组件:

<div class="category">
		<h3>{
    
    {
    
    title}}分类</h3>
		<slot :games="games" msg="hello">我是默认的一些内容</slot>
	</div>

猜你喜欢

转载自blog.csdn.net/qq_46056318/article/details/127574312