vue基础(一):基础学习

119 阅读5分钟
单项数据绑定
原/简写法
双向数据绑定 应用于表单元素
el的2种写法
data的2种写法
对象式 函数式 (组件的时候必须用函数式)
new Vue 实例对象
vue管理的函数不能写箭头函数(比如data函数),否则this不是vue实例,而是window
MVVM 【p10】
M:model 模型对应data V:视图 VM: 视图模型(ViewModel) 经常用vm代表vue实例对象 
console.log(vm);
能看见vm身上所有的属性 data中所有的属性,最后都出现在了vm身上 
vm身上所有的属性 及 Vue原型上所有属性,在Vue模板中都可以直接使用。
事件处理 如何传参@click="demo($event,a,b)"
1.使用v-on:xxx 或 @xxx 绑定事件,其中xxx是事件名;
2.事件的回调需要配置在methods对象中,最终会在vm上;
3.methods中配置的函数,不要用箭头函数!否则this就不是vm了;
4.methods中配置的函数,都是被Vue所管理的函数,this的指向是vm 或 组件实例对象;
5.@click="demo"@click="demo($event)" 效果一致,但后者可以传参;
事件修饰符 可以连续写
1.prevent:阻止默认事件(常用);
2.stop:阻止事件冒泡(常用);
3.once:事件只触发一次(常用);
4.capture:使用事件的捕获模式;
5.self:只有event.target是当前操作的元素时才触发事件;
6.passive:事件的默认行为立即执行,无需等待事件回调执行完毕;
键盘事件 最好用名称绑定事件 编码可能不同呢
常用的别名
回车 => enter
删除 => delete (捕获“删除”和“退格”键)
退出 => esc
空格 => space
换行 => tab (特殊,必须配合keydown去使用)
上 => up
下 => down
左 => left
右 => right
<!-- 键盘事件常用的有 keydown keyup keyCode是13 回车键的编码-->
<input type="text" placeholder="按下回车提示输入" @keyup="showInfo($event)">
<!-- 回车别名enter @keyup.enter -->
<input type="text" placeholder="按下回车提示输入" @keyup.enter="showInfo($event)">
<!-- event.keyCode 获取编码  -->
<!-- 多个单词的要小写单词用-连接 -->
<input type="text" placeholder="按下caps-lock提示输入" @keyup.caps-lock="showInfo($event)">
tips
  • 所被Vue管理的函数,最好写成普通函数,这样this的指向才是vm 或 组件实例对象。
  • 所有不被Vue所管理的函数(定时器的回调函数、ajax的回调函数等、Promise的回调函数),最好写成箭头函数, 这样this的指向才是vm 或 组件实例对象。
css跟style绑定样式 案例
  • :class="xxx" 对象、数组、字符串
字符串:类名不确定
对象:多个样式,个数、名字不确定
数组:多个样式,个数、名字确定,但不知道用不用
  • :style="xxx" 对象、数组
:style="{fontSize: xxx}"其中xxx是动态值。
:style="[a,b]"其中a、b是样式对象。
<div id="demo">
    <p :class="classStr">class1+class2使用字符串变量</p>
    <button @click="checkClass">点击切换样式</button>
    <p :class="classArr">绑定多个样式,个数名字不确定</p>
    <p :class="classObj">要绑定多个样式,个数确定,名字也确定,但不确定用不用</p>
    <p :style="{fontSize:sizeValue}">{fontSize:sizeValue}</p>
    <p :style="[a,b]">:style="[a,b]"其中a、b是样式对象</p>
</div>
<script type='text/javascript'>
    //阻止vue在启动时生成生产提示
    Vue.config.productionTip = false
    //创建Vue实例
    new Vue({
        el: '#demo',
        data: {
            classStr:'',
            classArr:['class1','class2'],
            classObj:{
                class1:true,
                class2:false,
                class3:true
            },
            sizeValue:'30px',
            a:{fontSize:'20px'},
            b:{color:'#911005'},
        },
        methods: {
            // 1.切换类名 字符串
            checkClass(){
                // 取随机数
                const index = Math.floor(Math.random(0,1)*2)+1; // 取1或者2
                this.classStr =   `class${index}`;
                console.log(index,this.classStr)
            }
        },
    })
</script>
条件渲染 列表渲染 key原理
  • 条件渲染 v-if (template) v-show
v-if v-else-if v-else 切换频率低的时候使用 直接移除dom 要求结构不能被打断
v-show 高频切换 仅使用样式隐藏
v-if 元素可能无法获取到 v-show可以
  • template 只能跟 v-if 配合使用
对结构破坏,为了v-if在外层加div 可以使用template去替代,就不会有多余的元素了
  • 列表渲染 v-for
/* v-for="(item,index) in xxx" :key="index" 遍历对象 数组 字符串 指定次数 */
<div id="demo">
    <!-- 数组渲染 -->
    <ul>
        <li v-for="(p,index) in persons" ::key="index">{{p.id}}{{p.name}}{{p.age}}</li>
    </ul>
    <!-- 对象渲染 -->
    <ul>
        <li v-for="(c,index) in car" ::key="index">{{c}}</li>
    </ul>
    <!-- 字符串渲染 -->
    <ul>
        <li v-for="(str,index) in str" ::key="index">{{str}}</li>
    </ul>
    <!-- 指定次数渲染 -->
    <ul>
        <li v-for="(number,index) of 5" :key="index">
            {{index}}-{{number}}
        </li>
    </ul>
</div>
<script type='text/javascript'>
    //阻止vue在启动时生成生产提示
    Vue.config.productionTip = false
    //创建Vue实例
    new Vue({
        el: '#demo',
        data: {
            persons: [{
                    id: '001',
                    name: '张三',
                    age: 18
                },
                {
                    id: '002',
                    name: '李四',
                    age: 19
                },
                {
                    id: '003',
                    name: '王五',
                    age: 20
                }
            ],
            car: {
                name: '奥迪A8',
                price: '70万',
                color: '黑色'
            },
            str: 'hello'
        }
    })
</script>
  • key原理 取唯一标识
【用index作为key】
1.如果对数据进行破坏顺序的操作 会导致数据残留导致dom渲染错乱
因为index重新排序01234 虚拟dom保持之前index相同的dom(比如这里的input结构并没有不同所以会保留原来的dom) 
2.并且数据没有复用 所以效率低
因为0123对应的文本 张三李四王五都变了 所以会重新渲染数据
ps:如果不写key那么vue补的key就是循环的那个index作为key

1677211961446.png

【用唯一标识作为key】
新虚拟dom取出第一个id 去旧的虚拟dom找id diff算法 找不到的话就重新生成 找的到的话就复用
所以效率高 且不会数据错乱 key值是唯一标识id
ps:身份证号等唯一标识

1677212175189.png

列表渲染 过滤(watch computed) 排序 案例
  • 列表过滤 使用watch实现
<!-- 准备好一个容器 -->
<div id="demo">
    <input type="text" v-model="keyWord">
    <ul>
        <li v-for="(item,index) in filterPerson">{{item.id}}{{item.name}}{{item.age}}{{item.sex}}</li>
    </ul>
</div>
<script type='text/javascript'>
    //阻止vue在启动时生成生产提示
    Vue.config.productionTip = false
    //创建Vue实例
    new Vue({
        el: '#demo',
        data: {
            keyWord: '',
            persons: [{
                    id: '001',
                    name: '马冬梅',
                    age: 19,
                    sex: '女'
                },
                {
                    id: '002',
                    name: '周冬雨',
                    age: 20,
                    sex: '女'
                },
                {
                    id: '003',
                    name: '周杰伦',
                    age: 21,
                    sex: '男'
                },
                {
                    id: '004',
                    name: '温兆伦',
                    age: 22,
                    sex: '男'
                }
            ],
            filterPerson: []
        },
        // 1.使用watch实现
        watch: {
            keyWord: {
                immediate: true, // 立马执行一次 传入空的时候会返回所有数据 用indexOf一样的 就是要匹配 !==-1
                handler(key) {
                    // 匹配对应的元素 indexOf
                    // const person = this.persons.filter((item) => {
                    //     return item.name.indexOf(key) !== -1;
                    // })
                    // 匹配对应的元素 includes
                    const person = this.persons.filter((item) => {
                        return item.name.includes(key)
                    })
                    // 赋值给过滤之后的数组
                    this.filterPerson = person;
                    console.log(person)
                }
            }
        },
    })
</script>
  • 列表过滤 使用computed实现
 <!-- 准备好一个容器 -->
 <div id="demo">
     <input type="text" v-model="keyWord">
     <ul>
         <li v-for="(item,index) in filterPerson">{{item.id}}{{item.name}}{{item.age}}{{item.sex}}</li>
     </ul>
 </div>
 <script type='text/javascript'>
     //阻止vue在启动时生成生产提示
     Vue.config.productionTip = false
     //创建Vue实例
     new Vue({
         el: '#demo',
         data: {
             keyWord: '',
             persons: [{
                     id: '001',
                     name: '马冬梅',
                     age: 19,
                     sex: '女'
                 },
                 {
                     id: '002',
                     name: '周冬雨',
                     age: 20,
                     sex: '女'
                 },
                 {
                     id: '003',
                     name: '周杰伦',
                     age: 21,
                     sex: '男'
                 },
                 {
                     id: '004',
                     name: '温兆伦',
                     age: 22,
                     sex: '男'
                 }
             ],
         },
         // 2.使用computed实现
         computed: {
             filterPerson() {
                 // 只调用了get() 简写的形式
                 // 返回数组
                 return this.persons.filter((item) => {
                     return item.name.indexOf(this.keyWord) !== -1;
                 })
             }
         }
     })
 </script>
  • 列表排序 升序 降序 原顺序
<!-- 准备好一个容器-->
<div id="root">
	<h2>人员列表</h2>
	<input type="text" placeholder="请输入名字" v-model="keyWord">
	<button @click="sortType = 2">年龄升序</button>
	<button @click="sortType = 1">年龄降序</button>
	<button @click="sortType = 0">原顺序</button>
	<ul>
		<li v-for="(p,index) of filPerons" :key="p.id">
			{{p.name}}-{{p.age}}-{{p.sex}}
			<input type="text">
		</li>
	</ul>
</div>
<script type="text/javascript">
Vue.config.productionTip = false
//创建Vue实例
new Vue({
    el: '#demo',
    data: {
        keyWord: '',
        sortNum:0,
        persons: [{
                id: '001',
                name: '马冬梅',
                age: 19,
                sex: '女'
            },
            {
                id: '002',
                name: '周冬雨',
                age: 20,
                sex: '女'
            },
            {
                id: '003',
                name: '周杰伦',
                age: 21,
                sex: '男'
            },
            {
                id: '004',
                name: '温兆伦',
                age: 22,
                sex: '男'
            }
        ],
    },
    computed: {
        filterPerson() {
            // 返回数组
            const arr = this.persons.filter((item) => {
                return item.name.indexOf(this.keyWord) !== -1;
            })
            if(this.sortNum){
                arr.sort((p1,p2)=>{
                    return this.sortNum === 1 ? p2.age-p1.age : p1.age-p2.age
                })
            }
            return arr
        }
    }
})
</script>
收集表单+过滤器
收集表单数据:
若:<input type="text"/>,则v-model收集的是value值,用户输入的就是value值。
若:<input type="radio"/>,则v-model收集的是value值,且要给标签配置value值。
若:<input type="checkbox"/>
    1.没有配置input的value属性,那么收集的就是checked(勾选 or 未勾选,是布尔值)
    2.配置input的value属性:
        (1)v-model的初始值是非数组,那么收集的就是checked(勾选 or 未勾选,是布尔值)
        (2)v-model的初始值是数组,那么收集的的就是value组成的数组
备注:v-model的三个修饰符:
    lazy:失去焦点再收集数据 v-model.lazy="userInfo.other"
    number:输入字符串转为有效的数字 type="number" v-model.number="userInfo.age"
    trim:输入首尾空格过滤 v-model.trim="userInfo.account"
  • 1.收集表单
    • 表单元素checkbox radio 没有输入框的
    • 需要配置个默认的value值,才能双向绑定
    • 如果是单选框只需要是否选择就不用配置 value 直接就给个'' 会返回true和false
<div id="demo">
    <form @submit.prevent="demo">
        账号:<input type="text" v-model.trim="userInfo.account"> <br /><br />
        密码:<input type="password" v-model="userInfo.password"> <br /><br />
        年龄:<input type="number" v-model.number="userInfo.age"> <br /><br />
        性别:
        男<input type="radio" name="sex" v-model="userInfo.sex" value="male"><input type="radio" name="sex" v-model="userInfo.sex" value="female"> <br /><br />
        爱好:
        学习<input type="checkbox" v-model="userInfo.hobby" value="study">
        打游戏<input type="checkbox" v-model="userInfo.hobby" value="game">
        吃饭<input type="checkbox" v-model="userInfo.hobby" value="eat">
        <br /><br />
        所属校区
        <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>
        <br /><br />
        其他信息:
        <textarea v-model.lazy="userInfo.other"></textarea> <br /><br />
        <input type="checkbox" v-model="userInfo.agree">阅读并接受<a href="http://www.atguigu.com">《用户协议》</a>
        <button>提交</button>
    </form>
</div>
<script type='text/javascript'>
    //阻止vue在启动时生成生产提示
    Vue.config.productionTip = false
    //创建Vue实例
    new Vue({
        el: '#demo',
        data: {
            userInfo: {
                account: '',
                password: '',
                age: 18,
                sex: 'female',
                hobby: [],
                city: 'beijing',
                other: '',
                agree: ''
            }
        },
        methods: {
            demo() {
                console.log(JSON.stringify(this.userInfo))
            }
        }
    })
</script>
  • 2.过滤器 过滤时间格式
定义:对要显示的数据进行特定格式化后再显示(适用于一些简单逻辑的处理)。
语法:
    1.注册过滤器:Vue.filter(name,callback) 或 new Vue{filters:{}}
    2.使用过滤器:{{ xxx | 过滤器名}}  或  v-bind:属性 = "xxx | 过滤器名"
备注:
    1.过滤器也可以接收额外参数、多个过滤器也可以串联
    2.并没有改变原本的数据, 是产生新的对应的数据
 <div id="demo">
     <!-- 1. computed计算属性实现 -->
     <p>{{newtime}}</p>
     <!-- 2.methods实现 -->
     <p>{{getTime()}}</p>
     <!-- 3.filters过滤器实现 | 管道符 过滤器名字 -->
     <p>{{time | timeFormater}}</p>
     <!-- 4.filters过滤器实现 传参 可以放多个过滤器-->
     <p>{{time | timeFormater('YYYY_MM_DD') | mySlice}}</p>
 </div>
 <div id="root">
     <h2>{{msg | mySlice}}</h2>
 </div>
 <script type='text/javascript'>
     //阻止vue在启动时生成生产提示
     Vue.config.productionTip = false
     // 配置全局过滤器
     Vue.filter('mySlice', function (value) {
         return value.slice(0, 4)
     })
     //创建Vue实例
     new Vue({
         el: '#demo',
         data: {
             time: 1621561377603, //时间戳
             msg: '你好,尚硅谷'
         },
         computed: {
             newtime() {
                 return dayjs(this.time).format('YYYY年MM月DD日 HH:mm:ss')
             }
         },
         methods: {
             getTime() {
                 return dayjs(this.time).format('YYYY年MM月DD日 HH:mm:ss')
             }
         },
         // 过滤器的本质是一个函数
         filters: {
             // 先走这个过滤器
             // es6 形参默认值
             timeFormater(value, str = 'YYYY年MM月DD日 HH:mm:ss') {
                 // console.log('@',value)
                 return dayjs(value).format(str)
             },
             // 再走这个过滤器
             mySlice(value) {
                 return value.slice(0, 4)
             }
         }
     })
     new Vue({
         el: '#root',
         data: {
             msg: 'hello,atguigu!'
         }
     })
 </script>
vue指令
  • 1.内置指令
  • 2.自定义指令
new Vue({
	directives:{指令名:配置对象}   或   		
        directives{指令名:回调函数}
})
<!-- 
    指令语法:
    用于解析标签(标签属性、内容、绑定事件) 
    // 1.v-big指令 把绑定的数值放大10倍
    // 2.v-fbind指令,当其绑定的input元素默认获取焦点
-->
<div id="demo">
  <!-- 需求1:放大10倍 -->
  <div>
    <p>当前n是 <span v-text="n"></span></p>
    <p>放大10倍后的n值是 <span v-big="n"></span></p>
    <button @click="n++">点我n+1</button>
  </div>
  <!-- 需求2:input默认获取元素焦点 -->
  <input type="text" v-fbind:value="n">
</div>
<script type="text/javascript">
  //阻止vue在启动时生成生产提示
  Vue.config.productionTip = false;
  //创建Vue实例
  new Vue({
    el: "#demo",
    data: {
      n: 1,
    },
    directives: {
    //big函数何时调用:1.指令和元素建立关系 2.指令所在的模板被重新解析时
    // big(element, binding) {
    //   // console.log(element instanceof HTMLElement); // true
    //   console.log(element, binding, binding.value, "sss"); // 可以找到绑定的元素 以及 元素身上的东西 1
    //   element.innerText = binding.value * 10;
    // },
    "big":function(element, binding) {
      // console.log(element instanceof HTMLElement); // true
      console.log(element, binding, binding.value, "sss"); // 可以找到绑定的元素 以及 元素身上的东西 1
      element.innerText = binding.value * 10;
    },
    // 可以写很多个函数
    fbind:{
      // 指令与元素成功绑定时(一上来)
      bind(element,binding){
        console.log('bind')
        element.value=binding.value
     },
      // 指令所在元素被插入页面时
      inserted(element,binding){
        console.log('inserted')
        element.focus()
      },
      // 指令所在的模板被重新解析时
      update(element,binding){
        console.log('update')
        element.focus()
        element.value=binding.value
      },
     }
    },
  });
</script>
  • 3.自定义指令的坑
就是一个命名的问题  定义的时候用-分隔 v-big-number 
directives里面则是 'big-number': function (element, binding){}
<!-- 准备好一个容器 -->
<div id="demo">
  <!-- 定义的时候用-分隔 命名的问题-->
  <div>
    <p>当前n是 <span v-text="n"></span></p>
    <p>放大10倍后的n值是 <span v-big-number="n"></span></p>
    <button @click="n++">点我n+1</button>
  </div>
</div>
<script type="text/javascript">
  //阻止vue在启动时生成生产提示
  Vue.config.productionTip = false;
  //创建Vue实例
  new Vue({
    el: "#demo",
    data: {
      n: 1,
    },
    directives: {
      'big-number': function (element, binding) {
        console.log('big',this); // this是window
        console.log(element, binding, binding.value, "sss"); // 可以找到绑定的元素 以及 元素身上的东西 1
        element.innerText = binding.value * 10;
      },
    },
  });
</script>
  • 4.全局指令
Vue.directive(指令名,配置对象) 或   Vue.directive(指令名,回调函数)
//定义全局指令
Vue.directive('fbind',{
	//指令与元素成功绑定时(一上来)
	bind(element,binding){
		element.value = binding.value
	},
	//指令所在元素被插入页面时
	inserted(element,binding){
		element.focus()
	},
	//指令所在的模板被重新解析时
	update(element,binding){
		element.value = binding.value
	}
}) 
VueComponent 构造函数 【p58听不懂】
一个重要的内置关系 【p59听不懂】